def test_equals(self): """Segments should be equalitive""" self.assertEqual(Move(10, 10), Move(10, 10)) self.assertEqual(Line(10, 10), Line(10, 10)) self.assertEqual(line(10, 10), line(10, 10)) self.assertNotEqual(line(10, 10), Line(10, 10)) self.assertEqual(Horz(10), Line(10, 0)) self.assertEqual(Vert(10), Line(0, 10)) self.assertNotEqual(Vert(10), Horz(10))
def test_to_curves(self): """Segments can become curves""" self.assertRaises(ValueError, Move(0, 0).to_curve, None) self.assertEqual( Line(10, 10).to_curve(Vector2d(10, 5)), (10, 5, 10, 10, 10, 10)) self.assertEqual( Horz(10).to_curve(Vector2d(10, 5)), (10, 5, 10, 5, 10, 5)) self.assertEqual( Vert(10).to_curve(Vector2d(5, 10)), (5, 10, 5, 10, 5, 10)) self.assertEqual( Curve(5, 5, 10, 10, 4, 4).to_curve(Vector2d(0, 0)), (5, 5, 10, 10, 4, 4)) self.assertEqual( Smooth(10, 10, 4, 4).to_curve(Vector2d(4, 4), Vector2d(10, 10)), (-2, -2, 10, 10, 4, 4), ) self.assertAlmostTuple( Quadratic(10, 10, 4, 4).to_curve(Vector2d(0, 0)).args, (6.666666666666666, 6.666666666666666, 8, 8, 4, 4), ) self.assertAlmostTuple( TepidQuadratic(4, 4).to_curve(Vector2d(14, 19), Vector2d(11, 12)).args, # (20.666666666666664, 30, 17.333333333333332, 25, 4, 4), (15.999999999999998, 23.666666666666664, 12.666666666666666, 18.666666666666664, 4, 4), ) curves = list(Arc(50, 50, 0, 0, 1, 85, 85).to_curves(Vector2d(0, 0))) self.assertEqual(len(curves), 3) self.assertAlmostTuple( curves[0].args, (19.77590700610636, -5.4865851247611115, 38.18634924829132, -10.4196482558544, 55.44095225512604, -5.796291314453416)) self.assertAlmostTuple( curves[1].args, (72.69555526196076, -1.172934373052433, 86.17293437305243, 12.30444473803924, 90.79629131445341, 29.559047744873958)) self.assertAlmostTuple( curves[2].args, (95.41964825585441, 46.81365075170867, 90.4865851247611, 65.22409299389365, 77.85533905932738, 77.85533905932738)) def apply_to_curve(obj): obj.to_curve(Vector2d()) def apply_to_curves(obj): obj.to_curve(Vector2d()) self.assertRaises(ValueError, apply_to_curve, ZoneClose()) self.assertRaises(ValueError, apply_to_curves, zoneClose()) self.assertRaises(ValueError, apply_to_curve, Move(0, 0)) self.assertRaises(ValueError, apply_to_curves, move(0, 0))
def draw_line(x1, y1, x2, y2, width, name, parent): elem = parent.add(inkex.PathElement()) elem.style = { 'stroke': '#000000', 'stroke-width': str(width), 'fill': 'none' } elem.set('inkscape:label', name) elem.path = [Move(x1, y1), Line(x2, y2)]
def effect(self): for node in self.svg.selection.filter(inkex.PathElement): path = node.path.to_absolute() result = [] for cmd_proxy in path.proxy_iterator( ): # type: inkex.Path.PathCommandProxy prev = cmd_proxy.previous_end_point end = cmd_proxy.end_point if cmd_proxy.letter == 'M': result.append(Move(*cmd_proxy.args)) else: for seg in self.fractalize((prev.x, prev.y, end.x, end.y), self.options.subdivs, self.options.smooth): result.append(Line(*seg)) result.append(Line(end.x, end.y)) node.path = result
def plot_beam(beam: List[Tuple[Ray, float]], node: inkex.ShapeElement) -> None: path = inkex.Path() if len(beam) > 0: path += [Move(beam[0][0].origin[0], beam[0][0].origin[1])] for ray, t in beam: p1 = ray.origin + t * ray.direction path += [Line(p1[0], p1[1])] element = node.getparent().add(inkex.PathElement()) element.style = node.get("style") element.path = path.transform(-node.composed_transform())
def plot_beam(self, beam: List[Ray], node: inkex.ShapeElement) -> None: path = inkex.Path() if len(beam) > 0: path += [Move(beam[0].origin[0], beam[0].origin[1])] for ray in beam: p1 = ray.origin + ray.travel * ray.direction path += [Line(p1[0], p1[1])] element = self._beam_layer.add(inkex.PathElement()) # Need to convert to path to get the correct style for inkex.Use element.style = node.to_path_element().style element.path = path
def plot_beam(self, beam: List[Tuple[Ray, float]], node: inkex.ShapeElement) -> None: path = inkex.Path() if len(beam) > 0: path += [Move(beam[0][0].origin[0], beam[0][0].origin[1])] for ray, t in beam: p1 = ray.origin + t * ray.direction path += [Line(p1[0], p1[1])] svg = self.document.getroot() element = svg.add(inkex.PathElement()) element.style = node.get("style") element.path = path
def effect(self): for node in self.svg.selection.filter(inkex.PathElement): result = Path() prev = Vector2d() start = None for seg in node.path.to_absolute(): if start is None: start = seg.end_point(start, prev) if isinstance(seg, Curve): result += [ Move(seg.x2, seg.y2), Line(prev.x, prev.y), Move(seg.x3, seg.y3), Line(seg.x4, seg.y4), ] elif isinstance(seg, Quadratic): result += [ Move(seg.x2, seg.y2), Line(prev.x, prev.y), Move(seg.x2, seg.y2), Line(seg.x3, seg.y3) ] prev = seg.end_point(start, prev) if not result: continue elem = node.getparent().add(inkex.PathElement()) elem.path = result.transform(node.transform) elem.style = { 'stroke-linejoin': 'miter', 'stroke-width': '1.0px', 'stroke-opacity': '1.0', 'fill-opacity': '1.0', 'stroke': '#000000', 'stroke-linecap': 'butt', 'fill': 'none' }
def to_meshdata(subpath): """Convert csp subpath to corners, edge path data.""" if len(subpath) >= 5: corners = [] edges = [] for i, corner in enumerate(subpath[:4]): corners.append(corner[1]) edge = [list(subpath[i]), list(subpath[i+1])] edge[0][0] = list(edge[0][1]) edge[1][2] = list(edge[1][1]) if inkex.CubicSuperPath.is_line(edge[0], edge[1]): edges.append(Line(*edge[1][1])) else: edges.append(Curve(*(edge[0][2] + edge[1][0] + edge[1][1]))) return corners, edges
def draw_poly(pts, face, st, name, parent): """Draw polygone""" style = {'stroke': '#000000', 'stroke-width': str(st.th), 'stroke-linejoin': st.linejoin, 'stroke-opacity': st.s_opac, 'fill': st.fill, 'fill-opacity': st.f_opac} path = inkex.Path() for facet in face: if not path: # for first point path.append(Move(pts[facet - 1][0], -pts[facet - 1][1])) else: path.append(Line(pts[facet - 1][0], -pts[facet - 1][1])) path.close() poly = parent.add(inkex.PathElement()) poly.label = name poly.style = style poly.path = path
def process_segment(cmd_proxy, facegroup, delx, dely): """Process each segments""" segments = [] if isinstance(cmd_proxy.command, (Curve, Smooth, TepidQuadratic, Quadratic, Arc)): prev = cmd_proxy.previous_end_point for curve in cmd_proxy.to_curves(): bez = [prev] + curve.to_bez() prev = curve.end_point(cmd_proxy.first_point, prev) tees = [ t for t in beziertatslope(bez, (dely, delx)) if 0 < t < 1 ] tees.sort() if len(tees) == 1: one, two = beziersplitatt(bez, tees[0]) segments.append(Curve(*(one[1] + one[2] + one[3]))) segments.append(Curve(*(two[1] + two[2] + two[3]))) elif len(tees) == 2: one, two = beziersplitatt(bez, tees[0]) two, three = beziersplitatt(two, tees[1]) segments.append(Curve(*(one[1] + one[2] + one[3]))) segments.append(Curve(*(two[1] + two[2] + two[3]))) segments.append(Curve(*(three[1] + three[2] + three[3]))) else: segments.append(curve) elif isinstance(cmd_proxy.command, (Line, Curve)): segments.append(cmd_proxy.command) elif isinstance(cmd_proxy.command, ZoneClose): segments.append( Line(cmd_proxy.first_point.x, cmd_proxy.first_point.y)) elif isinstance(cmd_proxy.command, (Vert, Horz)): segments.append(cmd_proxy.command.to_line(cmd_proxy.end_point)) for seg in Path([Move(*cmd_proxy.previous_end_point)] + segments).proxy_iterator(): if isinstance(seg.command, Move): continue Motion.makeface(seg.previous_end_point, seg.command, facegroup, delx, dely)
def makeface(last, segment, facegroup, delx, dely): """translate path segment along vector""" elem = facegroup.add(inkex.PathElement()) npt = segment.translate([delx, dely]) # reverse direction of path segment if isinstance(segment, Curve): rev = Curve(npt.x3, npt.y3, npt.x2, npt.y2, last[0] + delx, last[1] + dely) elif isinstance(segment, Line): rev = Line(last[0] + delx, last[1] + dely) else: raise RuntimeError("Unexpected segment type {}".format( type(segment))) elem.path = inkex.Path([ Move(last[0], last[1]), segment, npt.to_line(Vector2d()), rev, ZoneClose(), ])
def test_new_path(self): """Test new path element""" path = PathElement.new(path=[Move(10, 10), Line(20, 20)]) self.assertEqual(path.get('d'), 'M 10 10 L 20 20')
def effect(self): path_num = 0 elems = [] npaths = [] sstr = None for selem in self.svg.selection.filter(PathElement): elems.append(copy.deepcopy(selem)) if len(elems) == 0: raise inkex.AbortExtension("Nothing selected") for elem in elems: escale = 1.0 npaths.clear() #inkex.utils.debug(elem.attrib) if 'style' in elem.attrib: sstr = elem.attrib['style'] if 'transform' in elem.attrib: transforms = elem.attrib['transform'].split() for tf in transforms: if tf.startswith('scale'): escale = float(tf.split('(')[1].split(')')[0]) if sstr != None: lsstr = sstr.split(';') for stoken in range(len(lsstr)): if lsstr[stoken].startswith('stroke-width'): swt = lsstr[stoken].split(':')[1] if not swt[2:].isalpha( ): # is value expressed in units (e.g. px)? swf = str(float(swt) * escale) # no. scale it lsstr[stoken] = lsstr[stoken].replace(swt, swf) if lsstr[stoken].startswith('stroke-miterlimit'): swt = lsstr[stoken].split(':')[1] if not swt[2:].isalpha( ): # is value expressed in units (e.g. px)? swf = str(float(swt) * escale) # no. scale it lsstr[stoken] = lsstr[stoken].replace(swt, swf) sstr = ";".join(lsstr) else: sstr = None elem.apply_transform() xbound, ybound = elem.bounding_box() # Get bounds of this element xmin, xmax = xbound ymin, ymax = ybound ntotal = len(elem.path) nodecnt = 0 startx = 0 starty = ymax + 10 * escale endx = 0 endy = starty xoffset = 0 orig_sx = 0 orig_sy = 0 orig_ex = 0 orig_ey = 0 sx1 = 0 sy1 = 0 orig_length = 0 prev = Vector2d() for ptoken in elem.path.to_absolute( ): # For each point in the path startx = xmin + xoffset if ptoken.letter == 'M': # Starting a new line orig_sx = ptoken.x orig_sy = ptoken.y cd = Path() cd.append(Move(startx, starty)) sx1 = orig_sx sy1 = orig_sy else: if last_letter != 'M': orig_sx = orig_ex orig_sy = orig_ey if ptoken.letter == 'L': orig_ex = ptoken.x orig_ey = ptoken.y orig_length = math.sqrt((orig_sx - orig_ex)**2 + (orig_sy - orig_ey)**2) endx = startx + orig_length cd.append(Line(endx, endy)) elif ptoken.letter == 'H': orig_ey = ptoken.to_line(prev).y orig_length = abs(orig_sx - ptoken.x) orig_ex = ptoken.x endx = startx + orig_length cd.append(Line(endx, endy)) elif ptoken.letter == 'V': orig_ex = ptoken.to_line(prev).x orig_length = abs(orig_sy - ptoken.y) orig_ey = ptoken.y endx = startx + orig_length cd.append(Line(endx, endy)) elif ptoken.letter == 'Z': orig_ex = sx1 orig_ey = sy1 orig_length = math.sqrt((orig_sx - orig_ex)**2 + (orig_sy - orig_ey)**2) endx = startx + orig_length cd.append(Line(endx, endy)) elif ptoken.letter == 'C': bez = ptoken.to_bez() # [[x0,y0][x1,y1][x2,y2][x3,y3]] bez.insert(0, [prev.x, prev.y]) orig_ex = bez[3][0] #x3 orig_ey = bez[3][1] #y3 orig_length = inkex.bezier.bezierlength(bez) endx = startx + orig_length cd.append(Line(endx, endy)) else: raise inkex.AbortExtension( "Unknown letter - {0}".format(ptoken.letter)) nodecnt = nodecnt + 1 if ptoken.letter != 'M': if nodecnt == ntotal: self.drawline(str(cd), "hline{0}".format(path_num), self.svg.get_current_layer(), sstr) path_num = path_num + 1 xoffset = xoffset + orig_length prev.x = orig_ex prev.y = orig_ey else: prev.x = orig_sx prev.y = orig_sy last_letter = ptoken.letter
def test_to_line(self): self.assertEqual(Vert(3).to_line(Vector2d(5, 11)), Line(5, 3)) self.assertEqual(Horz(3).to_line(Vector2d(5, 11)), Line(3, 11)) self.assertEqual(vert(3).to_line(Vector2d(5, 11)), Line(5, 14)) self.assertEqual(horz(3).to_line(Vector2d(5, 11)), Line(8, 11))