Commit fab715d7 authored by sumpfralle's avatar sumpfralle

introduced a "Vector" class based on Point

* shifting components of transformations are ignored for these instances
* useful for Normal vectors (Planes, Triangles)
* fixes collision detection border cases after model transformations
fixed "point_inside" method of "Triangle" class
collect only basic elements (Points, Vectors) in TransformableContainer collection list (avoids skipping of partially transformed instances)


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@578 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 96ffabc3
...@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,7 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry import TransformableContainer from pycam.Geometry import TransformableContainer
from pycam.Geometry.utils import INFINITE from pycam.Geometry.utils import INFINITE
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point, Vector
class Plane(TransformableContainer): class Plane(TransformableContainer):
id = 0 id = 0
...@@ -31,6 +31,8 @@ class Plane(TransformableContainer): ...@@ -31,6 +31,8 @@ class Plane(TransformableContainer):
Plane.id += 1 Plane.id += 1
self.p = p self.p = p
self.n = n self.n = n
if not isinstance(self.n, Vector):
self.n = self.n.get_vector()
def __repr__(self): def __repr__(self):
return "Plane<%s,%s>" % (self.p, self.n) return "Plane<%s,%s>" % (self.p, self.n)
...@@ -48,9 +50,11 @@ class Plane(TransformableContainer): ...@@ -48,9 +50,11 @@ class Plane(TransformableContainer):
pass pass
def intersect_point(self, direction, point): def intersect_point(self, direction, point):
if direction.norm != 1: if (not direction is None) and (direction.norm != 1):
# calculations will go wrong, if the direction is not a unit vector # calculations will go wrong, if the direction is not a unit vector
direction = Point(direction.x, direction.y, direction.z).normalized() direction = direction.normalized()
if direction is None:
return (None, INFINITE)
denom = self.n.dot(direction) denom = self.n.dot(direction)
if denom == 0: if denom == 0:
return (None, INFINITE) return (None, INFINITE)
......
...@@ -114,3 +114,27 @@ class Point: ...@@ -114,3 +114,27 @@ class Point:
and ((minz is None) or (minz - epsilon <= self.z)) \ and ((minz is None) or (minz - epsilon <= self.z)) \
and ((maxz is None) or (self.z <= maxz + epsilon)) and ((maxz is None) or (self.z <= maxz + epsilon))
def get_vector(self):
return Vector(self.x, self.y, self.z)
class Vector(Point):
""" The Vector class is similar to the Point class. The only difference
is that vectors are not shifted during transformations. This feature
is necessary for normals (e.g. of Triangles or Planes).
"""
def transform_by_matrix(self, matrix, transformed_list=None, callback=None):
x = self.x * matrix[0][0] + self.y * matrix[0][1] \
+ self.z * matrix[0][2]
y = self.x * matrix[1][0] + self.y * matrix[1][1] \
+ self.z * matrix[1][2]
z = self.x * matrix[2][0] + self.y * matrix[2][1] \
+ self.z * matrix[2][2]
self.x = x
self.y = y
self.z = z
if callback:
callback()
self.reset_cache()
...@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License ...@@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>. along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point, Vector
from pycam.Geometry.Plane import Plane from pycam.Geometry.Plane import Plane
from pycam.Geometry.Line import Line from pycam.Geometry.Line import Line
from pycam.Geometry import TransformableContainer from pycam.Geometry import TransformableContainer
...@@ -74,6 +74,8 @@ class Triangle(TransformableContainer): ...@@ -74,6 +74,8 @@ class Triangle(TransformableContainer):
if self.normal is None: if self.normal is None:
self.normal = self.p3.sub(self.p1).cross(self.p2.sub( \ self.normal = self.p3.sub(self.p1).cross(self.p2.sub( \
self.p1)).normalized() self.p1)).normalized()
if not isinstance(self.normal, Vector):
self.normal = self.normal.get_vector()
self.center = self.p1.add(self.p2).add(self.p3).div(3) self.center = self.p1.add(self.p2).add(self.p3).div(3)
self.plane = Plane(self.center, self.normal) self.plane = Plane(self.center, self.normal)
# calculate circumcircle (resulting in radius and middle) # calculate circumcircle (resulting in radius and middle)
...@@ -200,13 +202,17 @@ class Triangle(TransformableContainer): ...@@ -200,13 +202,17 @@ class Triangle(TransformableContainer):
dot12 = v1.dot(v2) dot12 = v1.dot(v2)
# Compute barycentric coordinates # Compute barycentric coordinates
denom = dot00 * dot11 - dot01 * dot01 denom = dot00 * dot11 - dot01 * dot01
if denom == 0:
return False
invDenom = 1.0 / denom
# Originally, "u" and "v" are multiplied with "1/denom". # Originally, "u" and "v" are multiplied with "1/denom".
# We don't do this to avoid division by zero (for triangles that are # We don't do this to avoid division by zero (for triangles that are
# "almost" invalid). # "almost" invalid).
u = dot11 * dot02 - dot01 * dot12 u = (dot11 * dot02 - dot01 * dot12) * invDenom
v = dot00 * dot12 - dot01 * dot02 v = (dot00 * dot12 - dot01 * dot02) * invDenom
# Check if point is in triangle # Check if point is in triangle
return ((u * denom) >= 0) and ((v * denom) >= 0) and (u + v <= denom) return (u > 0) and (v > 0) and (u + v < 1)
def subdivide(self, depth): def subdivide(self, depth):
sub = [] sub = []
if depth == 0: if depth == 0:
......
...@@ -59,13 +59,11 @@ class TransformableContainer(object): ...@@ -59,13 +59,11 @@ class TransformableContainer(object):
# Prevent any kind of loops or double transformations (e.g. Points in # Prevent any kind of loops or double transformations (e.g. Points in
# multiple containers (Line, Triangle, ...). # multiple containers (Line, Triangle, ...).
# Use the 'id' builtin to prevent expensive object comparions. # Use the 'id' builtin to prevent expensive object comparions.
transformed_list.append(id(self))
for item in self.next(): for item in self.next():
if not id(item) in transformed_list:
if isinstance(item, TransformableContainer): if isinstance(item, TransformableContainer):
item.transform_by_matrix(matrix, transformed_list, item.transform_by_matrix(matrix, transformed_list,
callback=callback) callback=callback)
else: elif not id(item) in transformed_list:
# non-TransformableContainer do not care to update the # non-TransformableContainer do not care to update the
# 'transformed_list'. Thus we need to do it. # 'transformed_list'. Thus we need to do it.
transformed_list.append(id(item)) transformed_list.append(id(item))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment