def reflect(shape, position, _angle, keep_original): """Mirrors and copies the geometry across an invisible axis.""" if shape is None: return None new_shape = shape.cloneAndClear() for contour in shape.contours: c = Contour() for point in contour.points: d = distance(point.x, point.y, position.x, position.y) a = angle(point.x, point.y, position.x, position.y) x, y = coordinates(position.x, position.y, d * cos(radians(a - _angle)), 180 + _angle) d = distance(point.x, point.y, x, y) a = angle(point.x, point.y, x, y) px, py = coordinates(point.x, point.y, d * 2, a) c.addPoint(Point(px, py, point.type)) if contour.closed: c.close() new_shape.add(c) if keep_original: g = Geometry() g.add(shape) g.add(new_shape) return g return new_shape
def shape_on_path(shape, template, amount, dist, start, keep_geometry): if shape is None: return None if template is None: return None if isinstance(shape, Path): shape = shape.asGeometry() if isinstance(template, Path): template = template.asGeometry() g = Geometry() if keep_geometry: g.extend(template.clone()) first = True for i in range(amount): if first: t = start / 100 first = False else: t += dist / 500.0 pt1 = template.pointAt(t) pt2 = template.pointAt(t + 0.00001) a = angle(pt2.x, pt2.y, pt1.x, pt1.y) tp = Transform() tp.translate(pt1.x, pt1.y) tp.rotate(a - 180) new_shape = tp.map(shape) g.extend(new_shape) return g
def text_on_path(text, shape, font_name, font_size, alignment, margin, baseline_offset): if shape is None or shape.length <= 0: return None if text is None: return None text = unicode(text) if isinstance(shape, Path): shape = shape.asGeometry() p = Path() fm = get_font_metrics(font_name, font_size) string_width = textwidth(text, fm) dw = string_width / shape.length if alignment == "trailing": first = True for char in text: char_width = textwidth(char, fm) if first: t = (99.9 - margin) / 100.0 first = False else: t -= char_width / string_width * dw t = t % 1.0 margin = t * 100 first = True for char in text: char_width = textwidth(char, fm) if first: t = margin / 100.0 first = False else: t += char_width / string_width * dw # Always loop (the other behavior is weird) t = t % 1.0 pt1 = shape.pointAt(t) pt2 = shape.pointAt(t + 0.0000001) a = angle(pt2.x, pt2.y, pt1.x, pt1.y) tp = Text(char, -char_width, -baseline_offset) tp.align = Text.Align.LEFT tp.fontName = font_name tp.fontSize = font_size tp.translate(pt1.x, pt1.y) tp.rotate(a - 180) for contour in tp.path.contours: p.add(contour) return p
def round_segments(path, d): points = path.points new_points = [] for i, pt in enumerate(points): prev = points[i - 1] next = points[(i + 1) % len(points)] a = angle(prev.x, prev.y, next.x, next.y) c1 = coordinates(pt.x, pt.y, -d, a) c2 = coordinates(pt.x, pt.y, d, a) new_points.append(Point(c1[0], c1[1])) new_points.append(pt) new_points.append(Point(c2[0], c2[1])) new_path = path.cloneAndClear() _construct_path(new_path, new_points) return new_path
def text_on_path(shape, text, font_name="Verdana", font_size=20, position=0, offset=2.0, keep_geometry=True): if shape is None or shape.length <= 0: return None if text is None: return None text = unicode(text) if isinstance(shape, Path): shape = shape.asGeometry() g = Geometry() if keep_geometry: g.extend(shape.clone()) fm = get_font_metrics(font_name, font_size) string_width = textwidth(text, fm) dw = string_width / shape.length first = True for i, char in enumerate(text): char_width = textwidth(char, fm) if first: t = position / 100.0 first = False else: t += char_width / string_width * dw # Always loop (the other behavior is weird) t = t % 1.0 pt1 = shape.pointAt(t) pt2 = shape.pointAt(t + 0.001) a = angle(pt2.x, pt2.y, pt1.x, pt1.y) tp = Text(char, -char_width, -offset) tp.align = Text.Align.LEFT tp.fontName = font_name tp.fontSize = font_size tp.translate(pt1.x, pt1.y) tp.rotate(a - 180) g.add(tp.path) return g
def quad_curve(pt1, pt2, t, distance): t /= 100.0 cx = pt1.x + t * (pt2.x - pt1.x) cy = pt1.y + t * (pt2.y - pt1.y) a = angle(pt1.x, pt1.y, pt2.x, pt2.y) + 90 qx, qy = coordinates(cx, cy, distance, a) p = Path() p.moveto(pt1.x, pt1.y) c1x = pt1.x + 2 / 3.0 * (qx - pt1.x) c1y = pt1.y + 2 / 3.0 * (qy - pt1.y) c2x = pt2.x + 2 / 3.0 * (qx - pt2.x) c2y = pt2.y + 2 / 3.0 * (qy - pt2.y) p.curveto(c1x, c1y, c2x, c2y, pt2.x, pt2.y) p.fill = None p.stroke = Color.BLACK p.strokeWidth = 1.0 return p
def quad_curve(pt1, pt2, t, distance): t /= 100.0 cx = pt1.x + t * (pt2.x - pt1.x) cy = pt1.y + t * (pt2.y - pt1.y) a = angle(pt1.x, pt1.y, pt2.x, pt2.y) + 90 qx, qy = coordinates(cx, cy, distance, a) p = Path() p.moveto(pt1.x, pt1.y) c1x = pt1.x + 2/3.0 * (qx - pt1.x) c1y = pt1.y + 2/3.0 * (qy - pt1.y) c2x = pt2.x + 2/3.0 * (qx - pt2.x) c2y = pt2.y + 2/3.0 * (qy - pt2.y) p.curveto(c1x, c1y, c2x, c2y, pt2.x, pt2.y) p.fill = None p.stroke = Color.BLACK p.strokeWidth = 1.0 return p
def polygon(position, radius, sides, align): """Draw a polygon.""" p = Path() x, y, r = position.x, position.y, radius sides = max(sides, 3) a = 360.0 / sides da = 0 if align: x0, y0 = coordinates(x, y, r, 0) x1, y1 = coordinates(x, y, r, a) da = -angle(x1, y1, x0, y0) for i in xrange(sides): x1, y1 = coordinates(x, y, r, (a * i) + da) if i == 0: p.moveto(x1, y1) else: p.lineto(x1, y1) p.close() return p
def polygon(position, radius, sides, align): """Draw a polygon.""" p = Path() x, y, r = position.x, position.y, radius sides = max(sides, 3) a = 360.0 / sides da = 0 if align: x0, y0 = coordinates(x, y, r, 0) x1, y1 = coordinates(x, y, r, a) da = -angle(x1, y1, x0, y0) for i in xrange(sides): x1, y1 = coordinates(x, y, r, (a*i) + da) if i == 0: p.moveto(x1, y1) else: p.lineto(x1, y1) p.close() return p
def shape_on_path(shapes, path, amount, alignment, spacing, margin, baseline_offset): if not shapes: return [] if path is None: return [] if alignment == "trailing": shapes = list(shapes) shapes.reverse() length = path.length - margin m = margin / path.length c = 0 new_shapes = [] for i in xrange(amount): for shape in shapes: if alignment == "distributed": p = length / ((amount * len(shapes)) - 1) pos = c * p / length pos = m + (pos * (1 - 2 * m)) else: pos = ((c * spacing) % length) / length pos = m + (pos * (1 - m)) if alignment == "trailing": pos = 1 - pos p1 = path.pointAt(pos) p2 = path.pointAt(pos + 0.0000001) a = angle(p1.x, p1.y, p2.x, p2.y) if baseline_offset: coords = coordinates(p1.x, p1.y, baseline_offset, a - 90) p1 = Point(*coords) t = Transform() t.translate(p1) t.rotate(a) new_shapes.append(t.map(shape)) c += 1 return new_shapes
def _angle_to_point(shape): try: return angle(shape.x, shape.y, point.x, point.y) except AttributeError: centroid = shape.bounds.centroid return angle(centroid.x, centroid.y, point.x, point.y)