def sub_divide_cubic_path(sp, flat, i=1): """ Break up a bezier curve into smaller curves, each of which is approximately a straight line within a given tolerance (the "smoothness" defined by [flat]). This is a modified version of cspsubdiv.cspsubdiv(). I rewrote the recursive call because it caused recursion-depth errors on complicated line segments. """ while True: while True: if i >= len(sp): return p0 = sp[i - 1][1] p1 = sp[i - 1][2] p2 = sp[i][0] p3 = sp[i][1] b = (p0, p1, p2, p3) if bezier.maxdist(b) > flat: break i += 1 one, two = bezier.beziersplitatt(b, 0.5) sp[i - 1][2] = one[1] sp[i][0] = two[2] p = [one[2], one[3], two[1]] sp[i:1] = [p]
def linearize(p, tolerance=0.001): """ This function receives a component of a 'cubicsuperpath' and returns two things: The path subdivided in many straight segments, and an array containing the length of each segment. We could work with bezier path as well, but bezier arc lengths are (re)computed for each point in the deformed object. For complex paths, this might take a while. """ zero = 0.000001 i = 0 d = 0 lengths = [] while i < len(p) - 1: box = pointdistance(p[i][1], p[i][2]) box += pointdistance(p[i][2], p[i + 1][0]) box += pointdistance(p[i + 1][0], p[i + 1][1]) chord = pointdistance(p[i][1], p[i + 1][1]) if (box - chord) > tolerance: b1, b2 = beziersplitatt( [p[i][1], p[i][2], p[i + 1][0], p[i + 1][1]], 0.5) p[i][2][0], p[i][2][1] = b1[1] p[i + 1][0][0], p[i + 1][0][1] = b2[2] p.insert(i + 1, [[b1[2][0], b1[2][1]], [b1[3][0], b1[3][1]], [b2[1][0], b2[1][1]]]) else: d = (box + chord) / 2 lengths.append(d) i += 1 new = [p[i][1] for i in range(0, len(p) - 1) if lengths[i] > zero] new.append(p[-1][1]) lengths = [l for l in lengths if l > zero] return new, lengths
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 compatBezierSplitAtT(b, t): if isPython3(): return bezier.beziersplitatt(b, t) else: return beziersplitatt(b, t)
def effect(self): maxL = None separateSegs = self.options.separateSegs if (self.options.unit != 'perc' and self.options.unit != 'count'): maxL = self.options.maxLength * self.svg.unittouu( '1' + self.options.unit) # ~ inkex.errormsg(_(str(maxL))) tolerance = 10**(-1 * self.options.precision) selections = self.svg.selected pathNodes = self.document.xpath('//svg:path', namespaces=inkex.NSS) paths = [(pathNode.get('id'), CubicSuperPath(pathNode.get('d'))) for pathNode in pathNodes] if (len(paths) > 0): for key, cspath in paths: parts = getPartsFromCubicSuper(cspath) partsSplit = False for i, part in enumerate(parts): newSegs = [] for j, seg in enumerate(part): segL = bezier.bezierlength( (seg[0], seg[1], seg[2], seg[3]), tolerance=tolerance) if (maxL != None): divL = maxL elif (self.options.unit == 'perc'): divL = segL * self.options.maxLength / 100 else: divL = segL / ceil(self.options.maxLength) if (segL > divL): coveredL = 0 s = seg s1 = None s2 = DEF_ERR_MARGIN #Just in case while (not floatCmpWithMargin(segL, coveredL)): if (s == seg): sL = segL else: sL = bezier.bezierlength( (s[0], s[1], s[2], s[3]), tolerance=tolerance) if (floatCmpWithMargin(segL, coveredL + divL)): s2 = s break else: if (segL > (coveredL + divL)): t1L = divL else: t1L = segL - coveredL t1 = bezier.beziertatlength( (s[0], s[1], s[2], s[3]), l=t1L / sL, tolerance=tolerance) s1, s2 = bezier.beziersplitatt( (s[0], s[1], s[2], s[3]), t1) coveredL += t1L newSegs.append(s1) s = s2 newSegs.append(s2) else: newSegs.append(seg) if (len(newSegs) > len(part)): parts[i] = newSegs partsSplit = True if (partsSplit or separateSegs): elem = selections[key] if (separateSegs): parent = elem.getparent() idx = parent.index(elem) parent.remove(elem) allSegs = [seg for part in parts for seg in part] idSuffix = 0 for seg in allSegs: cspath = getCubicSuperFromParts([[seg]]) newElem = copy.copy(elem) oldId = newElem.get('id') newElem.set('d', CubicSuperPath(cspath)) newElem.set('id', oldId + str(idSuffix).zfill(5)) parent.insert(idx, newElem) idSuffix += 1 else: cspath = getCubicSuperFromParts(parts) elem.set('d', CubicSuperPath(cspath))
def splitAtT(seg, t): if (ver == 1.0): return bezier.beziersplitatt((seg[0], seg[1], seg[2], seg[3]), t) else: return bezmisc.beziersplitatt((seg[0], seg[1], seg[2], seg[3]), t)