Commit 343ef209 authored by sumpfralle's avatar sumpfralle

implement a proper and consistent model transformation


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@504 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 3f1f8385
...@@ -20,6 +20,10 @@ You should have received a copy of the GNU General Public License ...@@ -20,6 +20,10 @@ 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 import TransformableContainer
import math
try: try:
import OpenGL.GL as GL import OpenGL.GL as GL
GL_enabled = True GL_enabled = True
...@@ -27,10 +31,7 @@ except ImportError: ...@@ -27,10 +31,7 @@ except ImportError:
GL_enabled = False GL_enabled = False
import math class Line(TransformableContainer):
class Line:
id = 0 id = 0
def __init__(self, p1, p2): def __init__(self, p1, p2):
...@@ -61,6 +62,14 @@ class Line: ...@@ -61,6 +62,14 @@ class Line:
else: else:
return cmp(str(self), str(other)) return cmp(str(self), str(other))
def next(self):
yield self.p1
yield self.p2
def reset_cache(self):
self._dir is None
self._len is None
def dir(self): def dir(self):
if self._dir is None: if self._dir is None:
self._dir = self.p2.sub(self.p1) self._dir = self.p2.sub(self.p1)
......
...@@ -22,10 +22,13 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,10 +22,13 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
import pycam.Exporters.STLExporter import pycam.Exporters.STLExporter
from pycam.Geometry import Triangle, Line, Point from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.Line import Line
from pycam.Geometry.Point import Point
from pycam.Geometry.TriangleKdtree import TriangleKdtree from pycam.Geometry.TriangleKdtree import TriangleKdtree
from pycam.Toolpath import Bounds from pycam.Toolpath import Bounds
from pycam.Geometry.utils import INFINITE from pycam.Geometry.utils import INFINITE
from pycam.Geometry import TransformableContainer
MODEL_TRANSFORMATIONS = { MODEL_TRANSFORMATIONS = {
...@@ -42,7 +45,7 @@ MODEL_TRANSFORMATIONS = { ...@@ -42,7 +45,7 @@ MODEL_TRANSFORMATIONS = {
} }
class BaseModel(object): class BaseModel(TransformableContainer):
id = 0 id = 0
def __init__(self): def __init__(self):
...@@ -68,9 +71,6 @@ class BaseModel(object): ...@@ -68,9 +71,6 @@ class BaseModel(object):
result.append(item) result.append(item)
return result return result
def __iter__(self):
return self
def next(self): def next(self):
for item_group in self._item_groups: for item_group in self._item_groups:
for item in item_group: for item in item_group:
...@@ -134,25 +134,6 @@ class BaseModel(object): ...@@ -134,25 +134,6 @@ class BaseModel(object):
for item in self.next(): for item in self.next():
self._update_limits(item) self._update_limits(item)
def transform_by_matrix(self, matrix):
processed = []
for item in self.next():
for point in item.get_points():
if not point.id in processed:
processed.append(point.id)
x = point.x * matrix[0][0] + point.y * matrix[0][1] \
+ point.z * matrix[0][2] + matrix[0][3]
y = point.x * matrix[1][0] + point.y * matrix[1][1] \
+ point.z * matrix[1][2] + matrix[1][3]
z = point.x * matrix[2][0] + point.y * matrix[2][1] \
+ point.z * matrix[2][2] + matrix[2][3]
point.x = x
point.y = y
point.z = z
if hasattr(item, "reset_cache"):
item.reset_cache()
self.reset_cache()
def transform_by_template(self, direction="normal"): def transform_by_template(self, direction="normal"):
if direction in MODEL_TRANSFORMATIONS.keys(): if direction in MODEL_TRANSFORMATIONS.keys():
self.transform_by_matrix(MODEL_TRANSFORMATIONS[direction]) self.transform_by_matrix(MODEL_TRANSFORMATIONS[direction])
......
...@@ -22,6 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,6 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
""" """
import math import math
def _is_near(x, y): def _is_near(x, y):
return abs(x - y) < 1e-6 return abs(x - y) < 1e-6
...@@ -58,6 +59,22 @@ class Point: ...@@ -58,6 +59,22 @@ class Point:
else: else:
return cmp(str(self), str(other)) return cmp(str(self), str(other))
def transform_by_matrix(self, matrix, transformed_list=None):
x = self.x * matrix[0][0] + self.y * matrix[0][1] \
+ self.z * matrix[0][2] + matrix[0][3]
y = self.x * matrix[1][0] + self.y * matrix[1][1] \
+ self.z * matrix[1][2] + matrix[1][3]
z = self.x * matrix[2][0] + self.y * matrix[2][1] \
+ self.z * matrix[2][2] + matrix[2][3]
self.x = x
self.y = y
self.z = z
self.reset_cache()
def reset_cache(self):
self._norm = None
self._normsq = None
def mul(self, c): def mul(self, c):
return Point(self.x * c, self.y * c, self.z * c) return Point(self.x * c, self.y * c, self.z * c)
......
...@@ -23,8 +23,8 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -23,8 +23,8 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry.Point import Point from pycam.Geometry.Point import Point
from pycam.Geometry.Plane import Plane from pycam.Geometry.Plane import Plane
#from pycam.Geometry.utils import *
from pycam.Geometry.Line import Line from pycam.Geometry.Line import Line
from pycam.Geometry import TransformableContainer
try: try:
...@@ -36,7 +36,7 @@ except ImportError: ...@@ -36,7 +36,7 @@ except ImportError:
GL_enabled = False GL_enabled = False
class Triangle: class Triangle(TransformableContainer):
id = 0 id = 0
# points are expected to be in ClockWise order # points are expected to be in ClockWise order
...@@ -75,6 +75,19 @@ class Triangle: ...@@ -75,6 +75,19 @@ class Triangle:
def __repr__(self): def __repr__(self):
return "Triangle%d<%s,%s,%s>" % (self.id, self.p1, self.p2, self.p3) return "Triangle%d<%s,%s,%s>" % (self.id, self.p1, self.p2, self.p3)
def next(self):
yield self.p1
yield self.p2
yield self.p3
def transform_by_matrix(self, matrix, transformed_list=None):
previous_normal = self._normal
super(Triangle, self).transform_by_matrix(matrix, transformed_list)
# try to keep the original normal vector (transform it manually)
if not previous_normal is None:
previous_normal.transform_by_matrix(matrix)
self._normal = previous_normal
def name(self): def name(self):
return "triangle%d" % self.id return "triangle%d" % self.id
......
...@@ -25,9 +25,66 @@ __all__ = ["utils", "Line", "Model", "Path", "Plane", "Point", "Triangle", ...@@ -25,9 +25,66 @@ __all__ = ["utils", "Line", "Model", "Path", "Plane", "Point", "Triangle",
"PolygonExtractor", "TriangleKdtree", "intersection", "kdtree", "PolygonExtractor", "TriangleKdtree", "intersection", "kdtree",
"Matrix"] "Matrix"]
from pycam.Geometry.Point import Point #from pycam.Geometry.Point import Point
from pycam.Geometry.Line import Line #from pycam.Geometry.Line import Line
from pycam.Geometry.Triangle import Triangle #from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.Path import Path #from pycam.Geometry.Path import Path
from pycam.Geometry.Plane import Plane #from pycam.Geometry.Plane import Plane
from pycam.Geometry.PolygonExtractor import PolygonExtractor #from pycam.Geometry.PolygonExtractor import PolygonExtractor
class TransformableContainer(object):
""" a base class for geometrical objects containing other elements
This class is mainly used for simplifying model transformations in a
consistent way.
Every subclass _must_ implement a 'next' generator returning (via yield)
its children.
Additionally a method 'reset_cache' for any custom re-initialization must
be provided. This method is called when all children of the object were
successfully transformed.
Optionally the method 'transform_by_matrix' may be used to perform
object-specific calculations (e.g. retaining the 'normal' vector of a
triangle).
The basic primitives that are part of TransformableContainer _must_
implement the above 'transform_by_matrix' method. These primitives are
not required to be a subclass of TransformableContainer.
"""
def transform_by_matrix(self, matrix, transformed_list=None):
if transformed_list is None:
transformed_list = []
# 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)
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)
self.reset_cache()
def __iter__(self):
return self
def next(self):
raise NotImplementedError(("'%s' is a subclass of " \
+ "'TransformableContainer' but it fails to implement the " \
+ "'next' generator") % str(type(self)))
def reset_cache(self):
raise NotImplementedError(("'%s' is a subclass of " \
+ "'TransformableContainer' but it fails to implement the " \
+ "'reset_cache' method") % str(type(self)))
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