Commit 6d649676 authored by lode_leroy's avatar lode_leroy

integrated kdtree

git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@52 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 3657baf9
VER=0.1.8 VER=0.1.9
all: all:
......
...@@ -9,9 +9,11 @@ MaxZ=3 ...@@ -9,9 +9,11 @@ MaxZ=3
[config] [config]
ToolRadius=1 ToolRadius=1
TorusRadius=0.25 TorusRadius=0.25
Layers=4 Layers=1
Samples=50 Samples=20
Lines=20 Lines=20
Cutter=SphericalCutter Cutter=SphericalCutter
PathGenerator=PushCutter PathGenerator=PushCutter
PathProcessor=ZigZagCutter PathProcessor=ContourCutter
Direction=xy
...@@ -115,26 +115,16 @@ class CylindricalCutter(BaseCutter): ...@@ -115,26 +115,16 @@ class CylindricalCutter(BaseCutter):
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)
(cl_p1,d_p1) = self.intersect_circle_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_circle_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_circle_vertex(direction, triangle.p3)
(cl_e1,d_e1) = self.intersect_circle_edge(direction, Line(triangle.p1,triangle.p2))
(cl_e2,d_e2) = self.intersect_circle_edge(direction, Line(triangle.p2,triangle.p3))
(cl_e3,d_e3) = self.intersect_circle_edge(direction, Line(triangle.p3,triangle.p1))
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 d_p1 < d: if cl:
d = d_p1 return (cl,d)
cl = cl_p1 (cl_e1,d_e1) = self.intersect_circle_edge(direction, triangle.e1)
if d_p2 < d: (cl_e2,d_e2) = self.intersect_circle_edge(direction, triangle.e2)
d = d_p2 (cl_e3,d_e3) = self.intersect_circle_edge(direction, triangle.e3)
cl = cl_p2
if d_p3 < d:
d = d_p3
cl = cl_p3
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -144,13 +134,26 @@ class CylindricalCutter(BaseCutter): ...@@ -144,13 +134,26 @@ 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:
return (cl,d)
(cl_p1,d_p1) = self.intersect_circle_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_circle_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_circle_vertex(direction, triangle.p3)
if d_p1 < d:
d = d_p1
cl = cl_p1
if d_p2 < d:
d = d_p2
cl = cl_p2
if d_p3 < d:
d = d_p3
cl = cl_p3
if cl:
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_e1,d_e1) = self.intersect_cylinder_edge(direction, triangle.e1)
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2) (cl_e2,d_e2) = self.intersect_cylinder_edge(direction, triangle.e2)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3) (cl_e3,d_e3) = self.intersect_cylinder_edge(direction, triangle.e3)
(cl_e1,d_e1) = self.intersect_cylinder_edge(direction, Line(triangle.p1,triangle.p2))
(cl_e2,d_e2) = self.intersect_cylinder_edge(direction, Line(triangle.p2,triangle.p3))
(cl_e3,d_e3) = self.intersect_cylinder_edge(direction, Line(triangle.p3,triangle.p1))
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -160,6 +163,11 @@ class CylindricalCutter(BaseCutter): ...@@ -160,6 +163,11 @@ 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:
return (cl,d)
(cl_p1,d_p1) = self.intersect_cylinder_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
......
...@@ -117,26 +117,16 @@ class SphericalCutter(BaseCutter): ...@@ -117,26 +117,16 @@ class SphericalCutter(BaseCutter):
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)
(cl_p1,d_p1) = self.intersect_sphere_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_sphere_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_sphere_vertex(direction, triangle.p3)
(cl_e1,d_e1) = self.intersect_sphere_edge(direction, Line(triangle.p1,triangle.p2))
(cl_e2,d_e2) = self.intersect_sphere_edge(direction, Line(triangle.p2,triangle.p3))
(cl_e3,d_e3) = self.intersect_sphere_edge(direction, Line(triangle.p3,triangle.p1))
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 d_p1 < d: if cl:
d = d_p1 return (cl,d)
cl = cl_p1 (cl_e1,d_e1) = self.intersect_sphere_edge(direction, triangle.e1)
if d_p2 < d: (cl_e2,d_e2) = self.intersect_sphere_edge(direction, triangle.e2)
d = d_p2 (cl_e3,d_e3) = self.intersect_sphere_edge(direction, triangle.e3)
cl = cl_p2
if d_p3 < d:
d = d_p3
cl = cl_p3
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -146,13 +136,26 @@ class SphericalCutter(BaseCutter): ...@@ -146,13 +136,26 @@ 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:
return (cl,d)
(cl_p1,d_p1) = self.intersect_sphere_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_sphere_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_sphere_vertex(direction, triangle.p3)
if d_p1 < d:
d = d_p1
cl = cl_p1
if d_p2 < d:
d = d_p2
cl = cl_p2
if d_p3 < d:
d = d_p3
cl = cl_p3
if cl:
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_e1,d_e1) = self.intersect_cylinder_edge(direction, triangle.e1)
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2) (cl_e2,d_e2) = self.intersect_cylinder_edge(direction, triangle.e2)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3) (cl_e3,d_e3) = self.intersect_cylinder_edge(direction, triangle.e3)
(cl_e1,d_e1) = self.intersect_cylinder_edge(direction, Line(triangle.p1,triangle.p2))
(cl_e2,d_e2) = self.intersect_cylinder_edge(direction, Line(triangle.p2,triangle.p3))
(cl_e3,d_e3) = self.intersect_cylinder_edge(direction, Line(triangle.p1,triangle.p3))
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
...@@ -162,6 +165,11 @@ class SphericalCutter(BaseCutter): ...@@ -162,6 +165,11 @@ 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:
return (cl,d)
(cl_p1,d_p1) = self.intersect_cylinder_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3)
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
......
...@@ -181,26 +181,16 @@ class ToroidalCutter(BaseCutter): ...@@ -181,26 +181,16 @@ class ToroidalCutter(BaseCutter):
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)
(cl_p1,d_p1) = self.intersect_torus_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_torus_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_torus_vertex(direction, triangle.p3)
(cl_e1,d_e1) = self.intersect_torus_edge(direction, Line(triangle.p1,triangle.p2))
(cl_e2,d_e2) = self.intersect_torus_edge(direction, Line(triangle.p2,triangle.p3))
(cl_e3,d_e3) = self.intersect_torus_edge(direction, Line(triangle.p3,triangle.p1))
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 d_p1 < d: if cl:
d = d_p1 return (cl,d)
cl = cl_p1 (cl_e1,d_e1) = self.intersect_torus_edge(direction, triangle.e1)
if d_p2 < d: (cl_e2,d_e2) = self.intersect_torus_edge(direction, triangle.e2)
d = d_p2 (cl_e3,d_e3) = self.intersect_torus_edge(direction, triangle.e3)
cl = cl_p2
if d_p3 < d:
d = d_p3
cl = cl_p3
if d_e1 < d: if d_e1 < d:
d = d_e1 d = d_e1
cl = cl_e1 cl = cl_e1
...@@ -210,13 +200,29 @@ class ToroidalCutter(BaseCutter): ...@@ -210,13 +200,29 @@ class ToroidalCutter(BaseCutter):
if d_e3 < d: if d_e3 < d:
d = d_e3 d = d_e3
cl = cl_e3 cl = cl_e3
if cl:
return (cl,d)
(cl_p1,d_p1) = self.intersect_torus_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_torus_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_torus_vertex(direction, triangle.p3)
if d_p1 < d:
d = d_p1
cl = cl_p1
if d_p2 < d:
d = d_p2
cl = cl_p2
if d_p3 < d:
d = d_p3
cl = cl_p3
if cl:
return (cl,d)
(cl_t,d_t) = self.intersect_circle_triangle(direction, triangle) (cl_t,d_t) = self.intersect_circle_triangle(direction, triangle)
(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)
(cl_e1,d_e1) = self.intersect_circle_edge(direction, Line(triangle.p1,triangle.p2)) (cl_e1,d_e1) = self.intersect_circle_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_circle_edge(direction, Line(triangle.p2,triangle.p3)) (cl_e2,d_e2) = self.intersect_circle_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_circle_edge(direction, Line(triangle.p3,triangle.p1)) (cl_e3,d_e3) = self.intersect_circle_edge(direction, triangle.e3)
if d_t < d: if d_t < d:
d = d_t d = d_t
cl = cl_t cl = cl_t
...@@ -242,9 +248,9 @@ class ToroidalCutter(BaseCutter): ...@@ -242,9 +248,9 @@ class ToroidalCutter(BaseCutter):
(cl_p1,d_p1) = self.intersect_cylinder_vertex(direction, triangle.p1) (cl_p1,d_p1) = self.intersect_cylinder_vertex(direction, triangle.p1)
(cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2) (cl_p2,d_p2) = self.intersect_cylinder_vertex(direction, triangle.p2)
(cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3) (cl_p3,d_p3) = self.intersect_cylinder_vertex(direction, triangle.p3)
(cl_e1,d_e1) = self.intersect_cylinder_edge(direction, Line(triangle.p1,triangle.p2)) (cl_e1,d_e1) = self.intersect_cylinder_edge(direction, triangle.e1)
(cl_e2,d_e2) = self.intersect_cylinder_edge(direction, Line(triangle.p2,triangle.p3)) (cl_e2,d_e2) = self.intersect_cylinder_edge(direction, triangle.e2)
(cl_e3,d_e3) = self.intersect_cylinder_edge(direction, Line(triangle.p3,triangle.p1)) (cl_e3,d_e3) = self.intersect_cylinder_edge(direction, triangle.e3)
if d_p1 < d: if d_p1 < d:
d = d_p1 d = d_p1
cl = cl_p1 cl = cl_p1
......
from pycam.Geometry import *
class SVGExporter: class SVGExporter:
def __init__(self, filename): def __init__(self, filename):
self.file = file(filename,"w") self.file = file(filename,"w")
self.file.write("""<?xml version='1.0'?> self.file.write("""<?xml version='1.0'?>
<svg xmlns='http://www.w3.org/2000/svg' width='640' height='800'> <svg xmlns='http://www.w3.org/2000/svg' width='640' height='800'>
<g transform='translate(320,320) scale(30)' stroke-width='0.01' font-size='0.4'> <g transform='translate(320,320) scale(60)' stroke-width='0.01' font-size='0.2'>
""") """)
self._fill = 'none' self._fill = 'none'
self._stroke = 'black' self._stroke = 'black'
...@@ -29,11 +27,11 @@ class SVGExporter: ...@@ -29,11 +27,11 @@ class SVGExporter:
x = -7 x = -7
if y < -1000: if y < -1000:
y = -7 y = -7
l = "<circle fill='" + self._fill +"'" + (" cx='%g'" % x) + (" cy='%g'" % -y) + " r='0.1'/>\n" l = "<circle fill='" + self._fill +"'" + (" cx='%g'" % x) + (" cy='%g'" % -y) + " r='0.04'/>\n"
self.file.write(l) self.file.write(l)
def AddText(self, x, y, text): def AddText(self, x, y, text):
l = "<text fill='" + self._fill +"'" + (" x='%g'" % x) + (" y='%g'" % -y) + ">" + text + "</text>\n" l = "<text fill='" + self._fill +"'" + (" x='%g'" % x) + (" y='%g'" % -y) + " dx='0.07'>" + text + "</text>\n"
self.file.write(l) self.file.write(l)
......
list = [ "SimpleGCodeExporter"] list = [ "SimpleGCodeExporter", "SVGExporter" ]
__all__ = list __all__ = list
...@@ -69,7 +69,11 @@ class Model: ...@@ -69,7 +69,11 @@ class Model:
self._maxsize = max3(max(abs(self.maxx),abs(self.minx)),max(abs(self.maxy),abs(self.miny)),max(abs(self.maxz),abs(self.minz))) self._maxsize = max3(max(abs(self.maxx),abs(self.minx)),max(abs(self.maxy),abs(self.miny)),max(abs(self.maxz),abs(self.minz)))
return self._maxsize return self._maxsize
def triangles(self): def triangles(self, minx=-INFINITE,miny=-INFINITE,minz=-INFINITE,maxx=+INFINITE,maxy=+INFINITE,maxz=+INFINITE):
if minx==-INFINITE and miny==-INFINITE and minz==-INFINITE and maxx==+INFINITE and maxy==+INFINITE and maxz==+INFINITE:
return self._triangles
if hasattr(self, "t_kdtree"):
return self.t_kdtree.Search(minx,maxx,miny,maxy)
return self._triangles return self._triangles
def subdivide(self, depth): def subdivide(self, depth):
......
...@@ -9,7 +9,7 @@ class Point: ...@@ -9,7 +9,7 @@ class Point:
self.y = float(y) self.y = float(y)
self.z = float(z) self.z = float(z)
def __repr__(self): def __repr__(self):
return "Point<%g,%g,%g>" % (self.x,self.y,self.z) return "Point%d<%g,%g,%g>" % (self.id,self.x,self.y,self.z)
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)
def div(self, c): def div(self, c):
......
import math
from Point import *
from Line import *
from Triangle import *
from kdtree import *
class PointKdtree(kdtree):
def __init__(self, points=[],cutoff=5, cutoff_distance=0.5, tolerance=0.001):
self._n = None
self.tolerance=tolerance
nodes = []
for p in points:
n = Node();
n.point = p
n.bound = []
n.bound.append(p.x)
n.bound.append(p.y)
n.bound.append(p.z)
nodes.append(n)
kdtree.__init__(self, nodes, cutoff, cutoff_distance)
def dist(self, n1, n2):
dx = n1.bound[0]-n2.bound[0]
dy = n1.bound[1]-n2.bound[1]
dz = n1.bound[2]-n2.bound[2]
return dx*dx+dy*dy+dz*dz
def Point(self, x, y, z):
#return Point(x,y,z)
if self._n:
n = self._n
else:
n = Node();
n.bound = []
n.bound.append(x)
n.bound.append(y)
n.bound.append(z)
(nn,dist) = self.nearest_neighbor(n, self.dist)
if nn and dist<self.tolerance:
self._n = n
return nn.p
else:
n.p = Point(x,y,z)
self._n = None
self.insert(n)
return n.p
from Point import * from Point import *
from Plane import * from Plane import *
from utils import * from utils import *
from Line import *
ORIENTATION_CCW = 2 ORIENTATION_CCW = 2
ORIENTATION_CW = 3 ORIENTATION_CW = 3
...@@ -15,15 +16,27 @@ except: ...@@ -15,15 +16,27 @@ except:
class Triangle: class Triangle:
id = 0 id = 0
# points are expected to be in ClockWise order # points are expected to be in ClockWise order
def __init__(self, p1=None, p2=None, p3=None): def __init__(self, p1=None, p2=None, p3=None, e1=None, e2=None, e3=None):
self.id = Triangle.id self.id = Triangle.id
Triangle.id += 1 Triangle.id += 1
self.p1 = p1 self.p1 = p1
self.p2 = p2 self.p2 = p2
self.p3 = p3 self.p3 = p3
if (not e1) and p1 and p2:
self.e1 = Line(p1,p2)
else:
self.e1 = e1
if (not e2) and p2 and p3:
self.e2 = Line(p2,p3)
else:
self.e2 = e2
if (not e3) and p3 and p1:
self.e3 = Line(p3,p1)
else:
self.e3 = e3
def __repr__(self): def __repr__(self):
return "Triangle<%s,%s,%s>" % (self.p1,self.p2,self.p3) return "Triangle%d<%s,%s,%s>" % (self.id,self.p1,self.p2,self.p3)
def name(self): def name(self):
return "triangle%d" % self.id return "triangle%d" % self.id
...@@ -49,7 +62,7 @@ class Triangle: ...@@ -49,7 +62,7 @@ class Triangle:
self._sphere = gluNewQuadric() self._sphere = gluNewQuadric()
gluSphere(self._sphere, self._radius, 10, 10) gluSphere(self._sphere, self._radius, 10, 10)
glPopMatrix() glPopMatrix()
if False: # draw triangle id on triangle face if True: # draw triangle id on triangle face
glPushMatrix() glPushMatrix()
cc = glGetFloatv(GL_CURRENT_COLOR) cc = glGetFloatv(GL_CURRENT_COLOR)
c = self.center() c = self.center()
...@@ -102,9 +115,6 @@ class Triangle: ...@@ -102,9 +115,6 @@ class Triangle:
# calculate normal, if p1-p2-pe are in clockwise order # calculate normal, if p1-p2-pe are in clockwise order
self._normal = self.p3.sub(self.p1).cross(self.p2.sub(self.p1)) self._normal = self.p3.sub(self.p1).cross(self.p2.sub(self.p1))
denom = self._normal.norm() denom = self._normal.norm()
# # TODO: fix kludge: make surface normal point up for now
# if self._normal.z < 0:
# denom = -denom
self._normal = self._normal.div(denom) self._normal = self._normal.div(denom)
return self._normal return self._normal
......
...@@ -6,74 +6,42 @@ from Line import * ...@@ -6,74 +6,42 @@ from Line import *
from Triangle import * from Triangle import *
from kdtree import * from kdtree import *
def BuildKdtree2d(triangles, cutoff=3, cutoff_distance=1.0):
nodes = []
for t in triangles:
n = Node();
n.triangle = t
n.bound = []
n.bound.append(min(min(t.p1.x,t.p2.x),t.p3.x))
n.bound.append(min(min(t.p1.y,t.p2.y),t.p3.y))
n.bound.append(max(max(t.p1.x,t.p2.x),t.p3.x))
n.bound.append(max(max(t.p1.y,t.p2.y),t.p3.y))
nodes.append(n)
return kd_tree(nodes, cutoff, cutoff_distance)
tests = 0
hits = 0
overlaptest=True overlaptest=True
def ResetKdtree2dStats(overlap=True):
global tests, hits, overlaptest
hits = 0
tests = 0
overlaptest = overlap
def GetKdtree2dStats():
global tests, hits
return (hits, tests)
def SearchKdtree2d(kdtree, minx, maxx, miny, maxy): def SearchKdtree2d(kdtree, minx, maxx, miny, maxy):
if kdtree.bucket: if kdtree.bucket:
triangles = [] triangles = []
for n in kdtree.nodes: for n in kdtree.nodes:
global tests, hits, overlaptest global tests, hits, overlaptest
tests += 1
if not overlaptest: if not overlaptest:
# print "not testing overlap"
triangles.append(n.triangle) triangles.append(n.triangle)
hits += 1
else: else:
if not (n.bound[0]>maxx if not (n.bound[0]>maxx
or n.bound[1]>maxy or n.bound[1]<minx
or n.bound[2]<minx or n.bound[2]>maxy
or n.bound[3]<miny): or n.bound[3]<miny):
triangles.append(n.triangle) triangles.append(n.triangle)
hits += 1
return triangles return triangles
else: else:
# return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy)
if kdtree.cutdim==0: if kdtree.cutdim==0:
if maxx<kdtree.minval: if maxx<kdtree.minval:
return [] return []
elif maxx<=kdtree.cutval: elif maxx<kdtree.cutval:
return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)
else: else:
return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy)
elif kdtree.cutdim==1: elif kdtree.cutdim==1:
if maxy<kdtree.minval: if minx>kdtree.maxval:
return [] return []
elif maxy<=kdtree.cutval: elif minx>kdtree.cutval:
return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy)
else: else:
return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy)
elif kdtree.cutdim==2: elif kdtree.cutdim==2:
if minx>kdtree.maxval: if maxy<kdtree.minval:
return [] return []
elif minx>kdtree.cutval: elif maxy<kdtree.cutval:
return SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)
else: else:
return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy)
elif kdtree.cutdim==3: elif kdtree.cutdim==3:
...@@ -83,3 +51,21 @@ def SearchKdtree2d(kdtree, minx, maxx, miny, maxy): ...@@ -83,3 +51,21 @@ def SearchKdtree2d(kdtree, minx, maxx, miny, maxy):
return SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy)
else: else:
return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy) return SearchKdtree2d(kdtree.lo, minx, maxx, miny, maxy)+SearchKdtree2d(kdtree.hi, minx, maxx, miny, maxy)
class TriangleKdtree(kdtree):
def __init__(self, triangles, cutoff=3, cutoff_distance=1.0):
nodes = []
for t in triangles:
n = Node();
n.triangle = t
n.bound = []
n.bound.append(min(min(t.p1.x,t.p2.x),t.p3.x))
n.bound.append(max(max(t.p1.x,t.p2.x),t.p3.x))
n.bound.append(min(min(t.p1.y,t.p2.y),t.p3.y))
n.bound.append(max(max(t.p1.y,t.p2.y),t.p3.y))
nodes.append(n)
kdtree.__init__(self, nodes, cutoff, cutoff_distance)
def Search(self, minx, maxx, miny, maxy):
return SearchKdtree2d(self, minx, maxx, miny, maxy)
#!/usr/bin/env python #!/usr/bin/env python
import math import math
import pycam
try:
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
except:
pass
class Node: class Node:
def __repr__(self): def __repr__(self):
...@@ -31,18 +39,90 @@ def find_max_spread(nodes): ...@@ -31,18 +39,90 @@ def find_max_spread(nodes):
return (maxspreaddim, maxspread) return (maxspreaddim, maxspread)
class kd_tree: class kdtree:
id = 0 id = 0
def __repr__(self): def __repr__(self):
if self.bucket: if self.bucket:
return "(#%d)" % (len(self.nodes)) if True:
return "(#%d)" % (len(self.nodes))
else:
s = "("
for n in self.nodes:
if (len(s))>1:
s += ","
s += str(n.p.id)
s += ")"
return s
else: else:
return "(%f<=%s,%d:%f,%s<=%f)" % (self.minval,self.lo, self.cutdim,self.cutval,self.hi,self.maxval) return "(%s,%d:%g,%s)" % (self.lo,self.cutdim,self.cutval,self.hi)
def to_OpenGL(self,minx,maxx,miny,maxy,minz,maxz):
if self.bucket:
glBegin(GL_LINES)
glVertex3d(minx,miny,minz)
glVertex3d(minx,miny,maxz)
glVertex3d(minx,maxy,minz)
glVertex3d(minx,maxy,maxz)
glVertex3d(maxx,miny,minz)
glVertex3d(maxx,miny,maxz)
glVertex3d(maxx,maxy,minz)
glVertex3d(maxx,maxy,maxz)
glVertex3d(minx,miny,minz)
glVertex3d(maxx,miny,minz)
glVertex3d(minx,maxy,minz)
glVertex3d(maxx,maxy,minz)
glVertex3d(minx,miny,maxz)
glVertex3d(maxx,miny,maxz)
glVertex3d(minx,maxy,maxz)
glVertex3d(maxx,maxy,maxz)
glVertex3d(minx,miny,minz)
glVertex3d(minx,maxy,minz)
glVertex3d(maxx,miny,minz)
glVertex3d(maxx,maxy,minz)
glVertex3d(minx,miny,maxz)
glVertex3d(minx,maxy,maxz)
glVertex3d(maxx,miny,maxz)
glVertex3d(maxx,maxy,maxz)
glEnd()
elif self.dim==6:
if self.cutdim == 0 or self.cutdim == 2:
self.lo.to_OpenGL(minx,self.cutval,miny,maxy,minz,maxz)
self.hi.to_OpenGL(self.cutval,maxx,miny,maxy,minz,maxz)
elif self.cutdim == 1 or self.cutdim == 3:
self.lo.to_OpenGL(minx,maxx,miny,self.cutval,minz,maxz)
self.hi.to_OpenGL(minx,maxx,self.cutval,maxy,minz,maxz)
elif self.cutdim == 4 or self.cutdim == 5:
self.lo.to_OpenGL(minx,maxx,miny,maxx,minz,self.cutval)
self.hi.to_OpenGL(minx,maxx,miny,maxy,self.cutval,maxz)
elif self.dim==4:
if self.cutdim == 0 or self.cutdim == 2:
self.lo.to_OpenGL(minx,self.cutval,miny,maxy,minz,maxz)
self.hi.to_OpenGL(self.cutval,maxx,miny,maxy,minz,maxz)
elif self.cutdim == 1 or self.cutdim == 3:
self.lo.to_OpenGL(minx,maxx,miny,self.cutval,minz,maxz)
self.hi.to_OpenGL(minx,maxx,self.cutval,maxy,minz,maxz)
elif self.dim==3:
if self.cutdim == 0:
self.lo.to_OpenGL(minx,self.cutval,miny,maxy,minz,maxz)
self.hi.to_OpenGL(self.cutval,maxx,miny,maxy,minz,maxz)
elif self.cutdim == 1:
self.lo.to_OpenGL(minx,maxx,miny,self.cutval,minz,maxz)
self.hi.to_OpenGL(minx,maxx,self.cutval,maxy,minz,maxz)
elif self.cutdim == 2:
self.lo.to_OpenGL(minx,maxx,miny,maxy,minz,self.cutval)
self.hi.to_OpenGL(minx,maxx,miny,maxy,self.cutval,maxz)
def __init__(self, nodes, cutoff, cutoff_distance): def __init__(self, nodes, cutoff, cutoff_distance):
self.id = kd_tree.id self.id = kdtree.id
kd_tree.id += 1 self.bucket = False
if nodes and len(nodes)>0:
self.dim = len(nodes[0].bound)
else:
self.dim = 0
kdtree.id += 1
self.cutoff = cutoff self.cutoff = cutoff
self.cutoff_distance = cutoff_distance self.cutoff_distance = cutoff_distance
...@@ -62,9 +142,65 @@ class kd_tree: ...@@ -62,9 +142,65 @@ class kd_tree:
self.minval = nodes[0].bound[cutdim] self.minval = nodes[0].bound[cutdim]
self.maxval = nodes[-1].bound[cutdim] self.maxval = nodes[-1].bound[cutdim]
self.cutval = nodes[median].bound[cutdim] self.cutval = nodes[median].bound[cutdim]
self.lo = kd_tree(nodes[0:median], cutoff, cutoff_distance) self.lo = kdtree(nodes[0:median], cutoff, cutoff_distance)
self.hi = kd_tree(nodes[median:], cutoff, cutoff_distance) self.hi = kdtree(nodes[median:], cutoff, cutoff_distance)
def dist(self, n1, n2):
dist = 0
for i in range(0,len(n1.bound)):
d = n1.bound[i]-n2.bound[i]
dist += d*d
return dist
def nearest_neighbor(self, node, dist=dist):
if self.bucket:
if len(self.nodes)==0:
return (None, 0)
best = self.nodes[0]
bestdist = self.dist(node, best)
for n in self.nodes:
d = self.dist(n,node)
if d<bestdist:
best = n
bestdist = d
return (best,bestdist)
else:
if node.bound[self.cutdim] <= self.cutval:
(best,bestdist) = self.lo.nearest_neighbor(node, dist)
if bestdist > self.cutval - best.bound[self.cutdim]:
(best2,bestdist2) = self.hi.nearest_neighbor(node, dist)
if bestdist2<bestdist:
return (best2,bestdist2)
return (best,bestdist)
else:
(best,bestdist) = self.hi.nearest_neighbor(node, dist)
if bestdist > best.bound[self.cutdim] - self.cutval:
(best2,bestdist2) = self.lo.nearest_neighbor(node, dist)
if bestdist2<bestdist:
return (best2,bestdist2)
return (best,bestdist)
def insert(self, node):
if self.dim==0:
self.dim = len(node.bound)
if self.bucket:
self.nodes.append(node)
if (len(self.nodes)>self.cutoff):
self.bucket = False
(cutdim,spread) = find_max_spread(self.nodes)
self.cutdim = cutdim
self.nodes.sort(cmp=lambda x,y:cmp(x.bound[cutdim],y.bound[cutdim]))
median = len(self.nodes)/2
self.minval = self.nodes[0].bound[cutdim]
self.maxval = self.nodes[-1].bound[cutdim]
self.cutval = self.nodes[median].bound[cutdim]
self.lo = kdtree(self.nodes[0:median], self.cutoff, self.cutoff_distance)
self.hi = kdtree(self.nodes[median:], self.cutoff, self.cutoff_distance)
else:
if node.bound[self.cutdim] <= self.cutval:
self.lo.insert(node)
else:
self.hi.insert(node)
import re import re
from pycam.Geometry import * from pycam.Geometry import *
from pycam.Geometry.PointKdtree import PointKdtree
from pycam.Geometry.TriangleKdtree import TriangleKdtree
vertices = 0
edges = 0
epsilon = 0.0001
kdtree = None
def UniqueVertex(x,y,z):
global vertices
if kdtree:
last = Point.id
p = kdtree.Point(x,y,z)
if p.id == last:
# print p
vertices += 1
return p
else:
vertices += 1
return Point(x,y,z)
def UniqueEdge(p1, p2):
global edges
if hasattr(p1,"edges"):
for e in p1.edges:
if e.p1 == p1 and e.p2 == p2:
return e
if e.p2 == p1 and e.p1 == p2:
return e
edges += 1
e = Line(p1,p2)
if not hasattr(p1,"edges"):
p1.edges = [e]
else:
p1.edges.append(e)
if not hasattr(p2,"edges"):
p2.edges = [e]
else:
p2.edges.append(e)
return e
def ImportModel(filename): def ImportModel(filename):
model = Model() global vertices, edges, kdtree
vertices = 0
edges = 0
kdtree = None
f = file(filename,"r") f = file(filename,"r")
solid = re.compile("\s*solid\s+(\w+)\s+.*") solid = re.compile("\s*solid\s+(\w+)\s+.*")
solid_AOI = re.compile("\s*solid\s+\"([\w\-]+)\"; Produced by Art of Illusion.*") solid_AOI = re.compile("\s*solid\s+\"([\w\-]+)\"; Produced by Art of Illusion.*")
...@@ -15,12 +60,15 @@ def ImportModel(filename): ...@@ -15,12 +60,15 @@ def ImportModel(filename):
endloop = re.compile("\s*endloop\s+") endloop = re.compile("\s*endloop\s+")
vertex = re.compile("\s*vertex\s+(?P<x>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)\s+(?P<y>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)\s+(?P<z>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)\s+") vertex = re.compile("\s*vertex\s+(?P<x>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)\s+(?P<y>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)\s+(?P<z>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)\s+")
kdtree = PointKdtree([],3,1,epsilon)
model = Model() model = Model()
t = None t = None
p1 = None p1 = None
p2 = None p2 = None
p3 = None p3 = None
AOI = False AOI = False
for line in f: for line in f:
m = solid_AOI.match(line) m = solid_AOI.match(line)
if m: if m:
...@@ -31,6 +79,7 @@ def ImportModel(filename): ...@@ -31,6 +79,7 @@ def ImportModel(filename):
if m: if m:
model.name = m.group(1) model.name = m.group(1)
continue continue
m = facet.match(line) m = facet.match(line)
if m: if m:
m = normal.match(line) m = normal.match(line)
...@@ -46,10 +95,9 @@ def ImportModel(filename): ...@@ -46,10 +95,9 @@ def ImportModel(filename):
m = vertex.match(line) m = vertex.match(line)
if m: if m:
if AOI: if AOI:
p = Point(float(m.group('x')),float(m.group('z')),float(m.group('y'))) p = UniqueVertex(float(m.group('x')),float(m.group('z')),float(m.group('y')))
else: else:
p = Point(float(m.group('x')),float(m.group('y')),float(m.group('z'))) p = UniqueVertex(float(m.group('x')),float(m.group('y')),float(m.group('z')))
# TODO: check for duplicate points (using kdtree?)
if p1 == None: if p1 == None:
p1 = p p1 = p
elif p2 == None: elif p2 == None:
...@@ -66,17 +114,26 @@ def ImportModel(filename): ...@@ -66,17 +114,26 @@ def ImportModel(filename):
if m: if m:
# make sure the points are in ClockWise order # make sure the points are in ClockWise order
if n.dot(p3.sub(p1).cross(p2.sub(p1)))>0: if n.dot(p3.sub(p1).cross(p2.sub(p1)))>0:
t = Triangle(p1, p2, p3) t = Triangle(p1, p2, p3, UniqueEdge(p1,p2), UniqueEdge(p2,p3), UniqueEdge(p3,p1))
else: else:
t = Triangle(p1, p3, p2) t = Triangle(p1, p3, p2, UniqueEdge(p1,p3), UniqueEdge(p3,p2), UniqueEdge(p2,p1))
t._normal = n t._normal = n
n=p1=p2=p3=None n=p1=p2=p3=None
# if t.normal().z < 0: if t.normal().z < 0:
# continue continue
model.append(t) model.append(t)
continue continue
m = endsolid.match(line) m = endsolid.match(line)
if m: if m:
continue continue
model.p_kdtree = kdtree
model.t_kdtree = TriangleKdtree(model.triangles())
print "Imported STL model: ", vertices, "vertices,", edges, "edges,", len(model.triangles()),"triangles"
vertices = 0
edges = 0
kdtree = None
return model return model
...@@ -5,27 +5,47 @@ def TestModel(): ...@@ -5,27 +5,47 @@ def TestModel():
points.append(Point(-2,1,4)) points.append(Point(-2,1,4))
points.append(Point(2,1,4)) points.append(Point(2,1,4))
points.append(Point(0,-2,4)) points.append(Point(0,-2,4))
points.append(Point(-5,2,2)) points.append(Point(-5,2,2))
points.append(Point(-1,3,2)) points.append(Point(-1,3,2))
points.append(Point(5,2,2)) points.append(Point(5,2,2))
points.append(Point(4,-1,2)) points.append(Point(4,-1,2))
points.append(Point(2,-4,2)) points.append(Point(2,-4,2))
points.append(Point(-2,-4,2)) points.append(Point(-2,-4,2))
points.append(Point(-3,-2,2)) points.append(Point(-3,-2,2))
lines = []
lines.append(Line(points[0],points[1]))
lines.append(Line(points[1],points[2]))
lines.append(Line(points[2],points[0]))
lines.append(Line(points[0],points[3]))
lines.append(Line(points[3],points[4]))
lines.append(Line(points[4],points[0]))
lines.append(Line(points[4],points[1]))
lines.append(Line(points[4],points[5]))
lines.append(Line(points[5],points[1]))
lines.append(Line(points[5],points[6]))
lines.append(Line(points[6],points[1]))
lines.append(Line(points[6],points[2]))
lines.append(Line(points[6],points[7]))
lines.append(Line(points[7],points[2]))
lines.append(Line(points[7],points[8]))
lines.append(Line(points[8],points[2]))
lines.append(Line(points[8],points[9]))
lines.append(Line(points[9],points[2]))
lines.append(Line(points[9],points[0]))
lines.append(Line(points[9],points[3]))
model = Model() model = Model()
model.append(Triangle(points[0],points[1],points[2])) model.append(Triangle(points[0],points[1],points[2],lines[0],lines[1],lines[2]))
model.append(Triangle(points[0],points[3],points[4])) model.append(Triangle(points[0],points[3],points[4],lines[3],lines[4],lines[5]))
model.append(Triangle(points[0],points[4],points[1])) model.append(Triangle(points[0],points[4],points[1],lines[5],lines[6],lines[0]))
model.append(Triangle(points[1],points[4],points[5])) model.append(Triangle(points[1],points[4],points[5],lines[6],lines[7],lines[8]))
model.append(Triangle(points[1],points[5],points[6])) model.append(Triangle(points[1],points[5],points[6],lines[8],lines[9],lines[10]))
model.append(Triangle(points[1],points[6],points[2])) model.append(Triangle(points[1],points[6],points[2],lines[10],lines[11],lines[1]))
model.append(Triangle(points[2],points[6],points[7])) model.append(Triangle(points[2],points[6],points[7],lines[11],lines[12],lines[13]))
model.append(Triangle(points[2],points[7],points[8])) model.append(Triangle(points[2],points[7],points[8],lines[13],lines[14],lines[15]))
model.append(Triangle(points[2],points[8],points[9])) model.append(Triangle(points[2],points[8],points[9],lines[15],lines[16],lines[17]))
model.append(Triangle(points[2],points[9],points[0])) model.append(Triangle(points[2],points[9],points[0],lines[17],lines[18],lines[2]))
model.append(Triangle(points[0],points[9],points[3])) model.append(Triangle(points[0],points[9],points[3],lines[18],lines[19],lines[3]))
return model return model
...@@ -30,7 +30,8 @@ class DropCutter: ...@@ -30,7 +30,8 @@ class DropCutter:
t_max = None t_max = None
cl_last = None cl_last = None
self.cutter.moveto(p) self.cutter.moveto(p)
for t in self.model.triangles(): triangles = self.model.triangles(p.x-self.cutter.radius,p.y-self.cutter.radius,z0,p.x+self.cutter.radius,p.y+self.cutter.radius,+INFINITE)
for t in triangles:
if t.normal().z < 0: continue; if t.normal().z < 0: continue;
cl = self.cutter.drop(t) cl = self.cutter.drop(t)
if cl and (cl.z > z_max or cl_max is None): if cl and (cl.z > z_max or cl_max is None):
...@@ -85,7 +86,8 @@ class DropCutter: ...@@ -85,7 +86,8 @@ class DropCutter:
t_max = None t_max = None
cl_last = None cl_last = None
self.cutter.moveto(p) self.cutter.moveto(p)
for t in self.model.triangles(): triangles = self.model.triangles(p.x-self.cutter.radius,p.y-self.cutter.radius,z0,p.x+self.cutter.radius,p.y+self.cutter.radius,+INFINITE)
for t in triangles:
if t.normal().z < 0: continue; if t.normal().z < 0: continue;
cl = self.cutter.drop(t) cl = self.cutter.drop(t)
if cl and (cl.z > z_max or cl_max is None): if cl and (cl.z > z_max or cl_max is None):
......
...@@ -138,7 +138,13 @@ class PushCutter: ...@@ -138,7 +138,13 @@ class PushCutter:
prev = Point(x,y,z) prev = Point(x,y,z)
hits.append(Hit(prev, None, 0, None)) hits.append(Hit(prev, None, 0, None))
for t in model.triangles(): triangles = None
if dx==0:
triangles = model.triangles(minx-self.cutter.radius,y-self.cutter.radius,z,maxx+self.cutter.radius,y+self.cutter.radius,INFINITE)
else:
triangles = model.triangles(x-self.cutter.radius,miny-self.cutter.radius,z,x+self.cutter.radius,maxy+self.cutter.radius,INFINITE)
for t in triangles:
#if t.normal().z < 0: continue; #if t.normal().z < 0: continue;
# normals point outward... and we want to approach the model from the outside! # normals point outward... and we want to approach the model from the outside!
n = t.normal().dot(forward) n = t.normal().dot(forward)
......
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