def _line_line_intersections(self, other): a = self.start b = self.end c = other.start d = other.end if c == d or a == b: return [] if isclose(b.x, a.x): x = a.x if isclose(d.x, c.x): return [ ] slope34 = ( d.y - c.y ) / ( d.x - c.x ) y = slope34 * (x - c.x ) + c.y p = Point(x,y) i = Intersection(self,self.tOfPoint(p), other, other.tOfPoint(p)) return [ i ] if isclose(d.x, c.x): x = c.x slope12 = ( b.y - a.y ) / ( b.x - a.x ) y = slope12 * ( x - a.x ) + a.y p = Point(x,y) i = Intersection(self,self.tOfPoint(p), other, other.tOfPoint(p)) return [ i ] slope12 = ( b.y - a.y) / ( b.x - a.x ) slope34 = ( d.y - c.y) / ( d.x - c.x ) if isclose(slope12, slope34): return [ ] x = ( slope12 * a.x - a.y - slope34 * c.x + c.y ) / ( slope12 - slope34 ) y = slope12 * ( x - a.x ) + a.y intersection = Point(x,y) if (self._bothPointsAreOnSameSideOfOrigin(intersection, b, a) and self._bothPointsAreOnSameSideOfOrigin(intersection, c, d)): return [ Intersection(self,self.tOfPoint(intersection), other, other.tOfPoint(intersection)) ] return []
def fromNodelist(cls, path, nodelist): self = SegmentRepresentation(path) # Find first oncurve firstOncurve = -1 for ix, n in enumerate(nodelist): if n.type != "offcurve": firstOncurve = ix break first = nodelist[firstOncurve] seg = [(first.x, first.y)] for n in nodelist[firstOncurve + 1:]: if n.type == "offcurve": seg.append((n.x, n.y)) if n.type == "line" or n.type == "curve": seg.append((n.x, n.y)) self.appendSegment(seg) seg = [(n.x, n.y)] for n in nodelist[:firstOncurve]: if n.type == "offcurve": seg.append((n.x, n.y)) if n.type == "line" or n.type == "curve": seg.append((n.x, n.y)) self.appendSegment(seg) seg = [(n.x, n.y)] # Closed? if self.path.closed: if len(seg) == 1 and isclose(seg[-1][0], first.x) and isclose( seg[-1][1], first.y): pass else: seg.append((first.x, first.y)) self.appendSegment(seg) return self
def fromNodelist(cls, path, nodelist): self = SegmentRepresentation(path) # Find first oncurve firstOncurve = -1 for ix, n in enumerate(nodelist): if n.type != "offcurve": firstOncurve = ix break first = nodelist[firstOncurve] seg = [(first.x,first.y)] for n in nodelist[firstOncurve+1:]: if n.type == "offcurve": seg.append((n.x,n.y)) if n.type == "line" or n.type == "curve": seg.append((n.x,n.y)) self.appendSegment(seg) seg = [(n.x,n.y)] for n in nodelist[:firstOncurve]: if n.type == "offcurve": seg.append((n.x,n.y)) if n.type == "line" or n.type == "curve": seg.append((n.x,n.y)) self.appendSegment(seg) seg = [(n.x,n.y)] # Closed? if self.path.closed: if len(seg) == 1 and isclose(seg[-1][0], first.x) and isclose(seg[-1][1], first.y): pass else: seg.append((first.x,first.y)) self.appendSegment(seg) return self
def findshifts(segs, splitline): """ Yields lines which are possible positions of splitline. This includes all maxima and minima on the segments list and also every 20 units. """ trans = splitline.alignmentTransformation() bounds = [] maxy = -1e6 miny = 1e6 for _s in segs: # rotate segment so dealing purely in y, the splitline is in effect horizontal s = _s.transformed(trans) # add segment ends or any maxima to the list of possible positions if len(s) == 2: bounds = _addBound(bounds, Bound(s[0].x, s[0].y, s[0].y > s[1].y, s.slope)) bounds = _addBound( bounds, Bound(s[1].x, s[1].y, s[1].y >= s[0].y, s.slope)) # collect overall segment list extrema in y maxy = max(maxy, s[0].y, s[1].y) miny = min(miny, s[0].y, s[1].y) elif len(s) == 3: d2 = s[0].y - 2 * s[1].y + s[2].y if not isclose(d2, 0.): rt = (s[0].y - s[1].y) / d2 if 0 <= rt <= 1.: p = s.pointAtTime(rt) bounds.append(Bound(p.x, p.y, d2 < 0., 0.)) maxy = max(maxy, s[0].y, s[2].y, p.y) miny = min(miny, s[0].y, s[2].y, p.y) continue bounds = _addBound( bounds, Bound(s[0].x, s[0].y, s[0].y > s[2].y, s.derivative()[0].slope)) bounds = _addBound( bounds, Bound(s[2].x, s[2].y, s[2].y >= s[0].y, s.derivative()[1].slope)) maxy = max(maxy, s[0].y, s[2].y) miny = min(miny, s[0].y, s[2].y) # create transform back from horizontal to original direction backt = AffineTransformation() backt.apply_backwards(trans) backt.invert() last = None # yield each of the calculated bounds as a splitline for b in sorted(bounds, key=lambda b: (b[1], b)): if last is not None and isclose(last, b[1]): continue res = splitline.transformed(trans) res[0].y += b.y res[1].y += b.y # yield res.transformed(backt) last = b[1] # Now yield every 20 em units as a splitline for y in range(int(miny), int(maxy), max(20, int((maxy - miny) * .05))): res = splitline.transformed(trans) res[0].y += y res[1].y += y yield res.transformed(backt)
def _same_bounds(b1, b2): """ Calculate if a point is 'inline' with a point we have already seen. If the point is close and the slopes are both in the same direction, then we say yes. The points must also be at opposite ends of the segment. """ if b1.max == b2.max: return False if isclose(b1.x, b2.x) and isclose(b1.y, b2.y): return b1.slope * b2.slope >= 0 return False
def _findRoots(self, dimension): if dimension == "x": t = self[0].x / (self[0].x - self[1].x) if not isclose(self[0].x, self[1].x) else 100. elif dimension == "y": t = self[0].y / (self[0].y - self[1].y) if not isclose(self[0].y, self[1].y) else 100. else: raise SyntaxError("Meh") if 0. <= t <= 1.: return [t] return []
def _findRoots(self, dimension): if dimension == "x": t = self[0].x / (self[0].x - self[1].x) if not isclose( self[0].x, self[1].x) else 100. elif dimension == "y": t = self[0].y / (self[0].y - self[1].y) if not isclose( self[0].y, self[1].y) else 100. else: raise SyntaxError("Meh") if 0. <= t <= 1.: return [t] return []
def tOfPoint(self, point, its_on_the_line_i_swear=False): """Returns the t (0->1) value of the given point, assuming it lies on the line, or -1 if it does not.""" # Just find one and hope the other fits # point = self.start * (1-t) + self.end * t if not isclose(self.end.x, self.start.x): t = (point.x - self.start.x) / (self.end.x - self.start.x) elif not isclose(self.end.y, self.start.y): t = (point.y - self.start.y) / (self.end.y - self.start.y) else: print("! Line %s is actually a point..." % self) return -1 if its_on_the_line_i_swear or self.pointAtTime(t).distanceFrom( point) < 2e-7: return t return -1
def _update_curve(self, s, attrib, fn): d2 = fn(s[0]) - 2 * fn(s[1]) + fn(s[2]) if isclose(d2, 0): return t = (fn(s[0]) - fn(s[1])) / d2 if 0 <= t <= 1: p = s.pointAtTime(t) if fn(p) < getattr(self, attrib + "i"): setattr(self, attrib + "i", fn(p)) if fn(p) > getattr(self, attrib + "a"): setattr(self, attrib + "a", fn(p))
def invert(self): m = self.matrix det = m[0][0] * (m[1][1]*m[2][2] - m[1][2]*m[2][1]) - \ m[0][1] * (m[1][0]*m[2][2] - m[1][2]*m[2][0]) + \ m[0][2] * (m[1][0]*m[2][1] - m[1][1]*m[2][0]) if isclose(det, 0.): return None adj = [[(m[1][1]*m[2][2] - m[2][1]*m[1][2])/det, (m[2][1]*m[0][2] - m[0][1]*m[2][2])/det, (m[0][1]*m[1][2] - m[1][1]*m[0][2])/det], [(m[1][2]*m[2][0] - m[1][0]*m[2][2])/det, (m[0][0]*m[2][2] - m[0][2]*m[2][0])/det, (m[0][2]*m[1][0] - m[0][0]*m[1][2])/det], [(m[1][0]*m[2][1] - m[1][1]*m[2][0])/det, (m[0][1]*m[2][0] - m[0][0]*m[2][1])/det, (m[0][0]*m[1][1] - m[0][1]*m[1][0])/det]] self.matrix = adj
def _line_line_intersections(self, other): a = self.start b = self.end c = other.start d = other.end if isclose(c.x, d.x) and isclose(a.x, b.x): return [] if isclose(c.y, d.y) and isclose(a.y, b.y): return [] if c == d or a == b: return [] if isclose(b.x,a.x): x = a.x slope34 = ( d.y - c.y) / ( d.x - c.x ) y = slope34 * ( x - c.x ) + c.y p = Point(x,y) i = Intersection(self,self.tOfPoint(p), other, other.tOfPoint(p)) return [ i ] if isclose(c.x,d.x): x = c.x slope12 = ( b.y - a.y) / ( b.x - a.x ) y = slope12 * ( x - a.x ) + a.y p = Point(x,y) i = Intersection(self,self.tOfPoint(p), other, other.tOfPoint(p)) return [ i ] slope12 = ( b.y - a.y) / ( b.x - a.x ) slope34 = ( d.y - c.y) / ( d.x - c.x ) if abs(slope12 - slope34) < my_epsilon: return [ ] x = ( slope12 * a.x - a.y - slope34 * c.x + c.y ) / ( slope12 - slope34 ) y = slope12 * ( x - a.x ) + a.y intersection = Point(x,y) if (self._bothPointsAreOnSameSideOfOrigin(intersection, b, a) and self._bothPointsAreOnSameSideOfOrigin(intersection, c, d)): return [ Intersection(self,self.tOfPoint(intersection), other, other.tOfPoint(intersection)) ] return []
def invert(self): m = self.matrix det = m[0][0] * (m[1][1]*m[2][2] - m[1][2]*m[2][1]) - \ m[0][1] * (m[1][0]*m[2][2] - m[1][2]*m[2][0]) + \ m[0][2] * (m[1][0]*m[2][1] - m[1][1]*m[2][0]) if isclose(det, 0.): return None adj = [[(m[1][1] * m[2][2] - m[2][1] * m[1][2]) / det, (m[2][1] * m[0][2] - m[0][1] * m[2][2]) / det, (m[0][1] * m[1][2] - m[1][1] * m[0][2]) / det], [(m[1][2] * m[2][0] - m[1][0] * m[2][2]) / det, (m[0][0] * m[2][2] - m[0][2] * m[2][0]) / det, (m[0][2] * m[1][0] - m[0][0] * m[1][2]) / det], [(m[1][0] * m[2][1] - m[1][1] * m[2][0]) / det, (m[0][1] * m[2][0] - m[0][0] * m[2][1]) / det, (m[0][0] * m[1][1] - m[0][1] * m[1][0]) / det]] self.matrix = adj