Commit dd10fa15 authored by lode_leroy's avatar lode_leroy

Contour

git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@48 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent d530ae74
Currently it is not necessary to install the software,
simply unpack the distribution archive, and run "python pycam.py" DEPENDENCIES:
from the archive directory -------------
Windows:
--------
Python 2.5
PyOpenGL : http://pyopengl.sourceforge.net/
http://downloads.sourceforge.net/pyopengl/PyOpenGL-3.0.0.win32.exe
TOGL: http://downloads.sourceforge.net/togl/Togl2.0-8.4-Windows.zip
(just copy the directory Togl2.0 into Python25/tcl)
GLUT : http://www.cip.physik.uni-muenchen.de/~georg.hennig/downloads/glut-3.7.6-wheel_mingw.zip
Unix:
-----
Install PyOpenGL, Togl, Glut using your package manager.
Or compile from source:
http://downloads.sourceforge.net/pyopengl/PyOpenGL-3.0.0.tar.gz
In case Togl is not available or not working, I suggest to compile Togl yourself.
http://downloads.sourceforge.net/togl/Togl2.0-src.tar.gz
Install the source packages for tcl and tk using your package manager.
cd ~/Togl2.0
./configure --prefix=/usr --exec-prefix=/usr --enable-threads
make
make install
or, failing that, for download the sources for the same version of tcl and tk
as you have installed on your system:
(http://sourceforge.net/project/showfiles.php?group_id=10894&package_id=10452)
Togl only needs access to a few header files that are not part of the
binary distributions...
I unpacked the tcl and tk sources next to the Togl sources in my home directory, then
cd ~/tcl-8.5.5/unix;
./configure
cd ~/tk-8.5.5/unix;
./configure
cd ~/Togl2.0;
./configure --with-tcl=$HOME/tcl-8.5.5 --with-tk=$HOME/tk-8.5.5 \
--prefix=/usr --exec-prefix=/usr --enable-threads
make
make install
...@@ -19,6 +19,7 @@ Features: ...@@ -19,6 +19,7 @@ Features:
** Linear ** Linear
** ZigZag ** ZigZag
** Polygon ** Polygon
** Contour (aka. waterline)
* Importers: * Importers:
** STL ** STL
...@@ -30,23 +31,6 @@ Features: ...@@ -30,23 +31,6 @@ Features:
** OpenGL ** OpenGL
INSTALL:
PyOpenGL : http://pyopengl.sourceforge.net/
http://downloads.sourceforge.net/pyopengl/PyOpenGL-3.0.0b5.tar.gz
(requires TOGL)
TOGL: http://downloads.sourceforge.net/togl/Togl2.0-8.4-Windows.zip
(just copy Togl2.0 into Python25/tcl)
http://downloads.sourceforge.net/togl/Togl2.0-src.tar.gz
(download tcl-8.4-src.tgz and tk-8.4-src.tgz and compile and install togl)
(on windows, this also requires GLUT)
GLUT : http://www.cip.physik.uni-muenchen.de/~georg.hennig/downloads/glut-3.7.6-wheel_mingw.zip
RUNNING: RUNNING:
extract the archive and run "python pycam.py" extract the archive and run "python pycam.py"
...@@ -57,12 +41,21 @@ USAGE: ...@@ -57,12 +41,21 @@ USAGE:
as a practical approach, you would probably: as a practical approach, you would probably:
1) use the Cylindrical cutter with the PushCutter Pathgenerator and the Polygon PostProcessor to do the "rough" cutting 1) for "rough" cutting,
use the Cylindrical cutter
with the PushCutter Pathgenerator
and the Polygon PostProcessor in "x" or "y" mode
2) use the Toroidal cutter with the ContourCutter Pathgenerator to do the "semifinish" cutting. 2) for "semifinish" cutting,
(it's not yet implemented, so you can skip this one for now :-) use the Cylindrical/Toroidal cutter
with the PushCutter Pathgenerator
and the Contour PostProcessor in "xy" mode
3) use the Spherical cutter with the DropCutter Pathgenerator and the ZigZag PostProcessor to do the "finish" cutting. 3) "finish" cutting
use the Spherical cutter
with the DropCutter Pathgenerator
and the ZigZag PostProcessor in "x" or "y" mode
TODO: TODO:
...@@ -78,12 +71,8 @@ TODO: ...@@ -78,12 +71,8 @@ TODO:
* Cutters * Cutters
** FiletCutter ** FiletCutter
* PathGenerators
** ContourCutter
-> waterlevel tracer
* PathProcessors * PathProcessors
** Traveling Salesman ** Traveling Salesman for Polygon PostProcessor
* Gui * Gui
** create something better than "SimpleGui" ** create something better than "SimpleGui"
...@@ -98,15 +87,13 @@ FEATURE REQUESTS: ...@@ -98,15 +87,13 @@ FEATURE REQUESTS:
* diagonal paths * diagonal paths
* start at arbitrary corner
KNOWN BUGS: KNOWN BUGS:
* The combination of PushCutter with PolygonCutter sometimes cuts accross * The combination of PushCutter with PolygonCutter and ContourCutter
the model in between lines sometimes make tiny cuts accross the model in between lines
* The combination of PushCutter with ContourCutter sometimes cuts accross
the model in between lines in "x" or "y" mode
* The combination of PushCutter with ContourCutter sometimes gives erratic
toolpaths in "xy" mode
OPTIMIZATION: OPTIMIZATION:
...@@ -114,7 +101,7 @@ OPTIMIZATION: ...@@ -114,7 +101,7 @@ OPTIMIZATION:
* short-circuit the plane/triangle/line/edge/point/vertex tests, * short-circuit the plane/triangle/line/edge/point/vertex tests,
so that when the result is known, no further intersections are calculated so that when the result is known, no further intersections are calculated
* use kdtree * use kdtree to speed up collision detection
* make Model have unique points * make Model have unique points
......
...@@ -16,11 +16,13 @@ def g(x): ...@@ -16,11 +16,13 @@ def g(x):
def b(x): def b(x):
return ((col[(x)%12]>> 0)&0xff) return ((col[(x)%12]>> 0)&0xff)
def test_image(image): def test_image(image, image2=None):
pe = PolygonExtractor(policy=PolygonExtractor.CONTOUR) pe = PolygonExtractor(policy=PolygonExtractor.CONTOUR)
h = len(image) h = len(image)
w = len(image[0]) w = len(image[0])
for dir in [0, 1]: for dir in [1, 0, 1]:
if dir == 1 and image2:
image = image2
pe.new_direction(dir) pe.new_direction(dir)
imax = 0 imax = 0
jmax = 0 jmax = 0
...@@ -80,10 +82,10 @@ def test_image(image): ...@@ -80,10 +82,10 @@ def test_image(image):
elif dir == 1: elif dir == 1:
path_list = pe.ver_path_list path_list = pe.ver_path_list
else: else:
if hasattr(pe, "merge_path_list"):
path_list = pe.merge_path_list path_list = pe.merge_path_list
else:
path_list = [] if not path_list:
continue
for curr_path in path_list: for curr_path in path_list:
for point in curr_path.points: for point in curr_path.points:
...@@ -325,6 +327,41 @@ if __name__ == "__main__": ...@@ -325,6 +327,41 @@ if __name__ == "__main__":
] ]
test_image(image) test_image(image)
if (test==9):
image = [
" ",
" ",
" *********** ",
" *********** ",
" *********** ",
" *********** ",
" ",
" ",
" *** ",
" ***** ",
" ********* ",
" *********** ",
" ",
" ",
]
image2 = [
" ",
" ",
" *********** ",
" *********** ",
" *********** ",
" *********** ",
" ",
" * ",
" *** ",
" ***** ",
" ********* ",
" *********** ",
" ",
" ",
]
test_image(image, image2 )
if (test==10): if (test==10):
image = [ image = [
......
...@@ -5,24 +5,17 @@ from pycam.Geometry.Path import * ...@@ -5,24 +5,17 @@ from pycam.Geometry.Path import *
from pycam.Geometry.Point import * from pycam.Geometry.Point import *
DEBUG_POLYGONEXTRACTOR=False DEBUG_POLYGONEXTRACTOR=False
DEBUG_POLYGONEXTRACTOR2=False
class PolygonExtractor: class PolygonExtractor:
CONTOUR=1 CONTOUR=1
MONOTONE=2 MONOTONE=2
def __init__(self, policy=MONOTONE): def __init__(self, policy=MONOTONE):
self.policy = policy self.policy = policy
self.hor_path_list = None self.hor_path_list = None
self.ver_path_list = None self.ver_path_list = None
self.merge_path_list = None self.merge_path_list = None
self.dx = 1
self.dy = 1
def append(self, p):
if (self.current_dir==0):
self.curr_line.append(p)
elif self.current_dir==1:
# store as flipped
self.curr_line.append(Point(p.y, p.x, p.z))
def new_direction(self, dir): def new_direction(self, dir):
self.current_dir = dir self.current_dir = dir
...@@ -31,16 +24,36 @@ class PolygonExtractor: ...@@ -31,16 +24,36 @@ class PolygonExtractor:
self.prev_line = [] self.prev_line = []
self.curr_line = [] self.curr_line = []
if self.policy == PolygonExtractor.CONTOUR and dir == 1 and self.hor_path_list:
self.last_x = -INFINITE
self.delta_x = 0
self.convert_hor_path_list()
def end_direction(self): def end_direction(self):
if self.policy == PolygonExtractor.CONTOUR and self.hor_path_list:
self.process_virtual_hor_scanline(INFINITE)
self.new_scanline() self.new_scanline()
self.end_scanline() self.end_scanline()
if self.policy == PolygonExtractor.CONTOUR and self.hor_path_list:
for path in self.all_path_list:
i = 0
while i < len(path.points)-1:
if path.points[i].x > path.points[i+1].x:
if DEBUG_POLYGONEXTRACTOR2: print "drop point %d:" % path.points[i].id
path.points = path.points[:i] + path.points[i+1:]
if i>0:
i -= 1
else:
i += 1
if DEBUG_POLYGONEXTRACTOR: print "%d paths" % len(self.all_path_list) if DEBUG_POLYGONEXTRACTOR: print "%d paths" % len(self.all_path_list)
for path in self.all_path_list: for path in self.all_path_list:
if DEBUG_POLYGONEXTRACTOR: print "%d:" % path.id, if DEBUG_POLYGONEXTRACTOR: print "%d:" % path.id,
if DEBUG_POLYGONEXTRACTOR: print "%d ->" % path.top_join.id if DEBUG_POLYGONEXTRACTOR: print "%d ->" % path.top_join.id
for point in path.points: for point in path.points:
if DEBUG_POLYGONEXTRACTOR: print "(%g,%g)" % (point.x, point.y), if DEBUG_POLYGONEXTRACTOR: print "%d(%g,%g)" % (point.id, point.x, point.y),
if DEBUG_POLYGONEXTRACTOR: print "->%d" % path.bot_join.id if DEBUG_POLYGONEXTRACTOR: print "->%d" % path.bot_join.id
path_list = [] path_list = []
...@@ -74,33 +87,46 @@ class PolygonExtractor: ...@@ -74,33 +87,46 @@ class PolygonExtractor:
for path in path_list: for path in path_list:
if DEBUG_POLYGONEXTRACTOR: print "path %d(w=%d): " % (path.id, path.winding), if DEBUG_POLYGONEXTRACTOR: print "path %d(w=%d): " % (path.id, path.winding),
for point in path.points: for point in path.points:
if DEBUG_POLYGONEXTRACTOR: print "(%g,%g)" % (point.x, point.y), if DEBUG_POLYGONEXTRACTOR: print "%d(%g,%g)" % (point.id, point.x, point.y),
if DEBUG_POLYGONEXTRACTOR: print if DEBUG_POLYGONEXTRACTOR: print
if self.current_dir==0: if self.current_dir==0:
self.hor_path_list = path_list self.hor_path_list = path_list
elif self.current_dir==1: elif self.current_dir==1:
# flip back since we stored the points flipped (see add_point) if self.policy == PolygonExtractor.CONTOUR and self.hor_path_list and self.ver_path_list:
for path in path_list: self.merge_path_list = path_list
path.reverse() else:
for point in path.points:
(point.x,point.y) = (point.y,point.x)
self.ver_path_list = path_list self.ver_path_list = path_list
def finish(self): def finish(self):
if self.policy == PolygonExtractor.CONTOUR: pass
if self.hor_path_list and self.ver_path_list:
self.merge_path_lists()
def new_scanline(self): def new_scanline(self):
self.curr_line = [] self.curr_line = []
def append(self, p):
self.curr_line.append(p)
def end_scanline(self): def end_scanline(self):
if self.current_dir==0:
self.process_hor_scanline(self.curr_line)
elif self.current_dir==1:
if self.policy == PolygonExtractor.CONTOUR and self.hor_path_list:
next_x = 0
if len(self.curr_line)>0:
next_x = self.curr_line[0].x
self.delta_x = next_x - self.last_x
self.last_x = next_x
else:
next_x = self.last_x + self.delta_x
self.process_virtual_hor_scanline(next_x)
self.process_ver_scanline(self.curr_line)
def process_hor_scanline(self, scanline):
last = 0 last = 0
inside = False inside = False
s = "" s = ""
for point in self.curr_line: for point in scanline:
next = point.x next = point.x
if inside: if inside:
s += "*" * int(next-last) s += "*" * int(next-last)
...@@ -121,12 +147,12 @@ class PolygonExtractor: ...@@ -121,12 +147,12 @@ class PolygonExtractor:
if DEBUG_POLYGONEXTRACTOR: print if DEBUG_POLYGONEXTRACTOR: print
if DEBUG_POLYGONEXTRACTOR: print "active points: ", if DEBUG_POLYGONEXTRACTOR: print "active points: ",
for point in self.curr_line: for point in scanline:
if DEBUG_POLYGONEXTRACTOR: print "(%g,%g)" % (point.x, point.y), if DEBUG_POLYGONEXTRACTOR: print "(%g,%g)" % (point.x, point.y),
if DEBUG_POLYGONEXTRACTOR: print if DEBUG_POLYGONEXTRACTOR: print
prev_point = Iterator(self.prev_line) prev_point = Iterator(self.prev_line)
curr_point = Iterator(self.curr_line) curr_point = Iterator(scanline)
curr_path = Iterator(self.curr_path_list) curr_path = Iterator(self.curr_path_list)
winding = 0 winding = 0
...@@ -304,119 +330,337 @@ class PolygonExtractor: ...@@ -304,119 +330,337 @@ class PolygonExtractor:
if DEBUG_POLYGONEXTRACTOR: print "%d(%g,%g,w=%d)" % (path.id, path.points[-1].x, path.points[-1].y, path.winding), if DEBUG_POLYGONEXTRACTOR: print "%d(%g,%g,w=%d)" % (path.id, path.points[-1].x, path.points[-1].y, path.winding),
if DEBUG_POLYGONEXTRACTOR: print if DEBUG_POLYGONEXTRACTOR: print
self.prev_line = self.curr_line self.prev_line = scanline
def merge_path_lists(self): def process_ver_scanline(self, scanline, next_x=-INFINITE):
self.merge_path_list = [] last = 0
inside = False
# find matching path to merge with */ s = ""
for s0 in self.hor_path_list: for point in scanline:
next = point.y
if DEBUG_POLYGONEXTRACTOR: print "merging %d" % s0.id if inside:
if DEBUG_POLYGONEXTRACTOR: print "s0=", s0 s += "*" * int(next-last)
else:
#TODO: store/cache topmost point inside the path s += " " * int(next-last)
last = next
# find top of path to merge inside = not inside
point_iter = Iterator(s0.points) if DEBUG_POLYGONEXTRACTOR: print s
top0 = CyclicIterator(point_iter.seq, point_iter.ind)
min_x0 = top0.peek().x if DEBUG_POLYGONEXTRACTOR: print "active paths: ",
min_y0 = top0.peek().y for path in self.curr_path_list:
while point_iter.remains()>0: if DEBUG_POLYGONEXTRACTOR: print "%d(%g,%g)" % (path.id, path.points[-1].x, path.points[-1].y),
point = point_iter.peek() if DEBUG_POLYGONEXTRACTOR: print
if point and ((point.y<min_y0) or (point.y==min_y0 and point.x>min_x0)):
min_y0 = point.y if DEBUG_POLYGONEXTRACTOR: print "prev points: ",
min_x0 = point.x for point in self.prev_line:
top0 = CyclicIterator(point_iter.seq, point_iter.ind) if DEBUG_POLYGONEXTRACTOR: print "(%g,%g)" % (point.x, point.y),
point_iter.next() if DEBUG_POLYGONEXTRACTOR: print
if DEBUG_POLYGONEXTRACTOR: print "top0: x=", min_x0, "y=",min_y0, "p=",top0.peek().id
# find matching path to merge with if DEBUG_POLYGONEXTRACTOR: print "active points: ",
path_iter = Iterator(self.ver_path_list) for point in scanline:
while path_iter.remains()>0: if DEBUG_POLYGONEXTRACTOR: print "(%g,%g)" % (point.x, point.y),
s1 = path_iter.next() if DEBUG_POLYGONEXTRACTOR: print
if DEBUG_POLYGONEXTRACTOR: print "trying %d" % s1.id
if DEBUG_POLYGONEXTRACTOR: print "s1=", s1 prev_point = Iterator(self.prev_line)
curr_point = Iterator(scanline)
min_d = -1 curr_path = Iterator(self.curr_path_list)
point_iter = Iterator(s1.points)
top1 = None winding = 0
min_x1 = 0 while prev_point.remains()>0 or curr_point.remains()>0:
min_y1 = 0 if DEBUG_POLYGONEXTRACTOR: print "num_prev=", prev_point.remains(), ", num_curr=",curr_point.remains()
while point_iter.remains()>0: if prev_point.remains()==0 and curr_point.remains()>=2:
point = point_iter.peek() c0 = curr_point.next()
# check points in second quadrant # TODO: if none found: check other quadrants c1 = curr_point.next()
if point.y<=min_y0 and point.x<=min_x0: # new path starts
d = sqr(point.x-min_x0)+sqr(point.y-min_y0) p0 = Path()
if (d<min_d or top1==None): p0.winding = winding+1
min_x1 = point.x if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g)" % ( p0.id, c0.x, c0.y)
min_y1 = point.y p0.append(c0)
min_d = d self.curr_path_list.append(p0)
top1 = CyclicIterator(point_iter.seq, point_iter.ind) p1 = Path()
point_iter.next() p1.winding = winding
if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g)" % (p1.id, c1.x, c1.y)
if DEBUG_POLYGONEXTRACTOR: print "min_y0=%g min_y1=%g (d=%g)" % (min_y0, min_y1, min_d) p1.append(c1)
if min_d < 0: self.curr_path_list.append(p1)
p0.top_join = p1
p1.top_join = p0
continue
if prev_point.remains()>=2 and curr_point.remains()==0:
#old path ends
p0 = curr_path.takeNext()
if DEBUG_POLYGONEXTRACTOR: print "end path %d" % p0.id
self.all_path_list.append(p0)
prev_point.next()
p1 = curr_path.takeNext()
if DEBUG_POLYGONEXTRACTOR: print "end path %d" % p1.id
self.all_path_list.append(p1)
prev_point.next()
p0.bot_join = p1
p1.bot_join = p0
continue continue
if DEBUG_POLYGONEXTRACTOR: print "top1: x=", min_x1, "y=",min_y1, "p=",top1.peek().id if prev_point.remains()>=2 and curr_point.remains()>=2:
p0 = prev_point.peek(0)
if (min_y1 >= min_y0-self.dy) and (min_y1 <= min_y0+self.dy) and (min_x1 >= min_x0-self.dx) and (min_x1 <= min_x0+self.dx): p1 = prev_point.peek(1)
# we have a potential match c0 = curr_point.peek(0)
if DEBUG_POLYGONEXTRACTOR: print "matched %d" % s1.id c1 = curr_point.peek(1)
if DEBUG_POLYGONEXTRACTOR: print "i0=%d i1=%d" % (top0.peek().id, top1.peek().id)
if DEBUG_POLYGONEXTRACTOR: print "s1=", s1 if DEBUG_POLYGONEXTRACTOR: print "overlap test: p0=%g p1=%g" % (p0.x, p1.x)
total = len(s0.points) + len(s1.points) if DEBUG_POLYGONEXTRACTOR: print "overlap test: c0=%g c1=%g" % (c0.x, c1.x)
p = Path()
p.winding = s0.winding if c1.y < p0.y:
# new segment is completely to the left
p0 = top0.next() # new path starts
p1 = top1.next() s0 = Path()
if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g) w=%d" % (s0.id, c0.x, c0.y, winding+1)
next_p0 = top0.peek() s0.append(c0)
next_p1 = top1.peek() curr_path.insert(s0)
s1 = Path()
if p0.y == next_p0.y: s0.winding = winding+1
while (p1.y < p0.y) and (next_p1.y < p0.y) and (p0.x <= p1.x) and (p1.x <= next_p0.x): s1.winding = winding
p1 = top1.next() if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g) w=%d" % (s1.id, c1.x, c1.y, winding)
next_p1 = top1.peek() s1.append(c1)
curr_path.insert(s1)
if DEBUG_POLYGONEXTRACTOR: print "top0=%d: (%g,%g)" % (p0.id, p0.x, p0.y) curr_point.next()
if DEBUG_POLYGONEXTRACTOR: print "top1=%d: (%g,%g)" % (p1.id, p1.x, p1.y) curr_point.next()
s0.top_join = s1
last = p0; s1.top_join = s0
elif c0.y > p1.y:
pathlen = 0 # new segment is completely to the right
while pathlen < total: # old path ends
next_p0 = top0.peek() s0 = curr_path.takeNext()
next_p1 = top1.peek() if DEBUG_POLYGONEXTRACTOR: print "end path %d" % s0.id
self.all_path_list.append(s0)
pathlen = len(p.points) prev_point.next()
s1 = curr_path.takeNext()
if DEBUG_POLYGONEXTRACTOR: print "last=%d: (%g, %g)" % (last.id, last.x, last.y) if DEBUG_POLYGONEXTRACTOR: print "end path %d" % s1.id
if DEBUG_POLYGONEXTRACTOR: print "p0: %d(%g,%g)\t" % (p0.id, p0.x, p0.y), self.all_path_list.append(s1)
if DEBUG_POLYGONEXTRACTOR: print "next_p0: %d(%g,%g)" % (next_p0.id, next_p0.x, next_p0.y) prev_point.next()
if DEBUG_POLYGONEXTRACTOR: print "p1: %d(%g,%g)\t" % (p1.id, p1.x, p1.y), s0.bot_join = s1;
if DEBUG_POLYGONEXTRACTOR: print "next_p1: %d(%g,%g)" % (next_p1.id, next_p1.x, next_p1.y) s1.bot_join = s0;
if DEBUG_POLYGONEXTRACTOR: print "|p1-last|=%g |p0-last|=%g" % (sqr(p1.x - last.x) + sqr(p1.y - last.y), sqr(p0.x - last.x) + sqr(p0.y - last.y)) winding = s1.winding;
if sqr(p1.x - last.x) + sqr(p1.y - last.y) < sqr(p0.x - last.x) + sqr(p0.y - last.y): else:
if DEBUG_POLYGONEXTRACTOR: print "0: p1=%d: (%g,%g)" % (p1.id, p1.x, p1.y) # new segment is overlapping
p.append(p1) left_path = curr_path.next()
last = p1 right_path = curr_path.peek()
p1 = top1.next() left_point = c0
right_point = c1
winding = left_path.winding
curr_point.next()
prev_point.next()
overlap_p = True
overlap_c = True
while overlap_c or overlap_p:
overlap_p = False
overlap_c = False
# check for path joins
if prev_point.remains()>=2:
p2 = prev_point.peek(1)
if DEBUG_POLYGONEXTRACTOR: print "join test: p0=%g p1=%g p2=%g" % (p0.x, p1.x, p2.x)
if DEBUG_POLYGONEXTRACTOR: print "join test: c0=%g c1=%g" % (c0.x, c1.x)
if p2.y <= c1.y:
overlap_p = True
if self.policy == PolygonExtractor.CONTOUR:
s0 = curr_path.takeNext()
s1 = curr_path.takeNext()
if curr_path.remains()>=1:
right_path = curr_path.peek()
self.all_path_list.append(s0)
self.all_path_list.append(s1);
if DEBUG_POLYGONEXTRACTOR: print "path %d joins %d" % (s0.id, s1.id)
s0.bot_join = s1;
s1.bot_join = s0;
elif self.policy == PolygonExtractor.MONOTONE:
s0 = curr_path.takeNext()
left_path.bot_join = s0
s0.bot_join = left_path
if DEBUG_POLYGONEXTRACTOR: print "path %d joins %d" % (left_path.id, s0.id)
curr_path.remove(left_path)
self.all_path_list.append(left_path)
self.all_path_list.append(s0)
s1 = curr_path.next()
left_path = s1
right_path = curr_path.peek()
prev_point.next()
prev_point.next()
winding = s1.winding
p0 = p2
if prev_point.remains()>=1:
p1 = prev_point.peek(0)
else:
overlap_p = False
# check for path splits
if curr_point.remains()>=2:
c2 = curr_point.peek(1)
if DEBUG_POLYGONEXTRACTOR: print "split test: p0=%g p1=%g" % (p0.x, p1.x)
if DEBUG_POLYGONEXTRACTOR: print "split test: c0=%g c1=%g c2=%g" % (c0.x, c1.x, c2.x)
if c2.y <= p1.y:
overlap_c = True
s0 = Path()
s1 = Path()
s0.winding=winding+1
s1.winding=winding
s0.top_join = s1
s1.top_join = s0
if DEBUG_POLYGONEXTRACTOR: print "region split into %d and %d (w=%d)" %(s0.id, s1.id, winding+1)
curr_point.next()
c0 = curr_point.next()
if self.policy == PolygonExtractor.CONTOUR:
s0.append(c1)
curr_path.insert(s0)
s1.append(c2)
curr_path.insert(s1)
elif self.policy == PolygonExtractor.MONOTONE:
s0.append(left_point)
s1.append(c1)
curr_path.insertBefore(s0)
curr_path.insertBefore(s1)
left_point = c2
if curr_point.remains()>=1:
c1 = curr_point.peek(0)
right_point = c1
else:
overlap_c = False
if DEBUG_POLYGONEXTRACTOR: print "add to path %d(%g,%g)" % (left_path.id, left_point.x, left_point.y)
left_path.append(left_point)
right_path.append(right_point)
if right_path == curr_path.peek():
curr_path.next()
if DEBUG_POLYGONEXTRACTOR: print "add to path %d(%g,%g)" % (right_path.id, right_point.x, right_point.y)
winding = right_path.winding;
prev_point.next()
curr_point.next()
if DEBUG_POLYGONEXTRACTOR: print "active paths: ",
for path in self.curr_path_list:
if DEBUG_POLYGONEXTRACTOR: print "%d(%g,%g,w=%d)" % (path.id, path.points[-1].x, path.points[-1].y, path.winding),
if DEBUG_POLYGONEXTRACTOR: print
self.prev_line = scanline
def convert_hor_path_list(self):
if DEBUG_POLYGONEXTRACTOR2: print "converting hor paths"
hor_path_list = []
for s in self.hor_path_list:
allsame = True
miny = s.points[0].y
maxy = s.points[0].y
for p in s.points:
if not p.x == s.points[0].x:
allsame=False
if p.y < miny:
miny = p.y
if p.y > maxy:
maxy = p.y
if allsame:
if DEBUG_POLYGONEXTRACTOR2: print "all same !"
s0 = Path()
for p in s.points:
if p.y == miny:
s0.append(p)
hor_path_list.append(s0)
s1 = Path()
for p in s.points:
if p.y == maxy:
s1.append(p)
hor_path_list.append(s1)
continue
prev = s.points[-1]
iter = CyclicIterator(s.points)
p = s.points[0]
next = iter.next()
while not (prev.x >= p.x and next.x > p.x):
p = next
next = iter.next()
count = 0
while count < len(s.points):
s0 = Path()
while next.x >= p.x:
s0.append(p)
p = next
next = iter.next()
count += 1
s0.append(p)
while len(s0.points)>1 and s0.points[0].x == s0.points[1].x:
s0.points = s0.points[1:]
while len(s0.points)>1 and s0.points[-2].x == s0.points[-1].x:
s0.points = s0.points[0:-1]
hor_path_list.append(s0)
s1 = Path()
while next.x <= p.x:
s1.append(p)
p = next
next = iter.next()
count += 1
s1.append(p)
s1.reverse()
while len(s1.points)>1 and s1.points[0].x == s1.points[1].x:
s1.points = s1.points[1:]
while len(s1.points)>1 and s1.points[-2].x == s1.points[-1].x:
s1.points = s1.points[0:-1]
hor_path_list.append(s1)
hor_path_list.sort(cmp=lambda a,b:cmp(a.points[0].x,b.points[0].x))
if DEBUG_POLYGONEXTRACTOR2:
print "ver_hor_path_list = ", hor_path_list
for s in hor_path_list:
print "s%d =" % s.id,
for point in s.points:
print point.id,
print
self.ver_hor_path_list = hor_path_list
self.act_hor_path_list = []
def process_virtual_hor_scanline(self, next_x):
if len(self.ver_hor_path_list)>0 and self.ver_hor_path_list[0].points[0].x < next_x:
next_x = self.ver_hor_path_list[0].points[0].x
if len(self.act_hor_path_list)>0 and self.act_hor_path_list[0].points[0].x < next_x:
next_x = self.act_hor_path_list[0].points[0].x
if DEBUG_POLYGONEXTRACTOR2:
print "ver_hor_path_list =", self.ver_hor_path_list
print "act_hor_path_list =", self.act_hor_path_list
print "next_x =", next_x
if len(self.ver_hor_path_list)>0 and self.ver_hor_path_list[0].points[0].x <= next_x:
while len(self.ver_hor_path_list)>0 and self.ver_hor_path_list[0].points[0].x <= next_x:
self.act_hor_path_list.append(self.ver_hor_path_list[0])
self.ver_hor_path_list = self.ver_hor_path_list[1:]
self.act_hor_path_list.sort(cmp=lambda a,b:cmp(a.points[0].x,b.points[0].x))
while len(self.act_hor_path_list)>0 and self.act_hor_path_list[0].points[0].x <= next_x:
scanline = []
i = 0
while i < len(self.act_hor_path_list):
s = self.act_hor_path_list[i]
if DEBUG_POLYGONEXTRACTOR2: print "s =",s
scanline.append(s.points[0])
if s.points[0].x <= next_x:
if len(s.points) <= 1:
if DEBUG_POLYGONEXTRACTOR2: print "remove list"
self.act_hor_path_list = self.act_hor_path_list[:i]+self.act_hor_path_list[i+1:]
hor_list_removed = True
continue continue
else: else:
if DEBUG_POLYGONEXTRACTOR: print "1: p0=%d: (%g,%g)" % (p0.id, p0.x, p0.y) if DEBUG_POLYGONEXTRACTOR2: print "remove point", s.points[0]
p.append(p0) s.points = s.points[1:]
last = p0 if len(s.points)> 0 and s.points[0].x == next_x:
p0 = top0.next() repeat = True
continue; i += 1
self.act_hor_path_list.sort(cmp=lambda a,b:cmp(a.points[0].x,b.points[0].x))
if pathlen == len(p): scanline.sort(cmp=lambda a,b:cmp(a.y,b.y))
if DEBUG_POLYGONEXTRACTOR: print "failed: size=%d total=%d" %(len(p), total) if DEBUG_POLYGONEXTRACTOR2:
p = None print "scanline =", scanline
break print "ver_hor_path_list =", self.ver_hor_path_list
print "act_hor_path_list =", self.act_hor_path_list
if p: self.process_ver_scanline(scanline)
self.merge_path_list.append(p)
if DEBUG_POLYGONEXTRACTOR: print "done: size=%d total=%d" % (len(p.points), total)
break
...@@ -6,13 +6,16 @@ class ContourCutter: ...@@ -6,13 +6,16 @@ class ContourCutter:
self.paths = [] self.paths = []
self.curr_path = None self.curr_path = None
self.scanline = None self.scanline = None
self.pe = PolygonExtractor(PolygonExtractor.CONTOUR) self.pe = None
self.points = [] self.points = []
def append(self, p): def append(self, p):
self.points.append(p) self.points.append(p)
def new_direction(self, dir): def new_direction(self, dir):
if self.pe == None:
self.pe = PolygonExtractor(PolygonExtractor.CONTOUR)
self.pe.new_direction(dir) self.pe.new_direction(dir)
def end_direction(self): def end_direction(self):
...@@ -38,5 +41,5 @@ class ContourCutter: ...@@ -38,5 +41,5 @@ class ContourCutter:
self.paths = self.pe.ver_path_list self.paths = self.pe.ver_path_list
for p in self.paths: for p in self.paths:
p.append(p.points[0]) p.append(p.points[0])
self.pe = 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