def getIntersectionPathFromBox(infLine, left, right, top, bottom): # Intersect the line with all the sides of the box and # take the two points inside the box. # This will always be on the top and bottom # or on the left and right sides. p1 = complex(left, infLine.y_for_x(left)) p2 = complex(right, infLine.y_for_x(right)) l1 = Line(start=p1, end=p2) p3 = complex(infLine.x_for_y(top), top) p4 = complex(infLine.x_for_y(bottom), bottom) l2 = Line(start=p3, end=p4) if l1.length() < l2.length(): return l2 else: return l1
sp_10A_11 = pathtosvg(pf_10A_11) seg_10A_11 = parse_path(sp_10A_11) t = seg_10A_11.ilength(4.0 * cm) pt10B = pt("10B", pt10A[0] - abs(pt10A[0] - np.real(seg_10A_11.point(t)) / cm), (np.imag(seg_10A_11.point(t)) / cm)) #t = seg_10A_11.ilength(1.0*cm) #pt10C = pt("10C", np.real(seg.point(t))/cm, np.imag(seg.point(t))/cm) path1 = svgwrite.path.Path('%s' % sp_10A_11, fill="none", stroke=col_sew) # (pt2ph(pt10B), # only curve 0.25, not 0.5 hipline_curve = 0.2 # not 0.5 seg_11_8 = Line(complex(pt11[0] * cm, pt11[1] * cm), complex(pt8[0] * cm, pt8[1] * cm)) seg_length = seg_11_8.length() t_mid = seg_11_8.ilength(seg_length / 2) geo_mid = seg_11_8.point(t_mid) n = seg_11_8.normal(t_mid) normal_line = Line(seg_11_8.point(t_mid), seg_11_8.point(t_mid) + hipline_curve * cm * n) ctrl_pt = (np.real(normal_line.point(1)), np.imag(normal_line.point(1))) ctrl_pt_str = str(np.real(normal_line.point(1))) + ", " + str( np.imag(normal_line.point(1))) p_11_8 = (pt2cm(pt11), ctrl_pt, pt2cm(pt8)) pf_11_8 = fitpath(p_11_8, 10e-1) sp_11_8 = pathtosvg(pf_11_8).replace('M', 'L')[17:] path1.push('%s' % sp_11_8) # curve # path1.push('L %s' % (pt2ph(pt8))) # curve
def scan_lines(paths, current_y=None): bbox = overall_bbox(paths) lines = [] fudge_factor = 0.01 orientation = abs(bbox[3]-bbox[2]) > abs(bbox[1]-bbox[0]) if not current_y: current_y = bbox[2] if orientation else bbox[0] max_pos = bbox[3] if orientation else bbox[1] debug_shapes = [[paths, "none", "gray"]] while current_y < max_pos: current_y += MINIMUM_STITCH_DISTANCE if orientation: left = min(bbox[0], bbox[1]) right = max(bbox[0], bbox[1]) if left < 0: left *= 1.0 + fudge_factor else: left *= 1.0 - fudge_factor if right < 0: right *= 1.0 - fudge_factor else: right *= 1.0 + fudge_factor test_line = Line(start=current_y*1j+left, end=current_y*1j+right) else: up = min(bbox[2], bbox[3]) down = max(bbox[2], bbox[3]) if up < 0: up *= 1.0 + fudge_factor else: up *= 1.0 - fudge_factor if down < 0: down *= 1.0 - fudge_factor else: down *= 1.0 + fudge_factor test_line = Line(start=current_y + up*1j, end=current_y + down *1j) squash_intersections = [] for path in paths: if path.start == path.end: continue intersections = path.intersect(test_line) if len(intersections) > 0: squash_intersections += [test_line.point(p[1]) for p in intersections] if len(squash_intersections) == 0: continue intersections = sorted(squash_intersections, key=lambda x: abs(x-test_line.start)) if len(squash_intersections) < 2: continue debug_shapes.append([test_line, "none", "black"]) for i in range(0, 2*int(len(intersections)/2), 2): def format_center(ind): return (intersections[ind].real, intersections[ind].imag) debug_shapes.append([Circle(center=format_center(i), r=1, fill="red")]) debug_shapes.append([Circle(center=format_center(i+1), r=1, fill="blue")]) line = Line(start=intersections[i], end=intersections[i+1]) debug_shapes.append([line, "none", "green"]) if line.length() > MAXIMUM_STITCH: num_segments = ceil(line.length() / MAXIMUM_STITCH) for seg_i in range(int(num_segments)): lines.append(Line(start=line.point(seg_i/num_segments), end=line.point((seg_i+1)/num_segments))) else: lines.append(line) write_debug("fillscan", debug_shapes) return lines
def fill_polygon(self, paths): rotated = 0 fudge_factor = 0.03 while len(paths) > 2: if len(paths) < 4: self.fill_triangle(paths, color="red") return shapes = [[Path(*paths), "none", "blue"], [Path(*paths), "none", "green"]] write_debug("close", shapes) paths = remove_close_paths(paths) if len(paths) <= 2: return # check whether the next triangle is concave test_line1 = Line(start=paths[0].start, end=paths[1].end) test_line1 = Line(start=test_line1.point(fudge_factor), end=test_line1.point(1 - fudge_factor)) comparison_path = Path(*paths) if test_line1.length() == 0: has_intersection = True else: has_intersection = len([ 1 for line in paths if len(line.intersect(test_line1)) > 0 ]) > 0 if not path1_is_contained_in_path2( test_line1, comparison_path) or has_intersection: shapes = [[comparison_path, "none", "blue"], [test_line1, "none", "black"]] write_debug("anim", shapes) # rotate the paths paths = paths[1:] + [paths[0]] rotated += 1 if rotated >= len(paths): print("failed to rotate into a concave path -> ", (test_line1.start.real, test_line1.start.imag), (test_line1.end.real, test_line1.end.imag), [(p.start.real, p.start.imag) for p in paths]) return continue side = shorter_side(paths) test_line2 = Line(start=paths[1].start, end=paths[2].end) test_line2 = Line(start=test_line2.point(fudge_factor), end=test_line2.point(1 - fudge_factor)) test_line3 = Line(start=paths[-1 + side].end, end=paths[(3 + side) % len(paths)].start) test_line3 = Line(start=test_line3.point(fudge_factor), end=test_line3.point(1 - fudge_factor)) num_intersections = [] for path in comparison_path: if test_line3.length() == 0: print("test line 3 is degenerate!") num_intersections += test_line3.intersect(path) num_intersections += test_line2.intersect(path) rect_not_concave = not path1_is_contained_in_path2( test_line2, comparison_path) # test for concavity. If concave, fill as triangle if is_concave( paths) or len(num_intersections) > 0 or rect_not_concave: self.fill_triangle(paths, color="blue") shapes = [[Path(*paths), "none", "black"]] to_remove = [] to_remove.append(paths.pop(0)) to_remove.append(paths.pop(0)) for shape in to_remove: shapes.append([shape, "none", "blue"]) closing_line = Line(start=paths[-1].end, end=paths[0].start) shapes.append([closing_line, "none", "green"]) shapes.append([test_line1, "none", "red"]) write_debug("rem", shapes) else: # check whether the next triangle is concave side, side2 = self.fill_trap(paths) if side: paths = paths[1:] + [paths[0]] shapes = [[Path(*paths), "none", "black"]] to_remove = [] to_remove.append(paths.pop(0)) to_remove.append(paths.pop(0)) to_remove.append(paths.pop(0)) # if the trap was stitched in the vertical (perpendicular to the # stitches), don't remove that segment linecolors = ["blue", "purple", "pink"] for i, shape in enumerate(to_remove): shapes.append([shape, "none", linecolors[i]]) closing_line = Line(start=paths[-1].end, end=paths[0].start) shapes.append([closing_line, "none", "green"]) shapes.append([test_line2, "none", "purple"]) write_debug("rem", shapes) delta = closing_line.length() - (test_line3.length() / (1.0 - 2.0 * fudge_factor)) if abs(delta) > 1e-14: print("closing line different than test!", side, test_line3, closing_line) rotated = 0 if paths[-1].end != paths[0].start: # check for intersections closing_line = Line(start=paths[-1].end, end=paths[0].start) paths.insert(0, closing_line) else: print("removed paths but they connected anyway")