Commit 96c99d84 authored by sumpfralle's avatar sumpfralle

separated the single-line pushcutter collision detection


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@359 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 35814f29
...@@ -23,21 +23,10 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -23,21 +23,10 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
from pycam.Geometry import Point from pycam.Geometry import Point
from pycam.Geometry.utils import INFINITE, epsilon from pycam.Geometry.utils import INFINITE, epsilon
from pycam.PathGenerators import drop_cutter_test, get_free_horizontal_paths_ode from pycam.PathGenerators import drop_cutter_test, get_free_horizontal_paths_ode, get_free_horizontal_paths_triangles
import math import math
class Hit:
def __init__(self, cl, t, d, dir):
self.cl = cl
self.t = t
self.d = d
self.dir = dir
self.z = -INFINITE
def cmp(a,b):
return cmp(a.d, b.d)
class ProgressCounter: class ProgressCounter:
def __init__(self, max_value): def __init__(self, max_value):
...@@ -181,106 +170,25 @@ class PushCutter: ...@@ -181,106 +170,25 @@ class PushCutter:
def GenerateToolPathSlice_triangles(self, minx, maxx, miny, maxy, z, dx, dy, def GenerateToolPathSlice_triangles(self, minx, maxx, miny, maxy, z, dx, dy,
draw_callback=None, progress_counter=None): draw_callback=None, progress_counter=None):
c = self.cutter
model = self.model
if dx==0:
forward = Point(1,0,0)
backward = Point(-1,0,0)
forward_small = Point(epsilon,0,0)
backward_small = Point(-epsilon,0,0)
elif dy == 0:
forward = Point(0,1,0)
backward = Point(0,-1,0)
forward_small = Point(0,epsilon,0)
backward_small = Point(0,-epsilon,0)
x = minx x = minx
y = miny y = miny
line = 0
last_loop = False last_loop = False
while x<=maxx and y<=maxy: while x <= maxx and y <= maxy:
self.pa.new_scanline() self.pa.new_scanline()
# find all hits along scan line if dx > 0:
hits = [] points = get_free_horizontal_paths_triangles(self.model, self.cutter, x, x, miny, maxy, z)
prev = Point(x,y,z)
hits.append(Hit(prev, None, 0, None))
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;
# normals point outward... and we want to approach the model from the outside!
n = t.normal().dot(forward)
c.moveto(prev)
if n>=0:
(cl,d) = c.intersect(backward, t)
if cl:
hits.append(Hit(cl,t,-d,backward))
hits.append(Hit(cl.sub(backward_small),t,-d+epsilon,backward))
hits.append(Hit(cl.add(backward_small),t,-d-epsilon,backward))
if n<=0:
(cl,d) = c.intersect(forward, t)
if cl:
hits.append(Hit(cl,t,d,forward))
hits.append(Hit(cl.add(forward_small),t,d+epsilon,forward))
hits.append(Hit(cl.sub(forward_small),t,d-epsilon,forward))
if dx == 0:
x = maxx
if dy == 0:
y = maxy
next = Point(x, y, z)
hits.append(Hit(next, None, maxx-minx, None))
# sort along the scan direction
hits.sort(Hit.cmp)
# remove duplicates (typically shared edges)
i = 1
while i < len(hits):
while i<len(hits) and abs(hits[i].d - hits[i-1].d)<epsilon/2:
del hits[i]
i += 1
# determine height at each interesting point
for h in hits:
(zmax, tmax) = drop_cutter_test(self.cutter, h.cl, model)
h.z = zmax
# find first hit cutter location that is below z-level
begin = hits[0].cl
end = None
for h in hits:
if h.z >= z - epsilon/10:
if begin and end:
self.pa.append(begin)
self.pa.append(end)
begin = None
end = None
if h.z <= z + epsilon/10:
if not begin:
begin = h.cl
else: else:
end = h.cl points = get_free_horizontal_paths_triangles(self.model, self.cutter, minx, maxx, y, y, z)
if begin and end: if points:
self.pa.append(begin) for p in points:
self.pa.append(end) self.pa.append(p)
self.cutter.moveto(begin) self.cutter.moveto(p)
self.cutter.moveto(end)
if draw_callback: if draw_callback:
draw_callback(tool_position=end) draw_callback(tool_position=p)
if dx != 0: if dx != 0:
x += dx x += dx
......
...@@ -22,8 +22,100 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>. ...@@ -22,8 +22,100 @@ along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
__all__ = ["DropCutter", "PushCutter"] __all__ = ["DropCutter", "PushCutter"]
from pycam.Geometry.utils import INFINITE from pycam.Geometry.utils import INFINITE, epsilon
from pycam.Geometry import Point from pycam.Geometry import Point
import math
class Hit:
def __init__(self, cl, t, d, dir):
self.cl = cl
self.t = t
self.d = d
self.dir = dir
self.z = -INFINITE
def cmp(a,b):
return cmp(a.d, b.d)
def get_free_horizontal_paths_triangles(model, cutter, minx, maxx, miny, maxy, z):
points = []
x_dist = abs(maxx - minx)
y_dist = abs(maxy - miny)
xy_dist = math.sqrt(x_dist * x_dist + y_dist * y_dist)
x_frac = x_dist / xy_dist
y_frac = y_dist / xy_dist
forward = Point(x_frac, y_frac, 0)
backward = Point(-x_frac, -y_frac, 0)
forward_small = Point(epsilon * x_frac, epsilon * y_frac, 0)
backward_small = Point(-epsilon * x_frac, -epsilon * y_frac, 0)
# find all hits along scan line
hits = []
prev = Point(minx, miny, z)
hits.append(Hit(prev, None, 0, None))
triangles = model.triangles(minx - cutter.radius, miny - cutter.radius, z,
maxx + cutter.radius, maxy + cutter.radius, INFINITE)
for t in triangles:
# normals point outward... and we want to approach the model from the outside!
n = t.normal().dot(forward)
cutter.moveto(prev)
if n >= 0:
(cl, d) = cutter.intersect(backward, t)
if cl:
hits.append(Hit(cl, t, -d, backward))
hits.append(Hit(cl.sub(backward_small), t, -d + epsilon, backward))
hits.append(Hit(cl.add(backward_small), t, -d - epsilon, backward))
if n <= 0:
(cl, d) = cutter.intersect(forward, t)
if cl:
hits.append(Hit(cl, t, d, forward))
hits.append(Hit(cl.add(forward_small), t, d + epsilon, forward))
hits.append(Hit(cl.sub(forward_small), t, d - epsilon, forward))
next = Point(maxx, maxy, z)
hits.append(Hit(next, None, xy_dist, None))
# sort along the scan direction
hits.sort(Hit.cmp)
# remove duplicates (typically shared edges)
i = 1
while i < len(hits):
while i<len(hits) and abs(hits[i].d - hits[i-1].d)<epsilon/2:
del hits[i]
i += 1
# determine height at each interesting point
for h in hits:
(zmax, tmax) = drop_cutter_test(cutter, h.cl, model)
h.z = zmax
# find first hit cutter location that is below z-level
begin = hits[0].cl
end = None
for h in hits:
if h.z >= z - epsilon/10:
if begin and end:
points.append(begin)
points.append(end)
begin = None
end = None
if h.z <= z + epsilon/10:
if not begin:
begin = h.cl
else:
end = h.cl
# add add possibly remaining couple from the previous loop
if begin and end:
points.append(begin)
points.append(end)
return points
def get_free_horizontal_paths_ode(physics, minx, maxx, miny, maxy, z, depth=8): def get_free_horizontal_paths_ode(physics, minx, maxx, miny, maxy, z, depth=8):
...@@ -91,11 +183,10 @@ def get_free_horizontal_paths_ode(physics, minx, maxx, miny, maxy, z, depth=8): ...@@ -91,11 +183,10 @@ def get_free_horizontal_paths_ode(physics, minx, maxx, miny, maxy, z, depth=8):
def drop_cutter_test(cutter, point, model): def drop_cutter_test(cutter, point, model):
zmax = -INFINITE zmax = -INFINITE
tmax = None tmax = None
c = cutter cutter.moveto(point)
c.moveto(point)
for t in model.triangles(): for t in model.triangles():
if t.normal().z < 0: continue if t.normal().z < 0: continue
cl = c.drop(t) cl = cutter.drop(t)
if cl and cl.z > zmax and cl.z < INFINITE: if cl and cl.z > zmax and cl.z < INFINITE:
zmax = cl.z zmax = cl.z
tmax = t tmax = t
......
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