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/>.
from pycam.Geometry import TransformableContainer
from pycam.Geometry.utils import INFINITE
from pycam.Geometry.Point import Point
from pycam.Geometry.Point import Point, Vector
class Plane(TransformableContainer):
id = 0
......@@ -31,6 +31,8 @@ class Plane(TransformableContainer):
Plane.id += 1
self.p = p
self.n = n
if not isinstance(self.n, Vector):
self.n = self.n.get_vector()
def __repr__(self):
return "Plane<%s,%s>" % (self.p, self.n)
......@@ -48,9 +50,11 @@ class Plane(TransformableContainer):
pass
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
direction = Point(direction.x, direction.y, direction.z).normalized()
direction = direction.normalized()
if direction is None:
return (None, INFINITE)
denom = self.n.dot(direction)
if denom == 0:
return (None, INFINITE)
......
......@@ -114,3 +114,27 @@ class Point:
and ((minz is None) or (minz - epsilon <= self.z)) \
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
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.Line import Line
from pycam.Geometry import TransformableContainer
......@@ -74,6 +74,8 @@ class Triangle(TransformableContainer):
if self.normal is None:
self.normal = self.p3.sub(self.p1).cross(self.p2.sub( \
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.plane = Plane(self.center, self.normal)
# calculate circumcircle (resulting in radius and middle)
......@@ -200,13 +202,17 @@ class Triangle(TransformableContainer):
dot12 = v1.dot(v2)
# Compute barycentric coordinates
denom = dot00 * dot11 - dot01 * dot01
if denom == 0:
return False
invDenom = 1.0 / denom
# Originally, "u" and "v" are multiplied with "1/denom".
# We don't do this to avoid division by zero (for triangles that are
# "almost" invalid).
u = dot11 * dot02 - dot01 * dot12
v = dot00 * dot12 - dot01 * dot02
u = (dot11 * dot02 - dot01 * dot12) * invDenom
v = (dot00 * dot12 - dot01 * dot02) * invDenom
# 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):
sub = []
if depth == 0:
......
......@@ -59,20 +59,18 @@ class TransformableContainer(object):
# Prevent any kind of loops or double transformations (e.g. Points in
# multiple containers (Line, Triangle, ...).
# Use the 'id' builtin to prevent expensive object comparions.
transformed_list.append(id(self))
for item in self.next():
if not id(item) in transformed_list:
if isinstance(item, TransformableContainer):
item.transform_by_matrix(matrix, transformed_list,
callback=callback)
else:
# non-TransformableContainer do not care to update the
# 'transformed_list'. Thus we need to do it.
transformed_list.append(id(item))
# Don't transmit the 'transformed_list' if the object is
# not a TransformableContainer. It is not necessary and it
# is hard to understand on the lowest level (e.g. Point).
item.transform_by_matrix(matrix, callback=callback)
if isinstance(item, TransformableContainer):
item.transform_by_matrix(matrix, transformed_list,
callback=callback)
elif not id(item) in transformed_list:
# non-TransformableContainer do not care to update the
# 'transformed_list'. Thus we need to do it.
transformed_list.append(id(item))
# Don't transmit the 'transformed_list' if the object is
# not a TransformableContainer. It is not necessary and it
# is hard to understand on the lowest level (e.g. Point).
item.transform_by_matrix(matrix, callback=callback)
# run the callback - e.g. for a progress counter
if callback and callback():
# user requesteded abort
......
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