class PathAccumulator(pycam.PathProcessors.BasePathProcessor): def __init__(self, zigzag=False, reverse=False): super(PathAccumulator, self).__init__() self.curr_path = None self.zigzag = zigzag self.scanline = None self.reverse = reverse def append(self, point): if self.curr_path == None: self.curr_path = Path() if self.reverse: self.curr_path.insert(0, point) else: self.curr_path.append(point) def new_direction(self, direction): self.scanline = 0 def new_scanline(self): self.scanline += 1 if self.curr_path: print "ERROR: curr_path expected to be empty" self.curr_path = None def end_scanline(self): if self.curr_path: if self.zigzag and (self.scanline % 2 == 0): self.curr_path.reverse() simplify_toolpath(self.curr_path) if self.reverse: self.paths.insert(0, self.curr_path) else: self.paths.append(self.curr_path) self.curr_path = None
def copy(self): new_paths = [] for path in self.paths: new_path = Path() for point in path.points: new_path.append(point) new_paths.append(new_path) return Toolpath(new_paths, parameters=self.get_params())
def finish(self): self.polygon_extractor.finish() paths = [] source_paths = [] if self.polygon_extractor.hor_path_list: source_paths.extend(self.polygon_extractor.hor_path_list) if self.polygon_extractor.ver_path_list: source_paths.extend(self.polygon_extractor.ver_path_list) for path in source_paths: points = path.points for i in range((len(points) + 1) // 2): new_path = Path() if i % 2 == 0: new_path.append(points[i]) new_path.append(points[-i-1]) else: new_path.append(points[-i-1]) new_path.append(points[i]) paths.append(new_path) if paths: for path in paths: simplify_toolpath(path) if self.reverse: path.reverse() self.paths.extend(paths) self.sort_layered()
def finish(self): self.polygon_extractor.finish() paths = [] source_paths = [] if self.polygon_extractor.hor_path_list: source_paths.extend(self.polygon_extractor.hor_path_list) if self.polygon_extractor.ver_path_list: source_paths.extend(self.polygon_extractor.ver_path_list) for path in source_paths: points = path.points for i in range(0, (len(points)+1)/2): new_path = Path() if i % 2 == 0: new_path.append(points[i]) new_path.append(points[-i-1]) else: new_path.append(points[-i-1]) new_path.append(points[i]) paths.append(new_path) if paths: for path in paths: simplify_toolpath(path) if self.reverse: path.reverse() self.paths.extend(paths) self.sort_layered()
def append(self, point): curr_path = None if self.curr_path == None: curr_path = Path() self.curr_path = curr_path else: curr_path = self.curr_path self.curr_path = None curr_path.append(point) if self.curr_path == None: simplify_toolpath(curr_path) if self.reverse: curr_path.reverse() self.paths.insert(0, curr_path) else: self.paths.append(curr_path)
def append(self, point): curr_path = None if self.curr_path == None: curr_path = Path() self.curr_path = curr_path else: curr_path = self.curr_path self.curr_path = None curr_path.append(point) if self.curr_path == None: if (self.scanline % 2) == 0: self.curr_scanline.append(curr_path) else: curr_path.reverse() self.curr_scanline.insert(0, curr_path)
def crop(self, polygons, callback=None): # collect all existing toolpath lines open_lines = [] for path in self.toolpath: if path: for index in range(len(path.points) - 1): open_lines.append(Line(path.points[index], path.points[index + 1])) # go through all polygons and add "inner" lines (or parts thereof) to # the final list of remaining lines inner_lines = [] for polygon in polygons: new_open_lines = [] for line in open_lines: if callback and callback(): return inner, outer = polygon.split_line(line) inner_lines.extend(inner) new_open_lines.extend(outer) open_lines = new_open_lines # turn all "inner_lines" into toolpath movements new_paths = [] current_path = Path() if inner_lines: line = inner_lines.pop(0) current_path.append(line.p1) current_path.append(line.p2) while inner_lines: if callback and callback(): return end = current_path.points[-1] # look for the next connected point for line in inner_lines: if line.p1 == end: inner_lines.remove(line) current_path.append(line.p2) break else: new_paths.append(current_path) current_path = Path() line = inner_lines.pop(0) current_path.append(line.p1) current_path.append(line.p2) if current_path.points: new_paths.append(current_path) self.toolpath = new_paths
def crop(self, polygons, callback=None): # collect all existing toolpath lines open_lines = [] for path in self.paths: if path: for index in range(len(path.points) - 1): open_lines.append( Line(path.points[index], path.points[index + 1])) # go through all polygons and add "inner" lines (or parts thereof) to # the final list of remaining lines inner_lines = [] for polygon in polygons: new_open_lines = [] for line in open_lines: if callback and callback(): return inner, outer = polygon.split_line(line) inner_lines.extend(inner) new_open_lines.extend(outer) open_lines = new_open_lines # turn all "inner_lines" into toolpath moves new_paths = [] current_path = Path() if inner_lines: line = inner_lines.pop(0) current_path.append(line.p1) current_path.append(line.p2) while inner_lines: if callback and callback(): return end = current_path.points[-1] # look for the next connected point for line in inner_lines: if line.p1 == end: inner_lines.remove(line) current_path.append(line.p2) break else: new_paths.append(current_path) current_path = Path() line = inner_lines.pop(0) current_path.append(line.p1) current_path.append(line.p2) if current_path.points: new_paths.append(current_path) self.paths = new_paths
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] p_iter = CyclicIterator(s.points) p = s.points[0] next_p = p_iter.next() while not ((prev.x >= p.x) and (next_p.x > p.x)): p = next_p next_p = p_iter.next() count = 0 while count < len(s.points): s0 = Path() while next_p.x >= p.x: s0.append(p) p = next_p next_p = p_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_p.x <= p.x: s1.append(p) p = next_p next_p = p_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[:-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_ver_scanline(self, scanline): if DEBUG_POLYGONEXTRACTOR3: prev = None for p in scanline: if p.dir == 0: self.cont.fill("red") else: self.cont.fill("blue") self.cont.AddDot(p.x, p.y) self.cont.fill("black") self.cont.AddText(p.x, p.y, str(p.id)) if prev: self.cont.AddLine(prev.x, prev.y, p.x, p.y) prev = p if DEBUG_POLYGONEXTRACTOR: last = 0 inside = False s = "" for point in scanline: next_y = point.y if inside: s += "*" * int(next_y - last) else: s += " " * int(next_y - last) last = next_y inside = not inside print s if DEBUG_POLYGONEXTRACTOR: print "active paths: ", for path in self.curr_path_list: print "%d(%g,%g)" \ % (path.id, path.points[-1].x, path.points[-1].y), print print "prev points: ", for point in self.prev_line: print "(%g,%g)" % (point.x, point.y), print print "active points: ", for point in scanline: print "%d(%g,%g)" % (point.id, point.x, point.y), print prev_point = Iterator(self.prev_line) curr_point = Iterator(scanline) curr_path = Iterator(self.curr_path_list) winding = 0 while (prev_point.remains() > 0) or (curr_point.remains() > 0): if DEBUG_POLYGONEXTRACTOR: print "num_prev=%d, num_curr=%d" \ % (prev_point.remains(), curr_point.remains()) if (prev_point.remains() == 0) and (curr_point.remains() >= 2): c0 = curr_point.next() c1 = curr_point.next() # new path starts p0 = Path() p0.winding = winding + 1 if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g)" % (p0.id, c0.x, c0.y) p0.append(c0) self.curr_path_list.append(p0) p1 = Path() p1.winding = winding if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g)" % (p1.id, c1.x, c1.y) p1.append(c1) 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 if (prev_point.remains() >= 2) and (curr_point.remains() >= 2): p0 = prev_point.peek(0) p1 = prev_point.peek(1) c0 = curr_point.peek(0) c1 = curr_point.peek(1) if DEBUG_POLYGONEXTRACTOR: print "overlap test: p0=%g p1=%g" % (p0.x, p1.x) print "overlap test: c0=%g c1=%g" % (c0.x, c1.x) if c1.y < p0.y: # new segment is completely to the left # new path starts s0 = Path() if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g) w=%d" \ % (s0.id, c0.x, c0.y, winding + 1) s0.append(c0) curr_path.insert(s0) s1 = Path() s0.winding = winding + 1 s1.winding = winding if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g) w=%d" \ % (s1.id, c1.x, c1.y, winding) s1.append(c1) curr_path.insert(s1) curr_point.next() curr_point.next() s0.top_join = s1 s1.top_join = s0 elif c0.y > p1.y: # new segment is completely to the right # old path ends s0 = curr_path.takeNext() if DEBUG_POLYGONEXTRACTOR: print "end path %d" % s0.id self.all_path_list.append(s0) prev_point.next() s1 = curr_path.takeNext() if DEBUG_POLYGONEXTRACTOR: print "end path %d" % s1.id self.all_path_list.append(s1) prev_point.next() s0.bot_join = s1 s1.bot_join = s0 winding = s1.winding else: # new segment is overlapping left_path = curr_path.next() right_path = curr_path.peek() 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) 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) 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: print "%d(%g,%g,w=%d)" % (path.id, path.points[-1].x, path.points[-1].y, path.winding), print self.prev_line = scanline
def process_hor_scanline(self, scanline): if DEBUG_POLYGONEXTRACTOR: last = 0 inside = False s = "" for point in scanline: next_x = point.x if inside: s += "*" * int(next_x - last) else: s += " " * int(next_x - last) last = next_x inside = not inside print s if DEBUG_POLYGONEXTRACTOR: print "active paths: ", for path in self.curr_path_list: print "%d(%g,%g)" \ % (path.id, path.points[-1].x, path.points[-1].y), print print "prev points: ", for point in self.prev_line: print "(%g,%g)" % (point.x, point.y), print print "active points: ", for point in scanline: print "%d(%g,%g)" % (point.id, point.x, point.y), print prev_point = Iterator(self.prev_line) curr_point = Iterator(scanline) curr_path = Iterator(self.curr_path_list) winding = 0 while (prev_point.remains() > 0) or (curr_point.remains() > 0): if DEBUG_POLYGONEXTRACTOR: print "num_prev=%d, num_curr=%d" \ % (prev_point.remains(), curr_point.remains()) if (prev_point.remains() == 0) and (curr_point.remains() >= 2): c0 = curr_point.next() c1 = curr_point.next() # new path starts p0 = Path() p0.winding = winding + 1 if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g)" % (p0.id, c0.x, c0.y) p0.append(c0) self.curr_path_list.append(p0) p1 = Path() p1.winding = winding if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g)" % (p1.id, c1.x, c1.y) p1.append(c1) 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 if (prev_point.remains() >= 2) and (curr_point.remains() >= 2): p0 = prev_point.peek(0) p1 = prev_point.peek(1) c0 = curr_point.peek(0) c1 = curr_point.peek(1) if DEBUG_POLYGONEXTRACTOR: print "overlap test: p0=%g p1=%g" % (p0.x, p1.x) print "overlap test: c0=%g c1=%g" % (c0.x, c1.x) if c1.x < p0.x: # new segment is completely to the left # new path starts s0 = Path() if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g) w=%d" \ % (s0.id, c0.x, c0.y, winding + 1) s0.append(c0) curr_path.insert(s0) s1 = Path() s0.winding = winding + 1 s1.winding = winding if DEBUG_POLYGONEXTRACTOR: print "new path %d(%g,%g) w=%d" \ % (s1.id, c1.x, c1.y, winding) s1.append(c1) curr_path.insert(s1) curr_point.next() curr_point.next() s0.top_join = s1 s1.top_join = s0 elif c0.x > p1.x: # new segment is completely to the right # old path ends s0 = curr_path.takeNext() if DEBUG_POLYGONEXTRACTOR: print "end path %d" % s0.id self.all_path_list.append(s0) prev_point.next() s1 = curr_path.takeNext() if DEBUG_POLYGONEXTRACTOR: print "end path %d" % s1.id self.all_path_list.append(s1) prev_point.next() s0.bot_join = s1 s1.bot_join = s0 winding = s1.winding else: # new segment is overlapping left_path = curr_path.next() right_path = curr_path.peek() 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) print "join test: c0=%g c1=%g" % (c0.x, c1.x) if p2.x <= c1.x: 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) print "split test: c0=%g c1=%g c2=%g" \ % (c0.x, c1.x, c2.x) if c2.x <= p1.x: 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: print "%d(%g,%g,w=%d)" % (path.id, path.points[-1].x, path.points[-1].y, path.winding), 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][1] maxy = s.points[0][1] for p in s.points: if not p[0] == s.points[0][0]: allsame = False if p[1] < miny: miny = p[1] if p[1] > maxy: maxy = p[1] if allsame: if DEBUG_POLYGONEXTRACTOR2: print("all same !") s0 = Path() for p in s.points: if p[1] == miny: s0.append(p) hor_path_list.append(s0) s1 = Path() for p in s.points: if p[1] == maxy: s1.append(p) hor_path_list.append(s1) continue prev = s.points[-1] p_iter = CyclicIterator(s.points) p = s.points[0] next_p = next(p_iter) while not ((prev[0] >= p[0]) and (next_p[0] > p[0])): p = next_p next_p = next(p_iter) count = 0 while count < len(s.points): s0 = Path() while next_p[0] >= p[0]: s0.append(p) p = next_p next_p = next(p_iter) count += 1 s0.append(p) while (len(s0.points) > 1) \ and (s0.points[0][0] == s0.points[1][0]): s0.points = s0.points[1:] while (len(s0.points) > 1) \ and (s0.points[-2][0] == s0.points[-1][0]): s0.points = s0.points[0:-1] hor_path_list.append(s0) s1 = Path() while next_p[0] <= p[0]: s1.append(p) p = next_p next_p = next(p_iter) count += 1 s1.append(p) s1.reverse() while (len(s1.points) > 1) \ and (s1.points[0][0] == s1.points[1][0]): s1.points = s1.points[1:] while (len(s1.points) > 1) \ and (s1.points[-2][0] == s1.points[-1][0]): s1.points = s1.points[:-1] hor_path_list.append(s1) hor_path_list.sort(key=lambda p: p.points[0][0]) 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_ver_scanline(self, scanline): if DEBUG_POLYGONEXTRACTOR3: prev = None for p in scanline: if p.dir == 0: self.cont.fill("red") else: self.cont.fill("blue") self.cont.AddDot(p[0], p[1]) self.cont.fill("black") self.cont.AddText(p[0], p[1], str(p.id)) if prev: self.cont.AddLine(prev[0], prev[1], p[0], p[1]) prev = p if DEBUG_POLYGONEXTRACTOR: last = 0 inside = False s = "" for point in scanline: next_y = point[1] if inside: s += "*" * int(next_y - last) else: s += " " * int(next_y - last) last = next_y inside = not inside print(s) if DEBUG_POLYGONEXTRACTOR: print("active paths: "), for path in self.curr_path_list: print("%d(%g,%g)" % (path.id, path.points[-1][0], path.points[-1][1])), print() print("prev points: "), for point in self.prev_line: print("(%g,%g)" % (point[0], point[1])), print() print("active points: "), for point in scanline: print("%d(%g,%g)" % (point.id, point[0], point[1])), print() prev_point = Iterator(self.prev_line) curr_point = Iterator(scanline) curr_path = Iterator(self.curr_path_list) winding = 0 while (prev_point.remains() > 0) or (curr_point.remains() > 0): if DEBUG_POLYGONEXTRACTOR: print("num_prev=%d, num_curr=%d" % (prev_point.remains(), curr_point.remains())) if (prev_point.remains() == 0) and (curr_point.remains() >= 2): c0 = next(curr_point) c1 = next(curr_point) # new path starts p0 = Path() p0.winding = winding + 1 if DEBUG_POLYGONEXTRACTOR: print("new path %d(%g,%g)" % (p0.id, c0[0], c0[1])) p0.append(c0) self.curr_path_list.append(p0) p1 = Path() p1.winding = winding if DEBUG_POLYGONEXTRACTOR: print("new path %d(%g,%g)" % (p1.id, c1[0], c1[1])) p1.append(c1) 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) next(prev_point) p1 = curr_path.takeNext() if DEBUG_POLYGONEXTRACTOR: print("end path %d" % p1.id) self.all_path_list.append(p1) next(prev_point) p0.bot_join = p1 p1.bot_join = p0 continue if (prev_point.remains() >= 2) and (curr_point.remains() >= 2): p0 = prev_point.peek(0) p1 = prev_point.peek(1) c0 = curr_point.peek(0) c1 = curr_point.peek(1) if DEBUG_POLYGONEXTRACTOR: print("overlap test: p0=%g p1=%g" % (p0[0], p1[0])) print("overlap test: c0=%g c1=%g" % (c0[0], c1[0])) if c1[1] < p0[1]: # new segment is completely to the left # new path starts s0 = Path() if DEBUG_POLYGONEXTRACTOR: print("new path %d(%g,%g) w=%d" % (s0.id, c0[0], c0[1], winding + 1)) s0.append(c0) curr_path.insert(s0) s1 = Path() s0.winding = winding + 1 s1.winding = winding if DEBUG_POLYGONEXTRACTOR: print("new path %d(%g,%g) w=%d" % (s1.id, c1[0], c1[1], winding)) s1.append(c1) curr_path.insert(s1) next(curr_point) next(curr_point) s0.top_join = s1 s1.top_join = s0 elif c0[1] > p1[1]: # new segment is completely to the right # old path ends s0 = curr_path.takeNext() if DEBUG_POLYGONEXTRACTOR: print("end path %d" % s0.id) self.all_path_list.append(s0) next(prev_point) s1 = curr_path.takeNext() if DEBUG_POLYGONEXTRACTOR: print("end path %d" % s1.id) self.all_path_list.append(s1) next(prev_point) s0.bot_join = s1 s1.bot_join = s0 winding = s1.winding else: # new segment is overlapping left_path = next(curr_path) right_path = curr_path.peek() left_point = c0 right_point = c1 winding = left_path.winding next(curr_point) next(prev_point) 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[0], p1[0], p2[0])) print("join test: c0=%g c1=%g" % (c0[0], c1[0])) if p2[1] <= c1[1]: 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 = next(curr_path) left_path = s1 right_path = curr_path.peek() next(prev_point) next(prev_point) 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[0], p1[0])) print("split test: c0=%g c1=%g c2=%g" % (c0[0], c1[0], c2[0])) if c2[1] <= p1[1]: 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)) next(curr_point) c0 = next(curr_point) 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[0], left_point[1])) left_path.append(left_point) right_path.append(right_point) if right_path == curr_path.peek(): next(curr_path) if DEBUG_POLYGONEXTRACTOR: print("add to path %d(%g,%g)" % (right_path.id, right_point[0], right_point[1])) winding = right_path.winding next(prev_point) next(curr_point) if DEBUG_POLYGONEXTRACTOR: output = "active paths: " for path in self.curr_path_list: output += "%d(%g,%g,w=%d)" % (path.id, path.points[-1][0], path.points[-1][1], path.winding) print(output) self.prev_line = scanline