def load(self, node, trans): a = node.get('style').split(";") d = dict(s.split(':') for s in a) if d['stroke'] == "#ff0000": self.cut_style = 2 elif d['stroke'] == "#0000ff": self.cut_style = 3 else: pass d = node.get('d') p = Path(d) if len(p) == 0: return p = CubicSuperPath(p) p = p.transform(trans) # p is now a list of lists of cubic beziers [ctrl p1, ctrl p2, endpoint] # where the start-point is the last point in the previous segment self.segments = [] for sp in p: points = [] sub_divide_cubic_path(sp, 0.2) # TODO: smoothness preference for csp in sp: points.append((csp[1][0], csp[1][1])) self.segments.append(points)
def test_path_TepidQuadratic(self): path = Path("M 10 5 Q 15 30 25 15 T 50 40") pe = PathElement() pe.path = path ibb = (10, 50), (5, 40) self.assert_bounding_box_is_equal(pe, *ibb)
def get_points(el): if el.typename == 'Line': pts = [Vector2d(el.get('x1'),el.get('y1')),\ Vector2d(el.get('x2'),el.get('y2'))] elif el.typename == 'PathElement': pth = Path(el.get_path()) pts = list(pth.control_points) elif el.typename == 'Rectangle': x = float(el.get('x')) y = float(el.get('y')) w = float(el.get('width')) h = float(el.get('height')) pts = [ Vector2d(x, y), Vector2d(x + w, y), Vector2d(x + w, y + h), Vector2d(x, y + h), Vector2d(x, y) ] ct = el.composed_transform() xs = [] ys = [] for p in pts: p = ct.apply_to_point(p) xs.append(p.x) ys.append(p.y) return xs, ys
def scaleCubicSuper(self, cspath, scaleFactor, scaleFrom): bbox = Path(cspath).bounding_box() if (scaleFrom == 'topLeft'): oldOrigin = [bbox.left, bbox.bottom] elif (scaleFrom == 'topRight'): oldOrigin = [bbox.right, bbox.bottom] elif (scaleFrom == 'bottomLeft'): oldOrigin = [bbox.left, bbox.top] elif (scaleFrom == 'bottomRight'): oldOrigin = [bbox.right, bbox.top] else: #if(scaleFrom == 'center'): oldOrigin = [ bbox.left + (bbox.right - bbox.left) / 2., bbox.bottom + (bbox.top - bbox.bottom) / 2. ] newOrigin = [oldOrigin[0] * scaleFactor, oldOrigin[1] * scaleFactor] for subpath in cspath: for bezierPt in subpath: for i in range(0, len(bezierPt)): bezierPt[i] = [ bezierPt[i][0] * scaleFactor, bezierPt[i][1] * scaleFactor ] bezierPt[i][0] += (oldOrigin[0] - newOrigin[0]) bezierPt[i][1] += (oldOrigin[1] - newOrigin[1])
def test_path_combined_1(self): path = Path("M 0 0 C 11 14 33 3 85 98 H 84 V 91 L 13 78 C 26 83 65 24 94 77") # path = Path("M 0 0 C 11 14 33 3 85 98") pe = PathElement() pe.path = path ibb = self.get_inkscape_bounding_box(pe) self.assert_bounding_box_is_equal(pe, *ibb, disable_inkscape_check=True)
def load(self, node, trans): new_path = self.new_path_from_node(node) x1 = float(node.get('x1')) y1 = float(node.get('y1')) x2 = float(node.get('x2')) y2 = float(node.get('y2')) a = [['M', [x1, y1]], ['L', [x2, y2]]] new_path.set('d', str(Path(a))) SvgPath.load(self, new_path, trans)
def load(self, node, trans): new_path = self.new_path_from_node(node) x = float(node.get('x')) y = float(node.get('y')) w = float(node.get('width')) h = float(node.get('height')) a = [['M', [x, y]], ['l', [w, 0]], ['l', [0, h]], ['l', [-w, 0]], ['Z', []]] new_path.set('d', str(Path(a))) SvgPath.load(self, new_path, trans)
def path(self): # A polyline is a series of connected line segments described by their # points. In order to make use of the existing logic for incorporating # svg transforms that is in our superclass, we'll convert the polyline # to a degenerate cubic superpath in which the bezier handles are on # the segment endpoints. path = self.node.get_path() path = Path(path).to_superpath() return path
def effect(self): starttime = time.time() sel = self.svg.selection # an ElementList # inkex.utils.debug(sel) els = [sel[k] for k in sel.id_dict().keys()] poptext = self.options.poptext poprest = self.options.poprest removerectw = self.options.removerectw removerectb = self.options.removerectb gpe = sel.get() els = [gpe[k] for k in gpe.id_dict().keys()] gs = [el for el in els if el.typename == 'Group'] os = [el for el in els if not (el.typename == 'Group')] # inkex.utils.debug(self.svg.get_selected_bbox().width) # dh.ungroup(gs[0]); if poprest: for g in list(reversed(gs)): dh.ungroup(g) for el in list(reversed(os)): if el.typename == 'TextElement' and poptext: dh.split_distant(el) dh.pop_tspans(el) if removerectb or removerectw: for el in os: isrect = False if el.typename == 'Rectangle': isrect = True elif el.typename == 'PathElement': pth = Path(el.get_path()) pts = list(pth.control_points) xs = [p.x for p in pts] ys = [p.y for p in pts] if len(pts) == 5 and len(set(xs)) == 2 and len( set(ys)) == 2: isrect = True # if path has 2 unique x, 2 unique y, and exactly 5 pts # inkex.utils.debug(el.get_id()+el.typename+str(isrect)) if isrect: sty = el.composed_style() fill = sty.get('fill') strk = sty.get('stroke') if (removerectw and fill in ['#ffffff','white'] and strk in [None,'none'])\ or (removerectb and fill in ['#000000','black'] and strk in [None,'none']): el.delete()
def test_random_path_1(self): import random from inkex.paths import Line, Vert, Horz, Curve, Move, Arc, Quadratic, TepidQuadratic, Smooth, ZoneClose klasses = (Line, Vert, Horz, Curve, Move, Quadratic) # , ZoneClose, Arc def random_segment(klass): args = [random.randint(1, 100) for _ in range(klass.nargs)] if klass is Arc: args[2] = 0 # random.randint(0, 1) args[3] = 0 # random.randint(0, 1) args[4] = 0 # random.randint(0, 1) return klass(*args) random.seed(2128506) # random.seed(datetime.now()) n_trials = 10 n_elements = 15 for i in range(n_trials): path = Path() path.append(Move(0, 0)) for j in range(n_elements): k = random.choice(klasses) path.append(random_segment(k)) if k is Curve: while random.randint(0, 1) == 1: path.append(random_segment(Smooth)) if k is Quadratic: while random.randint(0, 1) == 1: path.append(random_segment(TepidQuadratic)) pe = PathElement() pe.path = path ibb = self.get_inkscape_bounding_box(pe) self.assert_bounding_box_is_equal(pe, *ibb, disable_inkscape_check=True)
def test_path_TepidQuadratic_2(self): path = Path("M 10 5 Q 15 30 25 15 T 50 40 T 15 20") pe = PathElement() pe.path = path ibb = (10, 10 + 43.462), (5, 56) self.assert_bounding_box_is_equal(pe, *ibb)
def test_path_Arc_long_sweep_on_axis_x_25(self): path = Path("M 10 20 A 10 20 25 1 1 20 15") path_element = PathElement() path_element.path = path self.assert_bounding_box_is_equal(path_element, (4.723, 4.723 + 24.786), (-17.149, -17.149 + 37.149))
def test_path_Arc_short_sweep_on(self): path = Path("M 10 20 A 10 20 0 0 1 20 15") path_element = PathElement() path_element.path = path self.assert_bounding_box_is_equal(path_element, (10, 20), (14.127, 14.127 + 5.873))
def test_path_Arc_long_sweep_off(self): path = Path("M 10 20 A 10 20 0 1 0 20 15") path_element = PathElement() path_element.path = path self.assert_bounding_box_is_equal(path_element, (7.078, 20 + 7.078), (15.0, 15.0 + 39.127))
def test_path_vert(self): path = Path("M 15 30 v 20") pe = PathElement() pe.path = path self.assert_bounding_box_is_equal(pe, (15, 15), (30, 50))
def test_path_Curve(self): path = Path("M10 10 C 20 20, 40 20, 50 10") pe = PathElement() pe.path = path self.assert_bounding_box_is_equal(pe, (10, 50), (10, 17.5))
def test_path_Zone(self): path = Path("M 15 30 Z") pe = PathElement() pe.path = path self.assert_bounding_box_is_equal(pe, (15, 15), (30, 30))
def test_path_horz(self): path = Path("M 15 30 h 20") pe = PathElement() pe.path = path self.assert_bounding_box_is_equal(pe, (15, 35), (30, 30))
def test_path_line(self): path = Path("M 15 30 l 10 20") pe = PathElement() pe.path = path self.assert_bounding_box_is_equal(pe, (15, 25), (30, 50))
def test_path_Line(self): path = Path("M 15 30 L 10 20") pe = PathElement() pe.path = path self.assert_bounding_box_is_equal(pe, (10, 15),( 20, 30))
def test_path_Move(self): path = Path("M 10 20") pe = PathElement() pe.path = path self.assert_bounding_box_is_equal(pe, (10, 10),( 20, 20))
def path_to_bline_list(path_d, nodetypes=None, mtx=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): """ Convert a path to a BLine List bline_list format: Vertex: [[tg1x, tg1y], [x,y], [tg2x, tg2y], split = T/F] Vertex list: [ vertex, vertex, vertex, ...] Bline: { "points" : vertex_list, "loop" : True / False } """ # Exit on empty paths if not path_d: return [] # Parse the path path = Path(path_d).to_arrays() # Append (more than) enough c's to the nodetypes if nodetypes is None: nt = "" else: nt = nodetypes for _ in range(len(path)): nt += "c" # Create bline list # borrows code from cubicsuperpath.py # bline_list := [bline, bline, ...] # bline := { # "points":[vertex, vertex, ...], # "loop":True/False, # } bline_list = [] subpathstart = [] last = [] lastctrl = [] lastsplit = True for s in path: cmd, params = s if cmd != "M" and bline_list == []: raise MalformedSVGError( "Bad path data: path doesn't start with moveto, {}, {}".format( s, path)) elif cmd == "M": # Add previous point to subpath if last: bline_list[-1]["points"].append( [lastctrl[:], last[:], last[:], lastsplit]) # Start a new subpath bline_list.append({"nodetypes": "", "loop": False, "points": []}) # Save coordinates of this point subpathstart = params[:] last = params[:] lastctrl = params[:] lastsplit = False if nt[0] == "z" else True nt = nt[1:] elif cmd in "LHV": bline_list[-1]["points"].append( [lastctrl[:], last[:], last[:], lastsplit]) if cmd == 'H': last = [params[0], last[1]] lastctrl = [params[0], last[1]] elif cmd == 'V': last = [last[0], params[0]] lastctrl = [last[0], params[0]] else: last = params[:] lastctrl = params[:] lastsplit = False if nt[0] == "z" else True nt = nt[1:] elif cmd == 'C': bline_list[-1]["points"].append( [lastctrl[:], last[:], params[:2], lastsplit]) last = params[-2:] lastctrl = params[2:4] lastsplit = False if nt[0] == "z" else True nt = nt[1:] elif cmd == 'Q': q0 = last[:] q1 = params[0:2] q2 = params[2:4] x0 = q0[0] x1 = 1. / 3 * q0[0] + 2. / 3 * q1[0] x2 = 2. / 3 * q1[0] + 1. / 3 * q2[0] x3 = q2[0] y0 = q0[1] y1 = 1. / 3 * q0[1] + 2. / 3 * q1[1] y2 = 2. / 3 * q1[1] + 1. / 3 * q2[1] y3 = q2[1] bline_list[-1]["points"].append( [lastctrl[:], [x0, y0], [x1, y1], lastsplit]) last = [x3, y3] lastctrl = [x2, y2] lastsplit = False if nt[0] == "z" else True nt = nt[1:] elif cmd == 'A': from inkex.paths import arc_to_path arcp = arc_to_path(last[:], params[:]) arcp[0][0] = lastctrl[:] last = arcp[-1][1] lastctrl = arcp[-1][0] lastsplit = False if nt[0] == "z" else True nt = nt[1:] for el in arcp[:-1]: el.append(True) bline_list[-1]["points"].append(el) elif cmd == "Z": if len(bline_list[-1]["points"]) == 0: # If the path "loops" after only one point # e.g. "M 0 0 Z" bline_list[-1]["points"].append( [lastctrl[:], last[:], last[:], False]) elif last == subpathstart: # If we are back to the original position # merge our tangent into the first point bline_list[-1]["points"][0][0] = lastctrl[:] else: # Otherwise draw a line to the starting point bline_list[-1]["points"].append( [lastctrl[:], last[:], last[:], lastsplit]) # Clear the variables (no more points need to be added) last = [] lastctrl = [] lastsplit = True # Loop the subpath bline_list[-1]["loop"] = True # Append final superpoint, if needed if last: bline_list[-1]["points"].append( [lastctrl[:], last[:], last[:], lastsplit]) # Apply the transformation if mtx != [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]: for bline in bline_list: for vertex in bline["points"]: for point in vertex: if not isinstance(point, bool): pnt = Transform(mtx).apply_to_point(point) point[0], point[1] = pnt[0], pnt[1] return bline_list
def test_path_Arc_long_sweep_on(self): path = Path("M 10 20 A 10 20 0 1 1 20 15") path_element = PathElement() path_element.path = path self.assert_bounding_box_is_equal(path_element, (2.922, 2.922 + 20), (-19.127, -19.127 + 39.127))