def getVerticalLinearizedSkeletonPath(comps1, comps2, offs, isLine): path = [] lengths = [] if isLine: for pt1 in comps1: pt2 = getPtsByY(pt1, comps2, False) midPt = getMidPoint(pt1, pt2) if offs > 0: dist = bezmisc.pointdistance(pt1, pt2) path.append(getPtOnSeg(pt1, pt2, dist, offs * dist)) else: path.append(midPt) if len(path) > 1: lengths.append(bezmisc.pointdistance(path[-2], path[-1])) else: pt1 = comps1[0] pt2 = comps2[0] firstPt = getMidPoint(pt1, pt2) path.append(firstPt) lastPt = [firstPt[0], comps1[-1][1]] path.append(lastPt) lengths.append(bezmisc.pointdistance(path[-2], path[-1])) return (path, lengths)
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 = bezmisc.pointdistance(p[i ][1],p[i ][2]) box += bezmisc.pointdistance(p[i ][2],p[i+1][0]) box += bezmisc.pointdistance(p[i+1][0],p[i+1][1]) chord = bezmisc.pointdistance(p[i][1], p[i+1][1]) if (box - chord) > tolerance: b1, b2 = bezmisc.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 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 = bezmisc.pointdistance(p[i][1], p[i][2]) box += bezmisc.pointdistance(p[i][2], p[i + 1][0]) box += bezmisc.pointdistance(p[i + 1][0], p[i + 1][1]) chord = bezmisc.pointdistance(p[i][1], p[i + 1][1]) if (box - chord) > tolerance: b1, b2 = bezmisc.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 pickCorrespPt(cntr, p, pts): tmpPts = [] for pt in pts: if (p[0] >= cntr[0] and p[1] >= cntr[1]): if (pt[0] >= cntr[0] and pt[1] >= cntr[1]): tmpPts.append(pt) elif (p[0] <= cntr[0] and p[1] <= cntr[1]): if (pt[0] <= cntr[0] and pt[1] <= cntr[1]): tmpPts.append(pt) elif (p[0] < cntr[0] and p[1] > cntr[1]): if (pt[0] <= cntr[0] and pt[1] >= cntr[1]): tmpPts.append(pt) else: if (pt[0] >= cntr[0] and pt[1] <= cntr[1]): tmpPts.append(pt) cntPts = len(tmpPts) resPt = tmpPts[0] if cntPts > 1: shortestDist = bezmisc.pointdistance(p, tmpPts[0]) shortI = 0 for i in range(1, cntPts): tmpDist = bezmisc.pointdistance(p, tmpPts[i]) if tmpDist < shortestDist: shortestDist = tmpDist shortI = i resPt = tmpPts[shortI] return resPt
def getClosedLinearizedSkeletonPath(comps1, comps2, offs, isLine): path = [] lengths = [] centroid = getPolygonCentroid(comps1) if isLine: for pt2 in comps2: pt1 = getIntersectionPt(centroid, pt2, comps1) midPt = getMidPoint(pt1, pt2) if offs > 0: dist = bezmisc.pointdistance(pt1, pt2) path.append(getPtOnSeg(pt1, pt2, dist, offs * dist)) else: path.append(midPt) if len(path) > 1: lengths.append(bezmisc.pointdistance(path[-2], path[-1])) else: pt1 = comps1[0] pt2 = getIntersectionPt(centroid, pt1, comps2) midPt = getMidPoint(pt1, pt2) rx = bezmisc.pointdistance(centroid, midPt) svgPath = getCirclePath(midPt, rx) path, lengths = linearize(modifySkeletonPath(cubicsuperpath.parsePath(svgPath))) return (path, lengths)
def applyToAdjacent(self, point): while point != None: p = (point[0], point[1]) next = None for item in self.candidates: if bezmisc.pointdistance(p, (item['s'][0], item['s'][1])) < self.options.tolerance: self.applyStyle(item) next = item['e'] break elif bezmisc.pointdistance(p, (item['e'][0], item['e'][1])) < self.options.tolerance: self.applyStyle(item) next = item['s'] break point = next
def applyToAdjacent(self, point): while point != None: p = (point[0], point[1]) next = None for item in self.candidates: if bezmisc.pointdistance( p, (item['s'][0], item['s'][1])) < self.options.tolerance: self.applyStyle(item) next = item['e'] break elif bezmisc.pointdistance( p, (item['e'][0], item['e'][1])) < self.options.tolerance: self.applyStyle(item) next = item['s'] break point = next
def linearizePath(self, skelPath, offs): comps, lengths = linearize(skelPath) self.skelCompIsClosed = isSkeletonClosed(comps) if (self.skelCompIsClosed and offs != 0): centroid = getPolygonCentroid(comps) for i in range(len(comps)): pt1 = comps[i] dist = bezmisc.pointdistance(centroid, pt1) comps[i] = getPtOnSeg(centroid, pt1, dist, dist + offs) if i > 0: lengths[i - 1] = bezmisc.pointdistance(comps[i - 1], comps[i]) return (comps, lengths)
def getPathLength(self): # close enough... poly = self.toPolyline() i = 1 d = 0 while i < len(poly): last = poly[i - 1][1] cur = poly[i][1] d += bezmisc.pointdistance(last, cur) i += 1 return d
def getPathLength(self): # close enough... poly = self.toPolyline() i = 1 d = 0 while i < len(poly): last = poly[i-1][1] cur = poly[i][1] d += bezmisc.pointdistance(last,cur) i+=1 return d
def computeOffsets( self, usedistance=False, distance=50.0, distbetween='centers'): #as distances from 0.0, 'centers bboxes' retval = [] centers = self.centers retval.append(0.0) for i in xrange(len(centers) - 1): retval.append((bezmisc.pointdistance( (centers[i + 1][1], centers[i + 1][2]), (centers[i][1], centers[i][2])) + retval[-1])) return retval
def distances(points): """Calculate the distances for a list of points :param points: iterable of float pairs :return: list of distance """ if not points: return [0] lastpt = points[0] dists = [] for pt in points[1:]: dists.append(bezmisc.pointdistance(lastpt, pt)) lastpt = pt return dists
def getPtsByY(pt, comps, isClosed): res = [] for i in range(1, len(comps)): if ((comps[i - 1][1] <= pt[1] and pt[1] <= comps[i][1]) or (comps[i - 1][1] >= pt[1] and pt[1] >= comps[i][1])): if comps[i - 1][1] == comps[i][1]: d1 = bezmisc.pointdistance(pt, comps[i - 1]) d2 = bezmisc.pointdistance(pt, comps[i]) if d1 < d2: res.append(comps[i - 1]) else: res.append(comps[i]) elif comps[i - 1][0] == comps[i][0]: res.append([comps[i - 1][0], pt[1]]) else: res.append(getPoint(comps[i - 1], comps[i], None, pt[1])) if not isClosed: return res[0] return res
def getDistBetweenFirstPts(comps1, comps2, bbox1, bbox2, nest): pt1 = comps1[0] pt2 = None if (bbox1[0] == bbox2[0] and bbox1[1] == bbox2[1]): pt2 = getPtsByX(pt1, comps2, False) elif (bbox1[2] == bbox2[2] and bbox1[3] == bbox2[3]): pt2 = getPtsByY(pt1, comps2, False) elif nest: centroid = getPolygonCentroid(comps1) pt2 = getIntersectionPt(centroid, pt1, comps2) dist = bezmisc.pointdistance(pt1, pt2) return dist
def applyOvercut(self, poly): # good old polyline overcut... d = self.overcut if self.closed and d > 0: # find overcut point d away from start, todo, don't use polylines, see setOvecut commented... i = 1 # skip move to last = poly[0][1][:] # start position while d > 0: cur = poly[i][1][:] cmd = poly[i][0] # get distance to next point dist = bezmisc.pointdistance(last, cur) # check distance if d < dist: # last point t = d / dist poly.append(['L', list(bezmisc.tpoint(last, cur, t))]) else: poly.append([cmd, cur]) # update last last = cur d -= dist i += 1 return poly
def applyOvercut(self,poly): # good old polyline overcut... d = self.overcut if self.closed and d > 0: # find overcut point d away from start, todo, don't use polylines, see setOvecut commented... i = 1 # skip move to last = poly[0][1][:] # start position while d > 0: cur = poly[i][1][:] cmd = poly[i][0] # get distance to next point dist = bezmisc.pointdistance(last,cur) # check distance if d<dist: # last point t = d/dist poly.append(['L',list(bezmisc.tpoint(last,cur,t))]) else: poly.append([cmd,cur]) # update last last = cur d -= dist i +=1 return poly
class Path: # a single path def __init__(self, basicpath, settings={}): default = { 'overcut': 0, 'offset': 0, 'smoothness': .1 * units['mm'], # 1 um 'scale': 1016 / units['in'] } default.update(settings) for k, v in default.iteritems(): setattr(self, k, v) self.data = basicpath self.closed = self.isClosed() #self.smoothness = .1 self.bbox = self.boundingBox() #self.length = self.getPathLength() #self.position = (self.bbox[0],self.bbox[2]) #self.scale = 11.288888889 # --------------------------path adjustments -------------------------- def translatePath(self, x, y): simplepath.translatePath(self.data, x, y) def rotatePath(self, a, x=0, y=0): simplepath.rotatePath(self.data, a, x, y) def scalePath(self, x, y): simplepath.scalePath(self.data, x, y) # --------------------------path properties -------------------------- def boundingBox(self): csp = cubicsuperpath.CubicSuperPath(self.data) self.bbox = list(simpletransform.roughBBox(csp)) return list(simpletransform.roughBBox(csp)) # [minx,maxx,miny,maxy] def getPathLength(self): # close enough... poly = self.toPolyline() i = 1 d = 0 while i < len(poly): last = poly[i - 1][1] cur = poly[i][1] d += bezmisc.pointdistance(last, cur) i += 1 return d def isClosed(self): try: return self.closed except: ans = self.data[-1][0] == "Z" self.closed = ans return ans # --------------------------path settings -------------------------- def setSmoothness(self, s): self.smoothness = s def setScale(self, s): self.scale = s def setBladeOffset(self, d): self.offset = d def setOvercut(self, d): self.overcut = d if self.closed and d > 0: # replace z with the start point """ pprint(self.data) endp = self.data.pop() if endp[0]=='Z': endp = ['L',self.data[0][1]] self.data.append(endp) """ # below does not work, beziersplitatt does not give the correct bezier.... """ if self.closed and d > 0: # replace z with the start point self.data.pop() endp = ['L',self.data[0][1]] self.data.append(endp) # find overcut point d away from start, todo, don't use polylines i = 1 last = self.data[0][1][:] # start position while d > 0: cur = self.data[i][1][:] cmd = self.data[i][0] # get distance to next point if cmd=='L': dist = bezmisc.pointdistance(last,cur) elif cmd=='C': curve = ((cur[0],cur[1]),(cur[2],cur[3]),(cur[4],cur[5]),last) dist = bezmisc.bezierlength(curve) # check distance if d<dist: # last point t = d/dist if cmd=='L': self.data.append(['L',list(bezmisc.tpoint(last,cur,t))]) elif cmd=='C': curve = ((cur[0],cur[1]),(cur[2],cur[3]),(cur[4],cur[5]),last) first,second = bezmisc.beziersplitatt(curve,t) self.data.append(['C',[first[0][0],first[0][1],first[1][0],first[1][1],first[2][0],first[2][1]]]) else: self.data.append([cmd,cur]) # update last if cmd=='L': last = cur elif cmd=='C': last = [cur[4],cur[5]] d -= dist i +=1 """ #--------------------------apply path changes -------------------------- def applyOvercut(self, poly): # good old polyline overcut... d = self.overcut if self.closed and d > 0: # find overcut point d away from start, todo, don't use polylines, see setOvecut commented... i = 1 # skip move to last = poly[0][1][:] # start position while d > 0: cur = poly[i][1][:] cmd = poly[i][0] # get distance to next point dist = bezmisc.pointdistance(last, cur) # check distance if d < dist: # last point t = d / dist poly.append(['L', list(bezmisc.tpoint(last, cur, t))]) else: poly.append([cmd, cur]) # update last last = cur d -= dist i += 1 return poly def applyOffset(self, poly): # adjust for blade offset #todo, this haha d = abs(self.offset) def angleBetween(axis, p0, p1): def dotP(p0, p1): p = 0 for a1, a2 in zip(p0, p1): p += a1 * a2 return p def norm(p0): n = 0 for a in p0: n += a * a return math.sqrt(n) p0 = [p0[0] - axis[0], p0[1] - axis[1]] p1 = [p1[0] - axis[0], p1[1] - axis[1]] assert norm(p0) > 0 and norm(p1) > 0, "invalid points" r = dotP(p0, p1) / (norm(p0) * norm(p1)) if -1 <= r <= 1: return math.acos(r) else: return math.pi def arcto(radius, theta, (x, y), p0): poly = [] arc = ['A', [radius, radius, theta, 0, 0, x, y]] d = simplepath.formatPath([['M', p0], arc]) p = cubicsuperpath.parsePath(d) cspsubdiv.cspsubdiv(p, self.smoothness) for sp in p: first = True for csp in sp: if first: first = False else: for subpath in csp: poly.append(['L', list(subpath)]) return poly def curveto(p0, curve, flat): poly = [] d = simplepath.formatPath([['M', p0], curve]) p = cubicsuperpath.parsePath(d) cspsubdiv.cspsubdiv(p, flat) for sp in p: first = True for csp in sp: if first: first = False else: for subpath in csp: poly.append(['L', list(subpath)]) return poly if d <= 0: return poly # start position last = poly[0][1][:] cur = poly[1][1][:] i = 2 while i < len(poly): next = poly[i][1][:] # skip double points if not last == cur and not cur == next: # where are doubles coming from? # get the angle between the two vectors using cur as origin theta = angleBetween(cur, last, next) if theta < math.pi / 1.1: # go past by offset amount dist = bezmisc.pointdistance(last, cur) t1 = d / dist + 1 start = bezmisc.tpoint(last, cur, t1) # come back to next line dist = bezmisc.pointdistance(cur, next) t2 = (4 * d) / dist finish = bezmisc.tpoint(cur, next, t2) if t2 <= 1: # add cur point poly.insert(i - 1, ['L', list(start)]) i += 1 poly[i - 1] = ['L', list(finish)] #else: # inkex.debug("failed on %i with points %s,%s and %s"%(i,last,cur,next)) # shift to next point last = cur[:] cur = next[:] i += 1 return poly
return hpgl #poly = hpgl.parse(hpgl) last = ['PU', [0, 0]] # start position cur = [hpgl[0][:2], map(int, hpgl[0][2:].split(','))] i = 1 while i < len(hpgl): cmd = hpgl[i][:2] point = map(int, hpgl[i][2:].split(',')) next = [cmd, point] if not last[1] == cur[1] and not cur[1] == next[1]: theta = angleBetween(cur[1], last[1], next[1]) if theta < math.pi / 1.1: # start point dist = bezmisc.pointdistance(last[1], cur[1]) t = d / dist + 1 start = bezmisc.tpoint(last[1], cur[1], t) # end point dist = bezmisc.pointdistance(cur[1], next[1]) t = (4 * d) / dist end = bezmisc.tpoint(cur[1], next[1], t) if t <= 1: # go distance d past actual point hpgl[i - 1] = '%s%d,%d' % (cur[0], start[0], start[1]) # curve to end point #for pt in arcto(d,0,end,start): # hpgl.insert(i,'%s%d,%d'%(cur[0],pt[0],pt[1])) # i+=1
def stretchComps(skelComps, patComps, comps1, comps2, bbox1, bbox2, nest, halfHeight, ampl, offs): res = [] if nest: newPt = None centroid = getPolygonCentroid(comps1) for pt in patComps: skelPt = getIntersectionPt(centroid, pt, skelComps) pt1 = getIntersectionPt(centroid, pt, comps1) pt2 = getIntersectionPt(centroid, pt, comps2) midPt = getMidPoint(pt1, pt2) dist1 = bezmisc.pointdistance(skelPt, pt) dist2 = bezmisc.pointdistance(midPt, pt1) * ampl dist3 = dist2 * dist1 / halfHeight if (skelPt[0] >= centroid[0] and skelPt[1] >= centroid[1]): if (pt[0] >= skelPt[0] and pt[1] >= skelPt[1]): newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) else: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) elif (skelPt[0] <= centroid[0] and skelPt[1] <= centroid[1]): if (pt[0] <= skelPt[0] and pt[1] <= skelPt[1]): newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) else: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) elif (skelPt[0] < centroid[0] and skelPt[1] > centroid[1]): if (pt[0] <= skelPt[0] and pt[1] >= skelPt[1]): newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) else: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) else: if (pt[0] >= skelPt[0] and pt[1] <= skelPt[1]): newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) else: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) res.append(newPt) elif (bbox1[0] == bbox2[0] and bbox1[1] == bbox2[1]): midY = skelComps[0][1] newPt = None if (patComps[-1][0] != comps1[-1][0] and round(patComps[-1][0], 10) == comps1[-1][0]): patComps[-1][0] = comps1[-1][0] for pt in patComps: pt1 = getPtsByX(pt, comps1, False) pt2 = getPtsByX(pt, comps2, False) midPt = getMidPoint(pt1, pt2) dist1 = abs(pt[1] - midY) dist2 = bezmisc.pointdistance(midPt, pt1) * ampl dist3 = dist2 * dist1 / halfHeight if bbox1[0] < bbox1[1]: if pt[1] > midY: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) else: newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) else: if pt[1] < midY: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) else: newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) res.append(newPt) elif (bbox1[2] == bbox2[2] and bbox1[3] == bbox2[3]): midX = skelComps[0][0] newPt = None if (patComps[-1][1] != comps1[-1][1] and round(patComps[-1][1], 10) == comps1[-1][1]): patComps[-1][1] = comps1[-1][1] for pt in patComps: pt1 = getPtsByY(pt, comps1, False) pt2 = getPtsByY(pt, comps2, False) midPt = getMidPoint(pt1, pt2) dist1 = abs(pt[0] - midX) dist2 = bezmisc.pointdistance(midPt, pt1) * ampl dist3 = dist2 * dist1 / halfHeight if bbox1[2] < bbox1[3]: if pt[0] < midX: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) else: newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) else: if pt[1] > midX: newPt = getPtOnSeg(midPt, pt1, bezmisc.pointdistance(midPt, pt1), dist3 - offs) else: newPt = getPtOnSeg(midPt, pt2, bezmisc.pointdistance(midPt, pt2), dist3 + offs) res.append(newPt) return res
return hpgl #poly = hpgl.parse(hpgl) last = ['PU',[0,0]] # start position cur = [hpgl[0][:2],map(int,hpgl[0][2:].split(','))] i = 1 while i < len(hpgl): cmd = hpgl[i][:2] point = map(int,hpgl[i][2:].split(',')) next = [cmd,point] if not last[1] == cur[1] and not cur[1] == next[1]: theta = angleBetween(cur[1],last[1],next[1]) if theta < math.pi/1.1: # start point dist = bezmisc.pointdistance(last[1],cur[1]) t = d/dist+1 start = bezmisc.tpoint(last[1],cur[1],t) # end point dist = bezmisc.pointdistance(cur[1],next[1]) t = (4*d)/dist end = bezmisc.tpoint(cur[1],next[1],t) if t<=1: # go distance d past actual point hpgl[i-1]='%s%d,%d'%(cur[0],start[0],start[1]) # curve to end point #for pt in arcto(d,0,end,start): # hpgl.insert(i,'%s%d,%d'%(cur[0],pt[0],pt[1])) # i+=1