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
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
from pycam.Geometry import TransformableContainer
import math
try:
import OpenGL.GL as GL
GL_enabled = True
......@@ -27,10 +31,7 @@ except ImportError:
GL_enabled = False
import math
class Line:
class Line(TransformableContainer):
id = 0
def __init__(self, p1, p2):
......@@ -61,6 +62,14 @@ class Line:
else:
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):
if self._dir is None:
self._dir = self.p2.sub(self.p1)
......
......@@ -22,10 +22,13 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
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.Toolpath import Bounds
from pycam.Geometry.utils import INFINITE
from pycam.Geometry import TransformableContainer
MODEL_TRANSFORMATIONS = {
......@@ -42,7 +45,7 @@ MODEL_TRANSFORMATIONS = {
}
class BaseModel(object):
class BaseModel(TransformableContainer):
id = 0
def __init__(self):
......@@ -68,9 +71,6 @@ class BaseModel(object):
result.append(item)
return result
def __iter__(self):
return self
def next(self):
for item_group in self._item_groups:
for item in item_group:
......@@ -134,25 +134,6 @@ class BaseModel(object):
for item in self.next():
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"):
if direction in MODEL_TRANSFORMATIONS.keys():
self.transform_by_matrix(MODEL_TRANSFORMATIONS[direction])
......
......@@ -22,6 +22,7 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import math
def _is_near(x, y):
return abs(x - y) < 1e-6
......@@ -58,6 +59,22 @@ class Point:
else:
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):
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/>.
from pycam.Geometry.Point import Point
from pycam.Geometry.Plane import Plane
#from pycam.Geometry.utils import *
from pycam.Geometry.Line import Line
from pycam.Geometry import TransformableContainer
try:
......@@ -36,7 +36,7 @@ except ImportError:
GL_enabled = False
class Triangle:
class Triangle(TransformableContainer):
id = 0
# points are expected to be in ClockWise order
......@@ -75,6 +75,19 @@ class Triangle:
def __repr__(self):
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):
return "triangle%d" % self.id
......
......@@ -25,9 +25,66 @@ __all__ = ["utils", "Line", "Model", "Path", "Plane", "Point", "Triangle",
"PolygonExtractor", "TriangleKdtree", "intersection", "kdtree",
"Matrix"]
from pycam.Geometry.Point import Point
from pycam.Geometry.Line import Line
from pycam.Geometry.Triangle import Triangle
from pycam.Geometry.Path import Path
from pycam.Geometry.Plane import Plane
from pycam.Geometry.PolygonExtractor import PolygonExtractor
#from pycam.Geometry.Point import Point
#from pycam.Geometry.Line import Line
#from pycam.Geometry.Triangle import Triangle
#from pycam.Geometry.Path import Path
#from pycam.Geometry.Plane import Plane
#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