def test_scale(self): p = Point(4, 5) m = AffineTransformation.scaling(2) p.transform(m) self.assertEqual(p.x, 8) self.assertEqual(p.y, 10) p = Point(4, 5) m = AffineTransformation.scaling(1.5, -2) p.transform(m) self.assertEqual(p.x, 6) self.assertEqual(p.y, -10)
def test_translate(self): p = Point(30, 70) p.rotate(Point(0, 0), math.pi / 4) self.assertEqual(p.x, -28.284271247461906) self.assertEqual(p.y, 70.71067811865476) p = Point(30, 70) m = AffineTransformation.rotation(math.pi / 4) p.transform(m) self.assertAlmostEqual(p.x, -28.284271247461906) self.assertAlmostEqual(p.y, 70.71067811865476) p = Point(0, 10) m = AffineTransformation.translation(Point(5, -2)) p.transform(m) self.assertEqual(p.x, 5) self.assertEqual(p.y, 8)
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 test_multiple_application(self): p = Point(10, 10) m = AffineTransformation() m.translate(Point(6, 5)) m.scale(1.5, 2) p.transform(m) self.assertEqual(p.x, 24) self.assertEqual(p.y, 30)
def alignmentTransformation(self): m = AffineTransformation.translation(self.start * -1) m.rotate((self.end.transformed(m)).angle * -1) return m
def splitWith(segs, splitline, args=None): """ Splits a list of segments given a straight splitting line. Returns 2 lists of segments such that the resulting segments are closed paths. """ trans = splitline.alignmentTransformation() lefts = [] rights = [] splits = [] for _s in segs: # transform so splitline is horizontal and is y=0 s = _s.transformed(trans) roots = s._findRoots("y") # does y=0 cut this segment? if len(roots) == 2: # chop a quadratic cuver and put parts in left and right collection l, r = s.splitAtTime(roots[0]) (rights if s.start.y < 0 else lefts).append(l) l, r = r.splitAtTime(roots[1]) (rights if s.end.y < 0 else lefts).append(r) # keep split points so we can add joinup lines later splits.append( (l.start.x, (l.start.x < s.start.x) ^ (s.start.y < 0))) splits.append((l.end.x, (l.end.x > s.end.x) ^ (s.start.y < 0))) elif len(roots) == 1: # chop a straight line l, r = s.splitAtTime(roots[0]) if s.start.y < 0: rights.append(l) lefts.append(r) splits.append((r.start.x, True)) else: lefts.append(l) rights.append(r) splits.append((r.start.x, False)) # otherwise no cut and simply allocate the segment elif s.start.y < 0 or s.end.y < 0: rights.append(s) else: lefts.append(s) # to convert from y=0 back to original co-ordinates backt = AffineTransformation() backt.apply_backwards(trans) backt.invert() if args is not None and args.detail & 8: print(" ", [(Point(s[0], 0).transformed(backt), s[1]) for s in sorted(splits)]) curr = False lastP = None # find adjacent pairs of bounding points on the splitline and join them up on either side # thus making closed paths, even if the segments aren't end to start all the way round. for x, d in sorted(splits): newP = Point(x, 0) if d != curr: curr = d if lastP is None: lastP = newP continue l = Line(lastP, newP) r = Line(newP, lastP) if not d: rights.append(l) lefts.append(r) lastP = newP rights = [s.transformed(backt) for s in rights] lefts = [s.transformed(backt) for s in lefts] return (rights, lefts)