def applyDiffeo(self,bpt,vects=()): ''' The kernel of this stuff: bpt is a base point and for v in vectors, v'=v-p is a tangent vector at bpt. ''' s=bpt[0]-self.skelcomp[0][0] i,t=self.lengthtotime(s) if i==len(self.skelcomp)-1: x,y=bezmisc.tpoint(self.skelcomp[i-1],self.skelcomp[i],1+t) dx=(self.skelcomp[i][0]-self.skelcomp[i-1][0])/self.lengths[-1] dy=(self.skelcomp[i][1]-self.skelcomp[i-1][1])/self.lengths[-1] else: x,y=bezmisc.tpoint(self.skelcomp[i],self.skelcomp[i+1],t) dx=(self.skelcomp[i+1][0]-self.skelcomp[i][0])/self.lengths[i] dy=(self.skelcomp[i+1][1]-self.skelcomp[i][1])/self.lengths[i] vx=0 vy=bpt[1]-self.skelcomp[0][1] if self.options.wave: bpt[0]=x+vx*dx bpt[1]=y+vy+vx*dy else: bpt[0]=x+vx*dx-vy*dy bpt[1]=y+vx*dy+vy*dx for v in vects: vx=v[0]-self.skelcomp[0][0]-s vy=v[1]-self.skelcomp[0][1] if self.options.wave: v[0]=x+vx*dx v[1]=y+vy+vx*dy else: v[0]=x+vx*dx-vy*dy v[1]=y+vx*dy+vy*dx
def applyDiffeo(self, bpt, vects=()): ''' The kernel of this stuff: bpt is a base point and for v in vectors, v'=v-p is a tangent vector at bpt. ''' s = bpt[0] - self.skelcomp[0][0] i, t = self.lengthtotime(s) if i == len( self.skelcomp ) - 1: #je regarde si je suis au debut du skelete car sinon j'ai pas de vecteur x, y = bezmisc.tpoint(self.skelcomp[i - 1], self.skelcomp[i], 1 + t) dx = (self.skelcomp[i][0] - self.skelcomp[i - 1][0]) / self.lengths[-1] dy = (self.skelcomp[i][1] - self.skelcomp[i - 1][1]) / self.lengths[-1] else: x, y = bezmisc.tpoint(self.skelcomp[i], self.skelcomp[i + 1], t) dx = (self.skelcomp[i + 1][0] - self.skelcomp[i][0]) / self.lengths[i] dy = (self.skelcomp[i + 1][1] - self.skelcomp[i][1]) / self.lengths[i] vx = 0 vy = bpt[1] - self.skelcomp[0][1] bpt[0] = x + vx * dx - vy * dy bpt[1] = y + vx * dy + vy * dx for v in vects: vx = v[0] - self.skelcomp[0][0] - s vy = v[1] - self.skelcomp[0][1] v[0] = x + vx * dx - vy * dy v[1] = y + vx * dy + vy * dx
def localTransformAt(self,s,follow=True): ''' receives a length, and returns the coresponding point and tangent of self.skelcomp if follow is set to false, returns only the translation ''' i,t=self.lengthtotime(s) if i==len(self.skelcomp)-1: x,y=bezmisc.tpoint(self.skelcomp[i-1],self.skelcomp[i],1+t) dx=(self.skelcomp[i][0]-self.skelcomp[i-1][0])/self.lengths[-1] dy=(self.skelcomp[i][1]-self.skelcomp[i-1][1])/self.lengths[-1] else: x,y=bezmisc.tpoint(self.skelcomp[i],self.skelcomp[i+1],t) dx=(self.skelcomp[i+1][0]-self.skelcomp[i][0])/self.lengths[i] dy=(self.skelcomp[i+1][1]-self.skelcomp[i][1])/self.lengths[i] if follow: mat=[[dx,-dy,x],[dy,dx,y]] else: mat=[[1,0,x],[0,1,y]] return mat
def localTransformAt(self, s, follow=True): ''' recieves a length, and returns the coresponding point and tangent of self.skelcomp if follow is set to false, returns only the translation ''' i, t = self.lengthtotime(s) if i == len(self.skelcomp) - 1: x, y = bezmisc.tpoint(self.skelcomp[i - 1], self.skelcomp[i], 1 + t) dx = (self.skelcomp[i][0] - self.skelcomp[i - 1][0]) / self.lengths[-1] dy = (self.skelcomp[i][1] - self.skelcomp[i - 1][1]) / self.lengths[-1] else: x, y = bezmisc.tpoint(self.skelcomp[i], self.skelcomp[i + 1], t) dx = (self.skelcomp[i + 1][0] - self.skelcomp[i][0]) / self.lengths[i] dy = (self.skelcomp[i + 1][1] - self.skelcomp[i][1]) / self.lengths[i] if follow: mat = [[dx, -dy, x], [dy, dx, y]] else: mat = [[1, 0, x], [0, 1, y]] return mat
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
#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 # end point, probably dont need hpgl.insert(i, '%s%d,%d' % (next[0], end[0], end[1]))
#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 # end point, probably dont need hpgl.insert(i,'%s%d,%d'%(next[0],end[0],end[1]))