Commit 6364ac9a authored by sumpfralle's avatar sumpfralle

fixed some code-style issues


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@495 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent f113e154
...@@ -21,16 +21,13 @@ You should have received a copy of the GNU General Public License ...@@ -21,16 +21,13 @@ 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/>.
""" """
import pycam.Geometry
from pycam.Geometry import * from pycam.Geometry.Point import Point
from pycam.Geometry.utils import *
from pycam.Geometry.utils import *
from math import sqrt
class BaseCutter:
class BaseCutter(object):
id = 0 id = 0
vertical = Point(0,0,-1) vertical = Point(0, 0, -1)
def __init__(self, radius, location=None, height=None): def __init__(self, radius, location=None, height=None):
if location is None: if location is None:
...@@ -46,7 +43,8 @@ class BaseCutter: ...@@ -46,7 +43,8 @@ class BaseCutter:
self.required_distance = 0 self.required_distance = 0
self.distance_radius = self.radius self.distance_radius = self.radius
self.distance_radiussq = self.distance_radius * self.distance_radius self.distance_radiussq = self.distance_radius * self.distance_radius
# self.minx, self.maxx, self.miny and self.maxy are defined as properties below # self.minx, self.maxx, self.miny and self.maxy are defined as
# properties below
self.shape = {} self.shape = {}
def _get_minx(self): def _get_minx(self):
...@@ -95,7 +93,8 @@ class BaseCutter: ...@@ -95,7 +93,8 @@ class BaseCutter:
set_pos_func(location.x, location.y, location.z) set_pos_func(location.x, location.y, location.z)
def intersect(self, direction, triangle): def intersect(self, direction, triangle):
return (None, None, None, INFINITE) raise NotImplementedError("Inherited class of BaseCutter does not " \
+ "implement the required function 'intersect'.")
def drop(self, triangle): def drop(self, triangle):
# check bounding box collision # check bounding box collision
...@@ -110,10 +109,12 @@ class BaseCutter: ...@@ -110,10 +109,12 @@ class BaseCutter:
# check bounding circle collision # check bounding circle collision
c = triangle.center() c = triangle.center()
if sqr(c.x-self.location.x)+sqr(c.y-self.location.y)>(self.distance_radiussq+2*self.distance_radius*triangle.radius()+triangle.radiussq()): if (c.x - self.location.x) ** 2 + (c.y - self.location.y) ** 2 \
> (self.distance_radiussq + 2 * self.distance_radius \
* triangle.radius() + triangle.radiussq()):
return None return None
(cl,d)= self.intersect(BaseCutter.vertical, triangle) (cl, d)= self.intersect(BaseCutter.vertical, triangle)
return cl return cl
def push(self, dx, dy, triangle): def push(self, dx, dy, triangle):
...@@ -129,16 +130,16 @@ class BaseCutter: ...@@ -129,16 +130,16 @@ class BaseCutter:
return None return None
if self.maxx < triangle.minx(): if self.maxx < triangle.minx():
return None return None
if triangle.maxz()<self.location.z: if triangle.maxz() < self.location.z:
return None return None
# check bounding sphere collision # check bounding sphere collision
c = triangle.center() c = triangle.center()
d = (c.x-self.location.x)*dy-(c.y-self.location.y)*dx d = (c.x - self.location.x) * dy -(c.y - self.location.y) * dx
t = self.radius + triangle.radius() t = self.radius + triangle.radius()
if d < -t or d > t: if abs(d) > t:
return None return None
(cl,d)= self.intersect(Point(dx,dy,0), triangle) (cl, d)= self.intersect(Point(dx, dy, 0), triangle)
return cl return cl
...@@ -21,12 +21,12 @@ You should have received a copy of the GNU General Public License ...@@ -21,12 +21,12 @@ 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/>.
""" """
import pycam.Geometry from pycam.Geometry.utils import INFINITE
from pycam.Geometry.Point import Point
from pycam.Geometry import Matrix #from pycam.Geometry.utils import *
from pycam.Geometry import * from pycam.Geometry.intersection import intersect_circle_plane, \
from pycam.Geometry.utils import * intersect_circle_point, intersect_circle_line, \
from pycam.Geometry.intersection import * intersect_cylinder_point, intersect_cylinder_line
from pycam.Cutters.BaseCutter import BaseCutter from pycam.Cutters.BaseCutter import BaseCutter
import math import math
...@@ -35,23 +35,25 @@ try: ...@@ -35,23 +35,25 @@ try:
import OpenGL.GL as GL import OpenGL.GL as GL
import OpenGL.GLU as GLU import OpenGL.GLU as GLU
GL_enabled = True GL_enabled = True
except: except ImportError:
GL_enabled = False GL_enabled = False
class CylindricalCutter(BaseCutter): class CylindricalCutter(BaseCutter):
def __init__(self, radius, **kwargs): def __init__(self, radius, **kwargs):
BaseCutter.__init__(self, radius, **kwargs) BaseCutter.__init__(self, radius, **kwargs)
self.axis = Point(0, 0, 1) self.axis = Point(0, 0, 1)
self.center = self.location.sub(Point(0, 0, self.get_required_distance())) self.center = self.location.sub(Point(0, 0,
self.get_required_distance()))
def __repr__(self): def __repr__(self):
return "CylindricalCutter<%s,%s>" % (self.location,self.radius) return "CylindricalCutter<%s,%s>" % (self.location, self.radius)
def get_shape(self, format="ODE"): def get_shape(self, engine="ODE"):
if format == "ODE": if engine == "ODE":
import ode import ode
import pycam.Physics.ode_physics import pycam.Physics.ode_physics as ode_physics
""" We don't handle the the "additional_distance" perfectly, since """ We don't handle the the "additional_distance" perfectly, since
the "right" shape would be a cylinder with a small flat cap that the "right" shape would be a cylinder with a small flat cap that
grows to the full expanded radius through a partial sphere. The grows to the full expanded radius through a partial sphere. The
...@@ -77,8 +79,8 @@ class CylindricalCutter(BaseCutter): ...@@ -77,8 +79,8 @@ class CylindricalCutter(BaseCutter):
reset_shape() reset_shape()
# see http://mathworld.wolfram.com/RotationMatrix.html # see http://mathworld.wolfram.com/RotationMatrix.html
hypotenuse = math.sqrt(diff_x * diff_x + diff_y * diff_y) hypotenuse = math.sqrt(diff_x * diff_x + diff_y * diff_y)
# some paths contain two identical points (e.g. a "touch" of the PushCutter) # Some paths contain two identical points (e.g. a "touch" of
# we don't need any extension for these # the PushCutter) We don't need any extension for these.
if hypotenuse == 0: if hypotenuse == 0:
return return
cosinus = diff_x / hypotenuse cosinus = diff_x / hypotenuse
...@@ -90,33 +92,44 @@ class CylindricalCutter(BaseCutter): ...@@ -90,33 +92,44 @@ class CylindricalCutter(BaseCutter):
geom_end.setPosition((diff_x, diff_y, diff_z + center_height)) geom_end.setPosition((diff_x, diff_y, diff_z + center_height))
geom_end_transform.setGeom(geom_end) geom_end_transform.setGeom(geom_end)
# create the block that connects to two cylinders at the end # create the block that connects to two cylinders at the end
rot_matrix_box = (cosinus, sinus, 0.0, -sinus, cosinus, 0.0, 0.0, 0.0, 1.0) rot_matrix_box = (cosinus, sinus, 0.0, -sinus, cosinus, 0.0,
0.0, 0.0, 1.0)
geom_connect_transform = ode.GeomTransform(geom.space) geom_connect_transform = ode.GeomTransform(geom.space)
geom_connect_transform.setBody(geom.getBody()) geom_connect_transform.setBody(geom.getBody())
geom_connect = pycam.Physics.ode_physics.get_parallelepiped_geom( geom_connect = ode_physics.get_parallelepiped_geom(
(Point(-hypotenuse / 2.0, radius, -diff_z / 2.0), Point(hypotenuse / 2.0, radius, diff_z / 2.0), (Point(-hypotenuse / 2.0, radius, -diff_z / 2.0),
Point(hypotenuse / 2.0, -radius, diff_z / 2.0), Point(-hypotenuse / 2.0, -radius, -diff_z / 2.0)), Point(hypotenuse / 2.0, radius, diff_z / 2.0),
(Point(-hypotenuse / 2.0, radius, self.height - diff_z / 2.0), Point(hypotenuse / 2.0, radius, self.height + diff_z / 2.0), Point(hypotenuse / 2.0, -radius, diff_z / 2.0),
Point(hypotenuse / 2.0, -radius, self.height + diff_z / 2.0), Point(-hypotenuse / 2.0, -radius, self.height - diff_z / 2.0))) Point(-hypotenuse / 2.0, -radius, -diff_z / 2.0)),
(Point(-hypotenuse / 2.0, radius,
self.height - diff_z / 2.0),
Point(hypotenuse / 2.0,
radius, self.height + diff_z / 2.0),
Point(hypotenuse / 2.0, -radius,
self.height + diff_z / 2.0),
Point(-hypotenuse / 2.0, -radius,
self.height - diff_z / 2.0)))
geom_connect.setRotation(rot_matrix_box) geom_connect.setRotation(rot_matrix_box)
geom_connect.setPosition((hypotenuse / 2.0, 0, radius)) geom_connect.setPosition((hypotenuse / 2.0, 0, radius))
geom_connect_transform.setGeom(geom_connect) geom_connect_transform.setGeom(geom_connect)
# sort the geoms in order of collision probability # sort the geoms in order of collision probability
geom.children.extend([geom_connect_transform, geom_end_transform]) geom.children.extend([geom_connect_transform,
geom_end_transform])
geom.extend_shape = extend_shape geom.extend_shape = extend_shape
geom.reset_shape = reset_shape geom.reset_shape = reset_shape
self.shape[format] = (geom, set_position) self.shape[engine] = (geom, set_position)
return self.shape[format] return self.shape[engine]
def to_OpenGL(self): def to_OpenGL(self):
if not GL_enabled: if not GL_enabled:
return return
GL.glPushMatrix() GL.glPushMatrix()
GL.glTranslate(self.center.x, self.center.y, self.center.z) GL.glTranslate(self.center.x, self.center.y, self.center.z)
if not hasattr(self,"_cylinder"): if not hasattr(self, "_cylinder"):
self._cylinder = GLU.gluNewQuadric() self._cylinder = GLU.gluNewQuadric()
GLU.gluCylinder(self._cylinder, self.radius, self.radius, self.height, 10, 10) GLU.gluCylinder(self._cylinder, self.radius, self.radius, self.height,
if not hasattr(self,"_disk"): 10, 10)
if not hasattr(self, "_disk"):
self._disk = GLU.gluNewQuadric() self._disk = GLU.gluNewQuadric()
GLU.gluDisk(self._disk, 0, self.radius, 10, 10) GLU.gluDisk(self._disk, 0, self.radius, 10, 10)
GL.glPopMatrix() GL.glPopMatrix()
...@@ -126,93 +139,98 @@ class CylindricalCutter(BaseCutter): ...@@ -126,93 +139,98 @@ class CylindricalCutter(BaseCutter):
self.center = location.sub(Point(0, 0, self.get_required_distance())) self.center = location.sub(Point(0, 0, self.get_required_distance()))
def intersect_circle_plane(self, direction, triangle): def intersect_circle_plane(self, direction, triangle):
(ccp,cp,d) = intersect_circle_plane(self.center, self.distance_radius, direction, triangle) (ccp, cp, d) = intersect_circle_plane(self.center, self.distance_radius,
direction, triangle)
if ccp: if ccp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,d) return (cl, ccp, cp, d)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_circle_triangle(self, direction, triangle): def intersect_circle_triangle(self, direction, triangle):
(cl,ccp,cp,d) = self.intersect_circle_plane(direction, triangle) (cl, ccp, cp, d) = self.intersect_circle_plane(direction, triangle)
if cp and triangle.point_inside(cp): if cp and triangle.point_inside(cp):
return (cl,d) return (cl, d)
return (None,INFINITE) return (None, INFINITE)
def intersect_circle_point(self, direction, point): def intersect_circle_point(self, direction, point):
(ccp,cp,l) = intersect_circle_point(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, point) (ccp, cp, l) = intersect_circle_point(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, point)
if ccp: if ccp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None,None,None,INFINITE) return (None, None, None, INFINITE)
def intersect_circle_vertex(self, direction, point): def intersect_circle_vertex(self, direction, point):
(cl,ccp,cp,l) = self.intersect_circle_point(direction, point) (cl, ccp, cp, l) = self.intersect_circle_point(direction, point)
return (cl,l) return (cl, l)
def intersect_circle_line(self, direction, edge): def intersect_circle_line(self, direction, edge):
(ccp,cp,l) = intersect_circle_line(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, edge) (ccp, cp, l) = intersect_circle_line(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, edge)
if ccp: if ccp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None,None,None,INFINITE) return (None, None, None, INFINITE)
def intersect_circle_edge(self, direction, edge): def intersect_circle_edge(self, direction, edge):
(cl,ccp,cp,l) = self.intersect_circle_line(direction, edge) (cl, ccp, cp, l) = self.intersect_circle_line(direction, edge)
if cp: if cp:
# check if the contact point is between the endpoints # check if the contact point is between the endpoints
m = cp.sub(edge.p1).dot(edge.dir()) m = cp.sub(edge.p1).dot(edge.dir())
if m<0 or m>edge.len(): if (m < 0) or (m > edge.len()):
return (None,INFINITE) return (None, INFINITE)
return (cl,l) return (cl, l)
def intersect_cylinder_point(self, direction, point): def intersect_cylinder_point(self, direction, point):
(ccp,cp,l) = intersect_cylinder_point(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, point) (ccp, cp, l) = intersect_cylinder_point(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, point)
# offset intersection # offset intersection
if ccp: if ccp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_cylinder_vertex(self, direction, point): def intersect_cylinder_vertex(self, direction, point):
(cl,ccp,cp,l) = self.intersect_cylinder_point(direction, point) (cl, ccp, cp, l) = self.intersect_cylinder_point(direction, point)
if ccp and ccp.z < self.center.z: if ccp and ccp.z < self.center.z:
return (None, INFINITE) return (None, INFINITE)
return (cl, l) return (cl, l)
def intersect_cylinder_line(self, direction, edge): def intersect_cylinder_line(self, direction, edge):
(ccp,cp,l) = intersect_cylinder_line(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, edge) (ccp, cp, l) = intersect_cylinder_line(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, edge)
# offset intersection # offset intersection
if ccp: if ccp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None,None,None,INFINITE) return (None, None, None, INFINITE)
def intersect_cylinder_edge(self, direction, edge): def intersect_cylinder_edge(self, direction, edge):
(cl,ccp,cp,l) = self.intersect_cylinder_line(direction, edge) (cl, ccp, cp, l) = self.intersect_cylinder_line(direction, edge)
if not ccp: if not ccp:
return (None,INFINITE) return (None, INFINITE)
m = cp.sub(edge.p1).dot(edge.dir()) m = cp.sub(edge.p1).dot(edge.dir())
if m<0 or m>edge.len(): if (m < 0) or (m > edge.len()):
return (None,INFINITE) return (None, INFINITE)
if ccp.z<self.center.z: if ccp.z < self.center.z:
return (None,INFINITE) return (None, INFINITE)
return (cl,l) return (cl, l)
def intersect_plane(self, direction, triangle): def intersect_plane(self, direction, triangle):
return self.intersect_circle_plane(direction, triangle) return self.intersect_circle_plane(direction, triangle)
def intersect(self, direction, triangle): def intersect(self, direction, triangle):
(cl_t,d_t) = self.intersect_circle_triangle(direction, triangle) (cl_t, d_t) = self.intersect_circle_triangle(direction, triangle)
d = INFINITE d = INFINITE
cl = None cl = None
if d_t < d: if d_t < d:
d = d_t d = d_t
cl = cl_t cl = cl_t
if cl and direction.x==0 and direction.y==0: if cl and (direction.x == 0) and (direction.y == 0):
return (cl,d) return (cl, d)
(cl_e1,d_e1) = self.intersect_circle_edge(direction, triangle.e1) (cl_e1, d_e1) = self.intersect_circle_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_circle_edge(direction, triangle.e2) (cl_e2, d_e2) = self.intersect_circle_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_circle_edge(direction, triangle.e3) (cl_e3, d_e3) = self.intersect_circle_edge(direction, triangle.e3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -222,11 +240,11 @@ class CylindricalCutter(BaseCutter): ...@@ -222,11 +240,11 @@ class CylindricalCutter(BaseCutter):
if d_e3 < d: if d_e3 < d:
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
if cl and direction.x==0 and direction.y==0: if cl and (direction.x == 0) and (direction.y == 0):
return (cl,d) return (cl, d)
(cl_p1,d_p1) = self.intersect_circle_vertex(direction, triangle.p1) (cl_p1, d_p1) = self.intersect_circle_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_circle_vertex(direction, triangle.p2) (cl_p2, d_p2) = self.intersect_circle_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_circle_vertex(direction, triangle.p3) (cl_p3, d_p3) = self.intersect_circle_vertex(direction, triangle.p3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -236,12 +254,15 @@ class CylindricalCutter(BaseCutter): ...@@ -236,12 +254,15 @@ class CylindricalCutter(BaseCutter):
if d_p3 < d: if d_p3 < d:
d = d_p3 d = d_p3
cl = cl_p3 cl = cl_p3
if cl and direction.x==0 and direction.y==0: if cl and (direction.x == 0) and (direction.y == 0):
return (cl,d) return (cl, d)
if direction.x != 0 or direction.y != 0: if (direction.x != 0) or (direction.y != 0):
(cl_p1,d_p1) = self.intersect_cylinder_vertex(direction, triangle.p1) (cl_p1, d_p1) = self.intersect_cylinder_vertex(direction,
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2) triangle.p1)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3) (cl_p2, d_p2) = self.intersect_cylinder_vertex(direction,
triangle.p2)
(cl_p3, d_p3) = self.intersect_cylinder_vertex(direction,
triangle.p3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -251,9 +272,9 @@ class CylindricalCutter(BaseCutter): ...@@ -251,9 +272,9 @@ class CylindricalCutter(BaseCutter):
if d_p3 < d: if d_p3 < d:
d = d_p3 d = d_p3
cl = cl_p3 cl = cl_p3
(cl_e1,d_e1) = self.intersect_cylinder_edge(direction, triangle.e1) (cl_e1, d_e1) = self.intersect_cylinder_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_cylinder_edge(direction, triangle.e2) (cl_e2, d_e2) = self.intersect_cylinder_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_cylinder_edge(direction, triangle.e3) (cl_e3, d_e3) = self.intersect_cylinder_edge(direction, triangle.e3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -263,4 +284,5 @@ class CylindricalCutter(BaseCutter): ...@@ -263,4 +284,5 @@ class CylindricalCutter(BaseCutter):
if d_e3 < d: if d_e3 < d:
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
return (cl,d) return (cl, d)
...@@ -21,12 +21,12 @@ You should have received a copy of the GNU General Public License ...@@ -21,12 +21,12 @@ 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/>.
""" """
import pycam.Geometry
from pycam.Geometry import Matrix from pycam.Geometry import Matrix
from pycam.Geometry import * from pycam.Geometry.Point import Point
from pycam.Geometry.utils import * from pycam.Geometry.utils import INFINITE, epsilon
from pycam.Geometry.intersection import * from pycam.Geometry.intersection import intersect_sphere_plane, \
intersect_sphere_point, intersect_sphere_line, \
intersect_cylinder_point, intersect_cylinder_line
from pycam.Cutters.BaseCutter import BaseCutter from pycam.Cutters.BaseCutter import BaseCutter
import math import math
...@@ -35,23 +35,25 @@ try: ...@@ -35,23 +35,25 @@ try:
import OpenGL.GL as GL import OpenGL.GL as GL
import OpenGL.GLU as GLU import OpenGL.GLU as GLU
GL_enabled = True GL_enabled = True
except: except ImportError:
GL_enabled = False GL_enabled = False
class SphericalCutter(BaseCutter): class SphericalCutter(BaseCutter):
def __init__(self, radius, **kwargs): def __init__(self, radius, **kwargs):
BaseCutter.__init__(self, radius, **kwargs) BaseCutter.__init__(self, radius, **kwargs)
self.axis = Point(0,0,1) self.axis = Point(0, 0, 1)
self.center = Point(self.location.x, self.location.y, self.location.z + radius) self.center = Point(self.location.x, self.location.y,
self.location.z + radius)
def __repr__(self): def __repr__(self):
return "SphericalCutter<%s,%s>" % (self.location,self.radius) return "SphericalCutter<%s,%s>" % (self.location, self.radius)
def get_shape(self, format="ODE"): def get_shape(self, engine="ODE"):
if format == "ODE": if engine == "ODE":
import ode import ode
import pycam.Physics.ode_physics import pycam.Physics.ode_physics as ode_physics
additional_distance = self.get_required_distance() additional_distance = self.get_required_distance()
radius = self.radius + additional_distance radius = self.radius + additional_distance
center_height = 0.5 * self.height + radius - additional_distance center_height = 0.5 * self.height + radius - additional_distance
...@@ -68,8 +70,8 @@ class SphericalCutter(BaseCutter): ...@@ -68,8 +70,8 @@ class SphericalCutter(BaseCutter):
reset_shape() reset_shape()
# see http://mathworld.wolfram.com/RotationMatrix.html # see http://mathworld.wolfram.com/RotationMatrix.html
hypotenuse = math.sqrt(diff_x * diff_x + diff_y * diff_y) hypotenuse = math.sqrt(diff_x * diff_x + diff_y * diff_y)
# some paths contain two identical points (e.g. a "touch" of the PushCutter) # Some paths contain two identical points (e.g. a "touch" of the
# we don't need any extension for these # PushCutter). We don't need any extension for these.
if hypotenuse == 0: if hypotenuse == 0:
return return
cosinus = diff_x / hypotenuse cosinus = diff_x / hypotenuse
...@@ -81,18 +83,28 @@ class SphericalCutter(BaseCutter): ...@@ -81,18 +83,28 @@ class SphericalCutter(BaseCutter):
geom_end.setPosition((diff_x, diff_y, diff_z + center_height)) geom_end.setPosition((diff_x, diff_y, diff_z + center_height))
geom_end_transform.setGeom(geom_end) geom_end_transform.setGeom(geom_end)
# create the block that connects the two cylinders at the end # create the block that connects the two cylinders at the end
rot_matrix_box = (cosinus, sinus, 0.0, -sinus, cosinus, 0.0, 0.0, 0.0, 1.0) rot_matrix_box = (cosinus, sinus, 0.0, -sinus, cosinus, 0.0,
0.0, 0.0, 1.0)
geom_connect_transform = ode.GeomTransform(geom.space) geom_connect_transform = ode.GeomTransform(geom.space)
geom_connect_transform.setBody(geom.getBody()) geom_connect_transform.setBody(geom.getBody())
geom_connect = pycam.Physics.ode_physics.get_parallelepiped_geom( geom_connect = ode_physics.get_parallelepiped_geom((
(Point(-hypotenuse / 2.0, radius, -diff_z / 2.0), Point(hypotenuse / 2.0, radius, diff_z / 2.0), Point(-hypotenuse / 2.0, radius, -diff_z / 2.0),
Point(hypotenuse / 2.0, -radius, diff_z / 2.0), Point(-hypotenuse / 2.0, -radius, -diff_z / 2.0)), Point(hypotenuse / 2.0, radius, diff_z / 2.0),
(Point(-hypotenuse / 2.0, radius, self.height - diff_z / 2.0), Point(hypotenuse / 2.0, radius, self.height + diff_z / 2.0), Point(hypotenuse / 2.0, -radius, diff_z / 2.0),
Point(hypotenuse / 2.0, -radius, self.height + diff_z / 2.0), Point(-hypotenuse / 2.0, -radius, self.height - diff_z / 2.0))) Point(-hypotenuse / 2.0, -radius, -diff_z / 2.0)),
(Point(-hypotenuse / 2.0, radius,
self.height - diff_z / 2.0),
Point(hypotenuse / 2.0, radius,
self.height + diff_z / 2.0),
Point(hypotenuse / 2.0, -radius,
self.height + diff_z / 2.0),
Point(-hypotenuse / 2.0, -radius,
self.height - diff_z / 2.0)))
geom_connect.setRotation(rot_matrix_box) geom_connect.setRotation(rot_matrix_box)
geom_connect.setPosition((hypotenuse / 2.0, 0, radius)) geom_connect.setPosition((hypotenuse / 2.0, 0, radius))
geom_connect_transform.setGeom(geom_connect) geom_connect_transform.setGeom(geom_connect)
# create a cylinder, that connects the two half spheres at the lower end of both drills # Create a cylinder, that connects the two half spheres at the
# lower end of both drills.
geom_cyl_transform = ode.GeomTransform(geom.space) geom_cyl_transform = ode.GeomTransform(geom.space)
geom_cyl_transform.setBody(geom.getBody()) geom_cyl_transform.setBody(geom.getBody())
hypotenuse_3d = Matrix.get_length((diff_x, diff_y, diff_z)) hypotenuse_3d = Matrix.get_length((diff_x, diff_y, diff_z))
...@@ -100,28 +112,33 @@ class SphericalCutter(BaseCutter): ...@@ -100,28 +112,33 @@ class SphericalCutter(BaseCutter):
# rotate cylinder vector # rotate cylinder vector
cyl_original_vector = (0, 0, hypotenuse_3d) cyl_original_vector = (0, 0, hypotenuse_3d)
cyl_destination_vector = (diff_x, diff_y, diff_z) cyl_destination_vector = (diff_x, diff_y, diff_z)
geom_cyl.setRotation(Matrix.get_rotation_matrix_from_to(cyl_original_vector, cyl_destination_vector)) geom_cyl.setRotation(Matrix.get_rotation_matrix_from_to(
# the rotation is around the center - thus we ignore negative diff values cyl_original_vector, cyl_destination_vector))
geom_cyl.setPosition((abs(diff_x / 2.0), abs(diff_y / 2.0), radius - additional_distance)) # The rotation is around the center - thus we ignore negative
# diff values.
geom_cyl.setPosition((abs(diff_x / 2.0), abs(diff_y / 2.0),
radius - additional_distance))
geom_cyl_transform.setGeom(geom_cyl) geom_cyl_transform.setGeom(geom_cyl)
# sort the geoms in order of collision probability # sort the geoms in order of collision probability
geom.children.extend([geom_connect_transform, geom_cyl_transform, geom_end_transform]) geom.children.extend([geom_connect_transform,
geom_cyl_transform, geom_end_transform])
geom.extend_shape = extend_shape geom.extend_shape = extend_shape
geom.reset_shape = reset_shape geom.reset_shape = reset_shape
self.shape[format] = (geom, set_position) self.shape[engine] = (geom, set_position)
return self.shape[format] return self.shape[engine]
def to_OpenGL(self): def to_OpenGL(self):
if not GL_enabled: if not GL_enabled:
return return
GL.glPushMatrix() GL.glPushMatrix()
GL.glTranslate(self.center.x, self.center.y, self.center.z) GL.glTranslate(self.center.x, self.center.y, self.center.z)
if not hasattr(self,"_sphere"): if not hasattr(self, "_sphere"):
self._sphere = GLU.gluNewQuadric() self._sphere = GLU.gluNewQuadric()
GLU.gluSphere(self._sphere, self.radius, 10, 10) GLU.gluSphere(self._sphere, self.radius, 10, 10)
if not hasattr(self,"_cylinder"): if not hasattr(self, "_cylinder"):
self._cylinder = GLU.gluNewQuadric() self._cylinder = GLU.gluNewQuadric()
GLU.gluCylinder(self._cylinder, self.radius, self.radius, self.height, 10, 10) GLU.gluCylinder(self._cylinder, self.radius, self.radius, self.height,
10, 10)
GL.glPopMatrix() GL.glPopMatrix()
def moveto(self, location): def moveto(self, location):
...@@ -129,97 +146,102 @@ class SphericalCutter(BaseCutter): ...@@ -129,97 +146,102 @@ class SphericalCutter(BaseCutter):
self.center = Point(location.x, location.y, location.z+self.radius) self.center = Point(location.x, location.y, location.z+self.radius)
def intersect_sphere_plane(self, direction, triangle): def intersect_sphere_plane(self, direction, triangle):
(ccp,cp,d) = intersect_sphere_plane(self.center, self.distance_radius, direction, triangle) (ccp, cp, d) = intersect_sphere_plane(self.center, self.distance_radius,
direction, triangle)
# offset intersection # offset intersection
if ccp: if ccp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,d) return (cl, ccp, cp, d)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_sphere_triangle(self, direction, triangle): def intersect_sphere_triangle(self, direction, triangle):
(cl,ccp,cp,d) = self.intersect_sphere_plane(direction, triangle) (cl, ccp, cp, d) = self.intersect_sphere_plane(direction, triangle)
if cp and triangle.point_inside(cp): if cp and triangle.point_inside(cp):
return (cl,d) return (cl, d)
return (None,INFINITE) return (None, INFINITE)
def intersect_sphere_point(self, direction, point): def intersect_sphere_point(self, direction, point):
(ccp,cp,l) = intersect_sphere_point(self.center, self.distance_radius, self.distance_radiussq, direction, point) (ccp, cp, l) = intersect_sphere_point(self.center, self.distance_radius,
self.distance_radiussq, direction, point)
# offset intersection # offset intersection
cl = None cl = None
if cp: if cp:
cl = self.location.add(direction.mul(l)) cl = self.location.add(direction.mul(l))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
def intersect_sphere_vertex(self, direction, point): def intersect_sphere_vertex(self, direction, point):
(cl,ccp,cp,l) = self.intersect_sphere_point(direction, point) (cl, ccp, cp, l) = self.intersect_sphere_point(direction, point)
return (cl,l) return (cl, l)
def intersect_sphere_line(self, direction, edge): def intersect_sphere_line(self, direction, edge):
(ccp,cp,l) = intersect_sphere_line(self.center, self.distance_radius, self.distance_radiussq, direction, edge) (ccp, cp, l) = intersect_sphere_line(self.center, self.distance_radius,
self.distance_radiussq, direction, edge)
# offset intersection # offset intersection
if ccp: if ccp:
cl = cp.sub(ccp.sub(self.location)) cl = cp.sub(ccp.sub(self.location))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_sphere_edge(self, direction, edge): def intersect_sphere_edge(self, direction, edge):
(cl,ccp,cp,l) = self.intersect_sphere_line(direction, edge) (cl, ccp, cp, l) = self.intersect_sphere_line(direction, edge)
if cp: if cp:
# check if the contact point is between the endpoints # check if the contact point is between the endpoints
d = edge.p2.sub(edge.p1) d = edge.p2.sub(edge.p1)
m = cp.sub(edge.p1).dot(d) m = cp.sub(edge.p1).dot(d)
if m<0 or m>d.normsq(): if (m < 0) or (m > d.normsq()):
return (None,INFINITE) return (None, INFINITE)
return (cl,l) return (cl, l)
def intersect_cylinder_point(self, direction, point): def intersect_cylinder_point(self, direction, point):
(ccp,cp,l)=intersect_cylinder_point(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, point) (ccp, cp, l)=intersect_cylinder_point(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, point)
# offset intersection # offset intersection
if ccp: if ccp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None,None,None,INFINITE) return (None, None, None, INFINITE)
def intersect_cylinder_vertex(self, direction, point): def intersect_cylinder_vertex(self, direction, point):
(cl,ccp,cp,l) = self.intersect_cylinder_point(direction, point) (cl, ccp, cp, l) = self.intersect_cylinder_point(direction, point)
if ccp and ccp.z < self.center.z: if ccp and ccp.z < self.center.z:
return (None, INFINITE) return (None, INFINITE)
return (cl, l) return (cl, l)
def intersect_cylinder_line(self, direction, edge): def intersect_cylinder_line(self, direction, edge):
(ccp,cp,l) = intersect_cylinder_line(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, edge) (ccp, cp, l) = intersect_cylinder_line(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, edge)
# offset intersection # offset intersection
if ccp: if ccp:
cl = self.location.add(cp.sub(ccp)) cl = self.location.add(cp.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None,None,None,INFINITE) return (None, None, None, INFINITE)
def intersect_cylinder_edge(self, direction, edge): def intersect_cylinder_edge(self, direction, edge):
(cl,ccp,cp,l) = self.intersect_cylinder_line(direction, edge) (cl, ccp, cp, l) = self.intersect_cylinder_line(direction, edge)
if not ccp: if not ccp:
return (None,INFINITE) return (None, INFINITE)
m = cp.sub(edge.p1).dot(edge.dir()) m = cp.sub(edge.p1).dot(edge.dir())
if m<0 or m>edge.len(): if (m < 0) or (m > edge.len()):
return (None,INFINITE) return (None, INFINITE)
if ccp.z<self.center.z: if ccp.z < self.center.z:
return (None,INFINITE) return (None, INFINITE)
return (cl,l) return (cl, l)
def intersect_point(self, direction, point): def intersect_point(self, direction, point):
return self.intersect_sphere_point(direction, point) return self.intersect_sphere_point(direction, point)
def intersect(self, direction, triangle): def intersect(self, direction, triangle):
(cl_t,d_t) = self.intersect_sphere_triangle(direction, triangle) (cl_t, d_t) = self.intersect_sphere_triangle(direction, triangle)
d = INFINITE d = INFINITE
cl = None cl = None
if d_t < d: if d_t < d:
d = d_t d = d_t
cl = cl_t cl = cl_t
if cl and direction.x==0 and direction.y==0: if cl and (direction.x == 0) and (direction.y == 0):
return (cl,d) return (cl, d)
(cl_e1,d_e1) = self.intersect_sphere_edge(direction, triangle.e1) (cl_e1, d_e1) = self.intersect_sphere_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_sphere_edge(direction, triangle.e2) (cl_e2, d_e2) = self.intersect_sphere_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_sphere_edge(direction, triangle.e3) (cl_e3, d_e3) = self.intersect_sphere_edge(direction, triangle.e3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -229,11 +251,11 @@ class SphericalCutter(BaseCutter): ...@@ -229,11 +251,11 @@ class SphericalCutter(BaseCutter):
if d_e3 < d: if d_e3 < d:
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
if cl and direction.x==0 and direction.y==0: if cl and (direction.x == 0) and (direction.y == 0):
return (cl,d) return (cl, d)
(cl_p1,d_p1) = self.intersect_sphere_vertex(direction, triangle.p1) (cl_p1, d_p1) = self.intersect_sphere_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_sphere_vertex(direction, triangle.p2) (cl_p2, d_p2) = self.intersect_sphere_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_sphere_vertex(direction, triangle.p3) (cl_p3, d_p3) = self.intersect_sphere_vertex(direction, triangle.p3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -243,12 +265,15 @@ class SphericalCutter(BaseCutter): ...@@ -243,12 +265,15 @@ class SphericalCutter(BaseCutter):
if d_p3 < d: if d_p3 < d:
d = d_p3 d = d_p3
cl = cl_p3 cl = cl_p3
if cl and direction.x==0 and direction.y==0: if cl and (direction.x == 0) and (direction.y == 0):
return (cl,d) return (cl, d)
if direction.x != 0 or direction.y != 0: if (direction.x != 0) or (direction.y != 0):
(cl_p1,d_p1) = self.intersect_cylinder_vertex(direction, triangle.p1) (cl_p1, d_p1) = self.intersect_cylinder_vertex(direction,
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2) triangle.p1)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3) (cl_p2, d_p2) = self.intersect_cylinder_vertex(direction,
triangle.p2)
(cl_p3, d_p3) = self.intersect_cylinder_vertex(direction,
triangle.p3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -258,9 +283,9 @@ class SphericalCutter(BaseCutter): ...@@ -258,9 +283,9 @@ class SphericalCutter(BaseCutter):
if d_p3 < d: if d_p3 < d:
d = d_p3 d = d_p3
cl = cl_p3 cl = cl_p3
(cl_e1,d_e1) = self.intersect_cylinder_edge(direction, triangle.e1) (cl_e1, d_e1) = self.intersect_cylinder_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_cylinder_edge(direction, triangle.e2) (cl_e2, d_e2) = self.intersect_cylinder_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_cylinder_edge(direction, triangle.e3) (cl_e3, d_e3) = self.intersect_cylinder_edge(direction, triangle.e3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -270,14 +295,15 @@ class SphericalCutter(BaseCutter): ...@@ -270,14 +295,15 @@ class SphericalCutter(BaseCutter):
if d_e3 < d: if d_e3 < d:
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
return (cl,d) return (cl, d)
def drop_bis(self, triangle): def drop_bis(self, triangle):
""" TODO: this function is never called - remove it? """ """ TODO: this function is never called - remove it? """
n = triangle.normal() n = triangle.normal()
if abs(n.dot(self.axis))<epsilon: if abs(n.dot(self.axis)) < epsilon:
d = triangle.p1.sub(self.center).dot(n) d = triangle.p1.sub(self.center).dot(n)
if abs(d)>= self.radius-epsilon: if abs(d) >= self.radius - epsilon:
return None return None
(cl,d)= self.intersect(Point(0,0,-1), triangle) (cl, d)= self.intersect(Point(0, 0, -1), triangle)
return cl return cl
...@@ -21,49 +21,55 @@ You should have received a copy of the GNU General Public License ...@@ -21,49 +21,55 @@ 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/>.
""" """
import pycam.Geometry from pycam.Geometry.Point import Point
from pycam.Geometry.utils import INFINITE
from pycam.Geometry import * from pycam.Geometry.intersection import intersect_torus_plane, \
from pycam.Geometry.utils import * intersect_torus_point, intersect_circle_plane, intersect_circle_line, \
from pycam.Geometry.intersection import * intersect_cylinder_point, intersect_cylinder_line
from pycam.Cutters.BaseCutter import BaseCutter from pycam.Cutters.BaseCutter import BaseCutter
from math import sqrt
try: try:
import OpenGL.GL as GL import OpenGL.GL as GL
import OpenGL.GLU as GLU import OpenGL.GLU as GLU
import OpenGL.GLUT as GLUT import OpenGL.GLUT as GLUT
GL_enabled = True GL_enabled = True
except: except ImportError:
GL_enabled = False GL_enabled = False
class ToroidalCutter(BaseCutter): class ToroidalCutter(BaseCutter):
def __init__(self, radius, minorradius, **kwargs): def __init__(self, radius, minorradius, **kwargs):
BaseCutter.__init__(self, radius, **kwargs) BaseCutter.__init__(self, radius, **kwargs)
self.majorradius = radius-minorradius self.majorradius = radius-minorradius
self.minorradius = minorradius self.minorradius = minorradius
self.axis = Point(0,0,1) self.axis = Point(0, 0, 1)
self.center = Point(self.location.x, self.location.y, self.location.z + minorradius) self.center = Point(self.location.x, self.location.y,
self.majorradiussq = sqr(self.majorradius) self.location.z + minorradius)
self.minorradiussq = sqr(self.minorradius) self.majorradiussq = self.majorradius ** 2
self.distance_majorradius = self.majorradius + self.get_required_distance() self.minorradiussq = self.minorradius ** 2
self.distance_minorradius = self.minorradius + self.get_required_distance() self.distance_majorradius = self.majorradius \
self.distance_majorradiussq = sqr(self.distance_majorradius) + self.get_required_distance()
self.distance_minorradiussq = sqr(self.distance_minorradius) self.distance_minorradius = self.minorradius \
+ self.get_required_distance()
self.distance_majorradiussq = self.distance_majorradius ** 2
self.distance_minorradiussq = self.distance_minorradius ** 2
def set_required_distance(self, value): def set_required_distance(self, value):
""" trigger the update of "self.distance_major/minorradius" """ """ trigger the update of "self.distance_major/minorradius" """
BaseCutter.set_required_distance(self, value) BaseCutter.set_required_distance(self, value)
if value >= 0: if value >= 0:
self.distance_majorradius = self.majorradius + self.get_required_distance() self.distance_majorradius = self.majorradius \
self.distance_minorradius = self.minorradius + self.get_required_distance() + self.get_required_distance()
self.distance_majorradiussq = sqr(self.distance_majorradius) self.distance_minorradius = self.minorradius \
self.distance_minorradiussq = sqr(self.distance_minorradius) + self.get_required_distance()
self.distance_majorradiussq = self.distance_majorradius ** 2
self.distance_minorradiussq = self.distance_minorradius ** 2
def __repr__(self): def __repr__(self):
return "ToroidalCutter<%s,%f,R=%f,r=%f>" % (self.location,self.radius,self.majorradius,self.minorradius) return "ToroidalCutter<%s,%f,R=%f,r=%f>" % (self.location, \
self.radius, self.majorradius, self.minorradius)
def __cmp__(self, other): def __cmp__(self, other):
""" Compare Cutters by shape and size (ignoring the location) """ """ Compare Cutters by shape and size (ignoring the location) """
...@@ -75,16 +81,17 @@ class ToroidalCutter(BaseCutter): ...@@ -75,16 +81,17 @@ class ToroidalCutter(BaseCutter):
# just return a string comparison # just return a string comparison
return cmp(str(self), str(other)) return cmp(str(self), str(other))
def get_shape(self, format="ODE"): def get_shape(self, engine="ODE"):
if format == "ODE": if engine == "ODE":
import ode
from pycam.Cutters.CylindricalCutter import CylindricalCutter from pycam.Cutters.CylindricalCutter import CylindricalCutter
# TODO: use an appromixated trimesh instead (ODE does not support toroidal shapes) # TODO: use an appromixated trimesh instead (ODE does not support
# for now: use the simple cylinder shape - this should not do any harm # toroidal shapes)
cylinder = CylindricalCutter(self.radius, location=self.location, height=self.height) # for now: use the simple cylinder shape - this should be ok
cylinder = CylindricalCutter(self.radius, location=self.location,
height=self.height)
cylinder.set_required_distance(self.get_required_distance()) cylinder.set_required_distance(self.get_required_distance())
self.shape[format] = cylinder.get_shape(format) self.shape[engine] = cylinder.get_shape(engine)
return self.shape[format] return self.shape[engine]
def to_OpenGL(self): def to_OpenGL(self):
if not GL_enabled: if not GL_enabled:
...@@ -92,13 +99,14 @@ class ToroidalCutter(BaseCutter): ...@@ -92,13 +99,14 @@ class ToroidalCutter(BaseCutter):
GL.glPushMatrix() GL.glPushMatrix()
GL.glTranslate(self.center.x, self.center.y, self.center.z) GL.glTranslate(self.center.x, self.center.y, self.center.z)
GLUT.glutSolidTorus(self.minorradius, self.majorradius, 10, 20) GLUT.glutSolidTorus(self.minorradius, self.majorradius, 10, 20)
if not hasattr(self,"_cylinder"): if not hasattr(self, "_cylinder"):
self._cylinder = GLU.gluNewQuadric() self._cylinder = GLU.gluNewQuadric()
GLU.gluCylinder(self._cylinder, self.radius, self.radius, self.height, 10, 20) GLU.gluCylinder(self._cylinder, self.radius, self.radius, self.height,
10, 20)
GL.glPopMatrix() GL.glPopMatrix()
GL.glPushMatrix() GL.glPushMatrix()
GL.glTranslate(self.location.x, self.location.y, self.location.z) GL.glTranslate(self.location.x, self.location.y, self.location.z)
if not hasattr(self,"_disk"): if not hasattr(self, "_disk"):
self._disk = GLU.gluNewQuadric() self._disk = GLU.gluNewQuadric()
GLU.gluDisk(self._disk, 0, self.majorradius, 20, 10) GLU.gluDisk(self._disk, 0, self.majorradius, 20, 10)
GL.glPopMatrix() GL.glPopMatrix()
...@@ -108,146 +116,159 @@ class ToroidalCutter(BaseCutter): ...@@ -108,146 +116,159 @@ class ToroidalCutter(BaseCutter):
self.center = Point(location.x, location.y, location.z+self.minorradius) self.center = Point(location.x, location.y, location.z+self.minorradius)
def intersect_torus_plane(self, direction, triangle): def intersect_torus_plane(self, direction, triangle):
(ccp,cp,l) = intersect_torus_plane(self.center, self.axis, self.distance_majorradius, self.distance_minorradius, direction, triangle) (ccp, cp, l) = intersect_torus_plane(self.center, self.axis,
self.distance_majorradius, self.distance_minorradius, direction,
triangle)
if cp: if cp:
cl = cp.add(self.location.sub(ccp)) cl = cp.add(self.location.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_torus_triangle(self, direction, triangle): def intersect_torus_triangle(self, direction, triangle):
(cl,ccp,cp,d) = self.intersect_torus_plane(direction, triangle) (cl, ccp, cp, d) = self.intersect_torus_plane(direction, triangle)
if cp and triangle.point_inside(cp): if cp and triangle.point_inside(cp):
return (cl,d) return (cl, d)
return (None,INFINITE) return (None, INFINITE)
def intersect_torus_point(self, direction, point): def intersect_torus_point(self, direction, point):
(ccp,cp,l) = intersect_torus_point(self.center, self.axis, self.distance_majorradius, self.distance_minorradius, self.distance_majorradiussq, self.distance_minorradiussq, direction, point) (ccp, cp, l) = intersect_torus_point(self.center, self.axis,
self.distance_majorradius, self.distance_minorradius,
self.distance_majorradiussq, self.distance_minorradiussq,
direction, point)
if ccp: if ccp:
cl = point.add(self.location.sub(ccp)) cl = point.add(self.location.sub(ccp))
return (cl, ccp, point, l) return (cl, ccp, point, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_torus_vertex(self, direction, point): def intersect_torus_vertex(self, direction, point):
(cl,ccp,cp,l) = self.intersect_torus_point(direction, point) (cl, ccp, cp, l) = self.intersect_torus_point(direction, point)
return (cl,l) return (cl, l)
def intersect_torus_edge(self, direction, edge): # TODO: calculate "optimal" scale = max(dir.dot(axis)/minor,dir.dot(dir.cross(axis).normalized())/major) def intersect_torus_edge(self, direction, edge):
# TODO: calculate "optimal" scale:
# max(dir.dot(axis)/minor,dir.dot(dir.cross(axis).normalized())/major)
# "When in doubt, use brute force." Ken Thompson # "When in doubt, use brute force." Ken Thompson
min_m = 0 min_m = 0
min_l = INFINITE min_l = INFINITE
min_cl = None min_cl = None
scale = int(edge.len()/self.distance_minorradius*2) scale = int(edge.len() / self.distance_minorradius * 2)
if scale<3: scale = max(3, scale)
scale = 3 for i in range(scale + 1):
for i in range(0,scale+1): m = float(i) / scale
m = float(i)/(scale)
p = edge.point(m) p = edge.point(m)
(cl,ccp,cp,l) = self.intersect_torus_point(direction, p) (cl, ccp, cp, l) = self.intersect_torus_point(direction, p)
if not cl: if not cl:
continue continue
if l<min_l: if l < min_l:
min_m = m min_m = m
min_l = l min_l = l
min_cl = cl min_cl = cl
if min_l == INFINITE: if min_l == INFINITE:
return (None, INFINITE) return (None, INFINITE)
scale2 = 10 scale2 = 10
for i in range(1,scale2+1): for i in range(1, scale2 + 1):
m = min_m + ((float(i)/(scale2))*2-1)/scale m = min_m + ((float(i) / (scale2)) * 2 - 1)/scale
if m<0 or m>1: if (m < 0) or (m > 1):
continue continue
p = edge.point(m) p = edge.point(m)
(cl,ccp,cp,l) = self.intersect_torus_point(direction, p) (cl, ccp, cp, l) = self.intersect_torus_point(direction, p)
if not cl: if not cl:
continue continue
if l<min_l: if l < min_l:
min_l = l min_l = l
min_cl = cl min_cl = cl
return (min_cl, min_l) return (min_cl, min_l)
def intersect_cylinder_point(self, direction, point): def intersect_cylinder_point(self, direction, point):
(ccp,cp,l) = intersect_cylinder_point(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, point) (ccp, cp, l) = intersect_cylinder_point(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, point)
# offset intersection # offset intersection
if ccp: if ccp:
cl = self.location.add(direction.mul(l)) cl = self.location.add(direction.mul(l))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_cylinder_vertex(self, direction, point): def intersect_cylinder_vertex(self, direction, point):
(cl,ccp,cp,l) = self.intersect_cylinder_point(direction, point) (cl, ccp, cp, l) = self.intersect_cylinder_point(direction, point)
if ccp and ccp.z < self.center.z: if ccp and ccp.z < self.center.z:
return (None, INFINITE) return (None, INFINITE)
return (cl, l) return (cl, l)
def intersect_cylinder_line(self, direction, edge): def intersect_cylinder_line(self, direction, edge):
(ccp,cp,l) = intersect_cylinder_line(self.center, self.axis, self.distance_radius, self.distance_radiussq, direction, edge) (ccp, cp, l) = intersect_cylinder_line(self.center, self.axis,
self.distance_radius, self.distance_radiussq, direction, edge)
# offset intersection # offset intersection
if ccp: if ccp:
cl = self.location.add(cp.sub(ccp)) cl = self.location.add(cp.sub(ccp))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_cylinder_edge(self, direction, edge): def intersect_cylinder_edge(self, direction, edge):
(cl,ccp,cp,l) = self.intersect_cylinder_line(direction, edge) (cl, ccp, cp, l) = self.intersect_cylinder_line(direction, edge)
if ccp and ccp.z<self.center.z: if ccp and ccp.z < self.center.z:
return (None,INFINITE) return (None, INFINITE)
if ccp: if ccp:
m = cp.sub(edge.p1).dot(edge.dir()) m = cp.sub(edge.p1).dot(edge.dir())
if m<0 or m>edge.len(): if (m < 0) or (m > edge.len()):
return (None,INFINITE) return (None, INFINITE)
return (cl,l) return (cl, l)
def intersect_circle_plane(self, direction, triangle): def intersect_circle_plane(self, direction, triangle):
(ccp,cp,l) = intersect_circle_plane(self.location, self.distance_majorradius, direction, triangle) (ccp, cp, l) = intersect_circle_plane(self.location,
self.distance_majorradius, direction, triangle)
# offset intersection # offset intersection
if ccp: if ccp:
cl = cp.sub(ccp.sub(self.location)) cl = cp.sub(ccp.sub(self.location))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_circle_triangle(self, direction, triangle): def intersect_circle_triangle(self, direction, triangle):
(cl,ccp,cp,d) = self.intersect_circle_plane(direction, triangle) (cl, ccp, cp, d) = self.intersect_circle_plane(direction, triangle)
if cp and triangle.point_inside(cp): if cp and triangle.point_inside(cp):
return (cl,d) return (cl, d)
return (None,INFINITE) return (None, INFINITE)
def intersect_circle_point(self, direction, point): def intersect_circle_point(self, direction, point):
(ccp, cp, l) = intersect_circle_point(self.location, self.axis, self.distance_majorradius, self.distance_majorradiussq, direction, point) (ccp, cp, l) = intersect_circle_point(self.location, self.axis,
self.distance_majorradius, self.distance_majorradiussq,
direction, point)
if ccp: if ccp:
cl = cp.sub(ccp.sub(self.location)) cl = cp.sub(ccp.sub(self.location))
return (cl,ccp,point,l) return (cl, ccp, point, l)
return (None,None,None,INFINITE) return (None, None, None, INFINITE)
def intersect_circle_vertex(self, direction, point): def intersect_circle_vertex(self, direction, point):
(cl,ccp,cp,l) = self.intersect_circle_point(direction, point) (cl, ccp, cp, l) = self.intersect_circle_point(direction, point)
return (cl,l) return (cl, l)
def intersect_circle_line(self, direction, edge): def intersect_circle_line(self, direction, edge):
(ccp,cp,l) = intersect_circle_line(self.location, self.axis, self.distance_majorradius, self.distance_majorradiussq, direction, edge) (ccp, cp, l) = intersect_circle_line(self.location, self.axis,
self.distance_majorradius, self.distance_majorradiussq,
direction, edge)
if ccp: if ccp:
cl = cp.sub(ccp.sub(self.location)) cl = cp.sub(ccp.sub(self.location))
return (cl,ccp,cp,l) return (cl, ccp, cp, l)
return (None, None, None, INFINITE) return (None, None, None, INFINITE)
def intersect_circle_edge(self, direction, edge): def intersect_circle_edge(self, direction, edge):
(cl,ccp,cp,l) = self.intersect_circle_line(direction, edge) (cl, ccp, cp, l) = self.intersect_circle_line(direction, edge)
if cp: if cp:
# check if the contact point is between the endpoints # check if the contact point is between the endpoints
m = cp.sub(edge.p1).dot(edge.dir()) m = cp.sub(edge.p1).dot(edge.dir())
if m<0 or m>edge.len(): if (m < 0) or (m > edge.len()):
return (None,INFINITE) return (None, INFINITE)
return (cl,l) return (cl, l)
def intersect(self, direction, triangle): def intersect(self, direction, triangle):
(cl_t,d_t) = self.intersect_torus_triangle(direction, triangle) (cl_t, d_t) = self.intersect_torus_triangle(direction, triangle)
d = INFINITE d = INFINITE
cl = None cl = None
if d_t < d: if d_t < d:
d = d_t d = d_t
cl = cl_t cl = cl_t
(cl_e1,d_e1) = self.intersect_torus_edge(direction, triangle.e1) (cl_e1, d_e1) = self.intersect_torus_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_torus_edge(direction, triangle.e2) (cl_e2, d_e2) = self.intersect_torus_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_torus_edge(direction, triangle.e3) (cl_e3, d_e3) = self.intersect_torus_edge(direction, triangle.e3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -257,9 +278,9 @@ class ToroidalCutter(BaseCutter): ...@@ -257,9 +278,9 @@ class ToroidalCutter(BaseCutter):
if d_e3 < d: if d_e3 < d:
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
(cl_p1,d_p1) = self.intersect_torus_vertex(direction, triangle.p1) (cl_p1, d_p1) = self.intersect_torus_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_torus_vertex(direction, triangle.p2) (cl_p2, d_p2) = self.intersect_torus_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_torus_vertex(direction, triangle.p3) (cl_p3, d_p3) = self.intersect_torus_vertex(direction, triangle.p3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -269,13 +290,13 @@ class ToroidalCutter(BaseCutter): ...@@ -269,13 +290,13 @@ class ToroidalCutter(BaseCutter):
if d_p3 < d: if d_p3 < d:
d = d_p3 d = d_p3
cl = cl_p3 cl = cl_p3
(cl_t,d_t) = self.intersect_circle_triangle(direction, triangle) (cl_t, d_t) = self.intersect_circle_triangle(direction, triangle)
if d_t < d: if d_t < d:
d = d_t d = d_t
cl = cl_t cl = cl_t
(cl_p1,d_p1) = self.intersect_circle_vertex(direction, triangle.p1) (cl_p1, d_p1) = self.intersect_circle_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_circle_vertex(direction, triangle.p2) (cl_p2, d_p2) = self.intersect_circle_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_circle_vertex(direction, triangle.p3) (cl_p3, d_p3) = self.intersect_circle_vertex(direction, triangle.p3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -285,9 +306,9 @@ class ToroidalCutter(BaseCutter): ...@@ -285,9 +306,9 @@ class ToroidalCutter(BaseCutter):
if d_p3 < d: if d_p3 < d:
d = d_p3 d = d_p3
cl = cl_p3 cl = cl_p3
(cl_e1,d_e1) = self.intersect_circle_edge(direction, triangle.e1) (cl_e1, d_e1) = self.intersect_circle_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_circle_edge(direction, triangle.e2) (cl_e2, d_e2) = self.intersect_circle_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_circle_edge(direction, triangle.e3) (cl_e3, d_e3) = self.intersect_circle_edge(direction, triangle.e3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -298,9 +319,12 @@ class ToroidalCutter(BaseCutter): ...@@ -298,9 +319,12 @@ class ToroidalCutter(BaseCutter):
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
if direction.x != 0 or direction.y != 0: if direction.x != 0 or direction.y != 0:
(cl_p1,d_p1) = self.intersect_cylinder_vertex(direction, triangle.p1) (cl_p1, d_p1) = self.intersect_cylinder_vertex(direction,
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2) triangle.p1)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3) (cl_p2, d_p2) = self.intersect_cylinder_vertex(direction,
triangle.p2)
(cl_p3, d_p3) = self.intersect_cylinder_vertex(direction,
triangle.p3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -310,9 +334,9 @@ class ToroidalCutter(BaseCutter): ...@@ -310,9 +334,9 @@ class ToroidalCutter(BaseCutter):
if d_p3 < d: if d_p3 < d:
d = d_p3 d = d_p3
cl = cl_p3 cl = cl_p3
(cl_e1,d_e1) = self.intersect_cylinder_edge(direction, triangle.e1) (cl_e1, d_e1) = self.intersect_cylinder_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_cylinder_edge(direction, triangle.e2) (cl_e2, d_e2) = self.intersect_cylinder_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_cylinder_edge(direction, triangle.e3) (cl_e3, d_e3) = self.intersect_cylinder_edge(direction, triangle.e3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -322,4 +346,5 @@ class ToroidalCutter(BaseCutter): ...@@ -322,4 +346,5 @@ class ToroidalCutter(BaseCutter):
if d_e3 < d: if d_e3 < d:
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
return (cl,d) return (cl, d)
...@@ -20,13 +20,13 @@ You should have received a copy of the GNU General Public License ...@@ -20,13 +20,13 @@ 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/>.
""" """
list = [ "SphericalCutter", "CylindricalCutter", "ToroidalCutter" ] __all__ = [ "SphericalCutter", "CylindricalCutter", "ToroidalCutter",
__all__ = [ "BaseCutter" ] + list "BaseCutter" ]
from BaseCutter import BaseCutter from pycam.Cutters.BaseCutter import BaseCutter
from SphericalCutter import SphericalCutter from pycam.Cutters.SphericalCutter import SphericalCutter
from CylindricalCutter import CylindricalCutter from pycam.Cutters.CylindricalCutter import CylindricalCutter
from ToroidalCutter import ToroidalCutter from pycam.Cutters.ToroidalCutter import ToroidalCutter
def get_tool_from_settings(tool_settings, height=None): def get_tool_from_settings(tool_settings, height=None):
......
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