def createSVG(filename, tool, points): # Generate the paths allPoints = list() paths = list() t = Template(PATH_TEMPLATE) for point in points: allPoints.extend(point) path = Path() lx, ly = point[0] pc = 0 for p in point[1:]: l = mkLine(lx, ly, p[0], p[1]) if l is not None: path.append(l) pc = pc + 1 lx = p[0] ly = p[1] path.closed = True paths.append(t.safe_substitute({ 'strokeWidth': tool, 'path': path.d() })) print "Generated path with %d points." % pc # Build the final output v = { 'xmin': min([ x for x, y in allPoints ]) - (tool / 2), 'ymin': min([ y for x, y in allPoints ]) - (tool / 2), 'xmax': max([ x for x, y in allPoints ]) + (tool / 2), 'ymax': max([ y for x, y in allPoints ]) + (tool / 2) } v['width'] = abs(v['xmax'] - v['xmin']) v['height'] = abs(v['ymax'] - v['ymin']) v['path'] = "\n".join(paths) out = Template(SVG_TEMPLATE).substitute(v).strip() # And write the file with open(filename, "w") as svg: svg.write(out)
def parse_polygon(points: str) -> Path: coordinates = [tuple(map(float, c.split(','))) for c in points.split()] path = Path() for a, b in pairwise(coordinates): path.append(Line(complex(*a), complex(*b))) return path
def remove_redundant_lines(self): lines_bucketed_by_slope_intersect = defaultdict(list) paths = self.svg_node.getElementsByTagName('path') overall_index = 0 for path_index, path in enumerate(paths): path_text = path.attributes['d'].value path_obj = parse_path(path_text) for line_index, line in enumerate(path_obj): slope, intersect = _get_slope_intersect(line.start, line.end) # TODO: float inaccuracy and rounding may cause collinear lines to end up in separate buckets in rare # cases, so this is not quite correct. Would be better to put lines into *2* nearest buckets in each # dimension to avoid edge cases. if slope is not None: slope = round(slope, ndigits=3) intersect = round(intersect, ndigits=3) lines_bucketed_by_slope_intersect[(slope, intersect)].append({ 'overall_index': overall_index, 'path_index': path_index, 'line_index': line_index, 'line': line, }) overall_index += 1 to_remove = {} to_update = {} for slope_intersect, lines in lines_bucketed_by_slope_intersect.items(): for i in range(20): if SvgProcessor._pairwise_overlap_check(lines, to_update, to_remove): print 'Re-running pairwise overlap check because of updated/merged line' continue break else: raise Exception( 'Exceeded the max number of pairwise overlap check passes. Something is probably wrong.' ) # Reconstruct the paths, but excluding/updating the lines we just identified i = 0 removed = 0 removed_length = 0 kept = 0 kept_length = 0 for path_index, path in enumerate(paths): path_text = path.attributes['d'].value path_obj = parse_path(path_text) filtered_path = Path() for line_index, line in enumerate(path_obj): if i in to_remove: assert path_index == to_remove[i][0] assert line_index == to_remove[i][1] removed += 1 removed_length += line.length() elif i in to_update: assert path_index == to_update[i][0] assert line_index == to_update[i][1] replacement_line = to_update[i][2] filtered_path.append(replacement_line) kept += 1 kept_length += replacement_line.length() else: filtered_path.append(line) kept += 1 kept_length += line.length() i += 1 # Update the path data with the filtered path data path.attributes['d'] = filtered_path.d() print 'Removed {} lines ({} length) and kept {} lines ({} length)'.format( removed, removed_length, kept, kept_length, ) return [to_remove[k][2] for k in to_remove], [to_update[k][2] for k in to_update]
SVG2 = ''' </g> </svg> ''' svgpath1 = '''<path style="fill:none;fill-rule:evenodd;stroke:#{0:02x}{1:02x}{2:02x};stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="''' svgpath2 = ''' Z"/> ''' print(SVG1) for p in paths: path = parse_path(p.attrib["d"]) start = None myrange = list(frange(0, 1, decimal.Decimal('0.01'))) mycolors = list(red.range_to(blue, len(myrange))) for i, px in enumerate(myrange): new_path = Path() if start is None: start = path.point(float(px)) else: end = path.point(float(px)) new_path.append(Line(start, end)) start = end color = mycolors[i] r = int(color.red * 255) g = int(color.green * 255) b = int(color.blue * 255) print((svgpath1 + new_path.d() + svgpath2).format(clamp(r), clamp(g), clamp(b))) print(SVG2)
''' svgpath1 = '''<path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="''' svgpath2 = ''' Z"/> ''' print(SVG1) for p in paths: new_path = Path() path = parse_path(p.attrib["d"]) start = None for command in path: if type(command) == Line: new_path.append(command) start = command.end ##print(command) else: not_line_path = Path(command) for px in list(frange(0, 1, decimal.Decimal(factor))): if start is None: start = not_line_path.point(float(px)) else: end = not_line_path.point(float(px)) new_command = Line(start, end) new_path.append(new_command) ##print(new_command) start = end new_path_str = new_path.d()