def __init__(self, **kwargs):
     super(byA_CubicBezier, self).__init__(self)
     self._from = kwargs.get('P1')
     self._fromcontrol = kwargs.get('C1')
     self._tocontrol = kwargs.get('C2')
     self._to = kwargs.get('P2')
     assert isinstance(self._from, byA_Point)
     assert isinstance(self._fromcontrol, byA_Point)
     assert isinstance(self._tocontrol, byA_Point)
     assert isinstance(self._to, byA_Point)
     self._svgpathtools = CubicBezier(self._from.toRI(),
                                      self._fromcontrol.toRI(),
                                      self._tocontrol.toRI(),
                                      self._to.toRI())
     self._freeze("byA_CubicBezier")
Beispiel #2
0
    def snap(self, tree, threshold):
        def process(points):
            for i, p in enumerate(points):
                best, _, dist = tree.nearest_neighbor([p.real, p.imag])

                if dist < threshold:
                    points[i] = complex(best[0], best[1])
            return points

        path = parse_path(self['d'])
        newPath = Path()
        for seg in path:
            points = process([seg.start, seg.end])

            if isinstance(seg, Line):
                newSeg = Line(*points)
                newPath.append(newSeg)

            elif isinstance(seg, CubicBezier):
                newSeg = CubicBezier(points[0], seg.control1, seg.control2,
                                     points[1])
                newPath.append(newSeg)

        self['d'] = newPath.d()
        return self
Beispiel #3
0
def generateInBetweens(poseA, poseB, steps):
    inv = Inventory()

    # make pairs
    pairs = []
    for key in ORDER:
        if key in poseA.inv and key in poseB.inv:
            partA = poseA.inv[key]
            partB = poseB.inv[key]

            if len(partA) != 1 or len(partB) != 1:
                print('Too many parts {0} - A: {1} B: {2}'.format(
                    key, partA.keys(), partB.keys()))
                continue

            pairs.append((key, partA.values()[0], partB.values()[0]))

    # If there are 3 steps, there are 4 gaps between start and finish
    # |------1------2------3------|
    gaps = steps + 1

    # process pairs
    for key, a, b in pairs:
        pathA = parse_path(a['d'])
        pathB = parse_path(b['d'])

        if len(pathA) != len(pathB):
            print('Unmatched segments {0} - A: {1} B: {2}'.format(
                key, pathA, pathB))
            continue

        for step in range(1, gaps):
            newPath = Path()
            for i in range(len(pathA)):
                segA = pathA[i]
                segB = pathB[i]

                if isinstance(segA, Line):
                    points = _deltaPoints([segA.start, segA.end],
                                          [segB.start, segB.end], step, gaps)
                    newPath.append(Line(*points))

                elif isinstance(segA, CubicBezier):
                    points = _deltaPoints(
                        [segA.start, segA.control1, segA.control2, segA.end],
                        [segB.start, segB.control1, segB.control2, segB.end],
                        step, gaps)
                    newPath.append(CubicBezier(*points))

            newPart = Part(newPath.d())
            newPart['x'] = int(_delta(a['x'], b['x'], step, gaps))
            newPart['y'] = int(_delta(a['y'], b['y'], step, gaps))
            newPart['z'] = int(_delta(a['z'], b['z'], step, gaps))

            inv.addPart(key, newPart)
            print(key, step, newPart)

    return inv
Beispiel #4
0
def glyphToPaths(g, yMul=-1):
  paths = []
  contours = []
  yOffs = -font.info.unitsPerEm

  # decompose components
  if len(g.components):
    font.newGlyph('__svgsync')
    ng = font['__svgsync']
    ng.width = g.width
    ng.appendGlyph(g)
    ng.decompose()
    g = ng

  for c in g:
    curve = False
    points = c.points
    path = Path()
    currentPos = 0j
    controlPoints = []

    for x in range(len(points)):
      p = points[x]
      # print 'p#' + str(x) + '.type = ' + repr(p.type)

      if p.type == 'move':
        currentPos = vec2(p.x, (p.y + yOffs) * yMul)
      elif p.type == 'offcurve':
        controlPoints.append(p)
      elif p.type == 'curve':
        pos = vec2(p.x, (p.y + yOffs) * yMul)
        if len(controlPoints) == 2:
          cp1, cp2 = controlPoints
          path.append(CubicBezier(
            currentPos,
            vec2(cp1.x, (cp1.y + yOffs) * yMul),
            vec2(cp2.x, (cp2.y + yOffs) * yMul),
            pos))
        else:
          if len(controlPoints) != 1:
            raise Exception('unexpected number of control points for curve')
          cp = controlPoints[0]
          path.append(QuadraticBezier(currentPos, vec2(cp.x, (cp.y + yOffs) * yMul), pos))
        currentPos = pos
        controlPoints = []
      elif p.type == 'line':
        pos = vec2(p.x, (p.y + yOffs) * yMul)
        path.append(Line(currentPos, pos))
        currentPos = pos

    paths.append(path)

  if font.has_key('__svgsync'):
    font.removeGlyph('__svgsync')

  return paths
def trace_image(filecontents):
    output = StringIO()
    output.write(filecontents)
    _image = Image.open(output)
    pixels = posturize(_image)
    output_paths = []
    attributes = []
    for color in pixels:
        data = zeros(_image.size, uint32)
        for pixel in pixels[color]:
            data[pixel[0], pixel[1]] = 1
        # Create a bitmap from the array
        bmp = potrace.Bitmap(data)
        # Trace the bitmap to a path
        path = bmp.trace()
        # Iterate over path curves
        for curve in path:
            svg_paths = []
            start_point = curve.start_point
            true_start = curve.start_point
            for segment in curve:
                if true_start is None:
                    true_start = segment.start_point
                if start_point is None:
                    start_point = segment.start_point
                if isinstance(segment, BezierSegment):
                    svg_paths.append(
                        CubicBezier(
                            start=start_point[1] + 1j * start_point[0],
                            control1=segment.c1[1] + segment.c1[0] * 1j,
                            control2=segment.c2[1] + segment.c2[0] * 1j,
                            end=segment.end_point[1] +
                            1j * segment.end_point[0]))
                elif isinstance(segment, CornerSegment):
                    svg_paths.append(
                        Line(start=start_point[1] + 1j * start_point[0],
                             end=segment.c[1] + segment.c[0] * 1j))
                    svg_paths.append(
                        Line(start=segment.c[1] + segment.c[0] * 1j,
                             end=segment.end_point[1] +
                             1j * segment.end_point[0]))
                else:
                    print("not sure what to do with: ", segment)
                start_point = segment.end_point
                # is the path closed?
                if true_start == start_point:
                    output_paths.append(Path(*svg_paths))
                    color = pixel[2]
                    rgb = "#%02x%02x%02x" % (color[0], color[1], color[2])
                    fill = rgb
                    attributes.append({"fill": fill, "stroke": rgb})
                    true_start = None
                    start_point = None
                    svg_paths = []
    return output_paths, attributes
Beispiel #6
0
def _paperjs_path_to_polygon(co):
    '''
  Convert Paper.js paths to a polygon (a line composed of
  consecutive vertices).
  Used by `download_microdraw_contours_as_polygons`.
  
  Note: Paper.js Bézier curves are encoded as px, py, ax, ay, bx, by,
  where px, py is an anchor point, ax, ay is the previous handle and
  bx, by the next handle. SVG path tools use a more standard encoding:
  p1x,p1y, b1x, b1y, a2x, a2y, p2x, p2y, where p1x, p1y is the start
  anchor point, p2x, p2y the end anchor point, b1x, b1y is the
  handle coming out from p1x, p1y, and a2x, a2y is the handle entering
  into the end anchor point.
  '''
    mysegs = []
    for i in range(len(co)):
        c = co[i % len(co)]
        c1 = co[(i + 1) % len(co)]
        try:
            if isinstance(c[0], (list, np.ndarray)):
                # print("c[0] is list")
                [s, sj], [_, _], [b, bj] = c
            else:
                # print("c[0] is not list:", type(c[0]))
                s, sj, b, bj = c[0], c[1], 0, 0
            if isinstance(c1[0], (list, np.ndarray)):
                # print("c1[0] is list")
                [s1, s1j], [a1, a1j], [_, _] = c1
            else:
                # print("c1[0] is not list:", type(c1[0]))
                s1, s1j, a1, a1j = c1[0], c1[1], 0, 0
            # print("c:", c)
            # print("c1:", c1)
            # print("s,sj:",s,sj,", b,bj:",b,bj, ", s1,sij:", s1,s1j, ", a1,a1j:",a1,a1j)
            seg = CubicBezier(complex(s, sj), complex(s + b, sj + bj),
                              complex(s1 + a1, s1j + a1j), complex(s1, s1j))
            mysegs.append(seg)
        except:  # ValueError as err:
            # print(err)
            pass
    if len(mysegs) < 5:
        # print("len(mysegs) is < 5")
        return
    p = Path(*mysegs)
    NUM_SAMPLES = int(p.length())
    my_path = []
    for i in range(NUM_SAMPLES):
        x = p.point(i / (NUM_SAMPLES - 1))
        my_path.append([x.real, x.imag])
    return np.array(my_path)
def augment(path_nested, num):
    path_list = []

    path = Path()
    for p in path_nested:
        for segment in p:
            path.append(segment)

    end_points_list = []
    for segment in path:
        s = segment.bpoints()[0]
        e = segment.bpoints()[-1]
        end_points_list.append((s.real, s.imag))
        end_points_list.append((e.real, e.imag))
    end_points = np.array(end_points_list)
    hull_points = end_points[ConvexHull(end_points).vertices]
    idx_xmin, idx_ymin = np.argmin(hull_points, axis=0)
    idx_xmax, idx_ymax = np.argmax(hull_points, axis=0)
    x_range = 0.15 * (hull_points[idx_xmax][0] - hull_points[idx_xmin][0])
    y_range = 0.15 * (hull_points[idx_ymax][1] - hull_points[idx_ymin][1])
    idx_min_max = np.unique([idx_xmin, idx_ymin, idx_xmax, idx_ymax])

    for _ in range(num):
        # global deformation
        p = hull_points
        q = hull_points.copy()
        for idx in idx_min_max:
            x, y = p[idx]
            q[idx] = (x + random.gauss(0, x_range),
                      y + y_range * random.gauss(0, y_range))

        path_deformed = Path()
        for segment in path:
            points = []
            for v in segment.bpoints():
                real, imag = moving_least_square_with_rigid_transformation(
                    p, q, np.array([v.real, v.imag]), max(x_range, y_range))
                point_xformed = complex(real, imag)
                points.append(point_xformed)
            if len(segment.bpoints()) == 2:
                line = Line(points[0], points[1])
                path_deformed.append(line)
            else:
                cubic_bezier = CubicBezier(points[0], points[1], points[2],
                                           points[3])
                path_deformed.append(cubic_bezier)

        path_list.append(path_deformed)

    return path_list
Beispiel #8
0
    def generate(self, u, v, w):
        seg1 = self.getSegment(self.c, self.k, 0, u)
        seg2 = self.getSegment(self.c, self.k, 1, u)
        seg3 = self.getSegment(self.c, self.k, 2, u)
        seg4 = self.getSegment(self.c, self.k, 3, u)

        ck = Path(seg1, seg2, seg3, seg4)

        ll0 = Path(
            CubicBezier(self.lerp(self.l['start'], self.l0['start'], v),
                        self.lerp(self.l['c1'], self.l0['c1'], v),
                        self.lerp(self.l['c2'], self.l0['c2'], v),
                        self.lerp(self.l['end'], self.l0['end'], v)))

        self.paths = [ck, ll0]
        self.width = w
Beispiel #9
0
    def quantize(self):
        path = parse_path(self['d'])
        newPath = Path()
        for seg in path:
            if isinstance(seg, Line):
                newSeg = Line(
                    complex(round(seg.start.real), round(seg.start.imag)),
                    complex(round(seg.end.real), round(seg.end.imag)))
                newPath.append(newSeg)

            elif isinstance(seg, CubicBezier):
                newSeg = CubicBezier(
                    complex(round(seg.start.real), round(seg.start.imag)),
                    complex(round(seg.control1.real),
                            round(seg.control1.imag)),
                    complex(round(seg.control2.real),
                            round(seg.control2.imag)),
                    complex(round(seg.end.real), round(seg.end.imag)))
                newPath.append(newSeg)

        self['d'] = newPath.d()
        return self
Beispiel #10
0
 def curveTo(self, *points):
     cpoints = [self.convertPoint(self._lastOnCurve)]
     cpoints.extend([self.convertPoint(p) for p in points])
     self._contour.append(CubicBezier(*cpoints))
     self.logger.debug(f"CurveTo({points})")
     self._lastOnCurve = points[-1]
Beispiel #11
0
                if type(penult_segment) == CubicBezier:
                    s = copy.copy(penult_segment[4])
                    e = copy.copy(initial[1])
                    pathlist[-1] = (['Line', s, e])
                elif type(penult_segment) == Line:
                    s = copy.copy(penult_segment[2])
                    e = copy.copy(initial[1])
                    pathlist[-1] = (['Line', s, e])

        #for i in range(len(pathlist)):
        #    print('-> {}\t{}'.format(pathlist[i][3], pathlist[(i + 1) % (len(pathlist)) ][0]))
        #    print('<-: {}\t{}'.format(pathlist[i][0], pathlist[(i -1) % (len(pathlist)) ][3]))

        for i in pathlist:
            if i[0] == 'CubicBezier':
                newpath.append(CubicBezier(i[1], i[2], i[3], i[4]))
            elif i[0] == 'Line':
                newpath.append(Line(i[1], i[2]))

        newpaths.append(newpath)
        j += 1

    print('\tfinished generating frame {}'.format(FRAME + 1))

    # export svg
    #newpaths.reverse()
    svg_newfile = svg_file + '_' + str(FRAME + 1) + '.svg'
    wsvg(newpaths,
         attributes=attr,
         svg_attributes=svg_attr,
         filename=svg_newfile)
Beispiel #12
0
def draw_glyph(font, char, ctx, offset=(0, 0), color=(0.6, 0.6, 0.6)):
    try:
        face = Face('data/ttfs/{}.ttf'.format(font))
    except:
        face = Face('data/ttfs/{}.otf'.format(font))
    face.set_char_size(48*64)
    face.load_char(char)
    outline = face.glyph.outline
    contours = [-1] + outline.contours
    segment = []
    segments = []
    paths = []
    for i in range(len(outline.points)):
        segment.append(complex(*outline.points[i]).conjugate())
        tag = int(bin(outline.tags[i])[2])
        try:
            j = contours.index(i)
            if tag == 0:
                segment.append(complex(*outline.points[contours[j-1]+1]).conjugate())
                tag = 2
            else:
                tag = 3
        except ValueError:
            pass
        if tag > 0:
            if len(segment) == 1:
                pass
            elif len(segment) == 2:
                segments.append(Line(*segment))
            elif len(segment) == 3:
                segments.append(QuadraticBezier(*segment))
            elif len(segment) == 4:
                segments.append(CubicBezier(*segment))
            else:
                for k in range(len(segment)-1):
                    A, C = segment[k:k+2]
                    B = (A+C) / 2
                    segments.append(QuadraticBezier(A, B, C))

            if tag == 1:
                segment = [complex(*outline.points[i]).conjugate()]
            elif tag == 2:
                paths.append(Path(*segments))
                segments = []
                segment = []
            else:
                segments.append(Line(segment[-1], complex(*outline.points[contours[j-1]+1]).conjugate()))
                paths.append(Path(*segments))
                segments = []
                segment = []

    xmin, xmax, ymin, ymax = paths2svg.big_bounding_box(paths)
    factor = 0.8 / max(xmax-xmin, ymax-ymin)
    for i, path in enumerate(paths):
        paths[i] = path.translated(complex(-xmin, -ymin)).scaled(factor)
    xmin, xmax, ymin, ymax = paths2svg.big_bounding_box(paths)
    xmargin = (1 - (xmax-xmin)) / 2
    ymargin = (1 - (ymax-ymin)) / 2
    for i, path in enumerate(paths):
        paths[i] = path.translated(complex(xmargin, ymargin))

    ctx.set_source_rgb(*color)
    ctx.new_path()
    ctx.set_line_width(0.02)
    x, y = offset
    for path in paths:
        ctx.move_to(path[0].bpoints()[0].real + x, path[0].bpoints()[0].imag + y)
        for seg in path:
            bpoints = seg.bpoints()
            if len(bpoints) == 2:
                ctx.line_to(bpoints[1].real + x, bpoints[1].imag + y)
            elif len(bpoints) == 3:
                ctx.curve_to(bpoints[0].real * 1/3 + bpoints[1].real * 2/3 + x,
                             bpoints[0].imag * 1/3 + bpoints[1].imag * 2/3 + y,
                             bpoints[1].real * 2/3 + bpoints[2].real * 1/3 + x,
                             bpoints[1].imag * 2/3 + bpoints[2].imag * 1/3 + y,
                             bpoints[2].real + x, bpoints[2].imag + y)
            elif len(bpoints) == 4:
                ctx.curve_to(bpoints[1].real + x, bpoints[1].imag + y,
                             bpoints[2].real + x, bpoints[2].imag + y,
                             bpoints[3].real + x, bpoints[3].imag + y)
    ctx.fill()
Beispiel #13
0
 def getSegment(self, c, k, idx, t):
     return CubicBezier(self.lerp(c[idx]['start'], k[idx]['start'], t),
                        self.lerp(c[idx]['c1'], k[idx]['c1'], t),
                        self.lerp(c[idx]['c2'], k[idx]['c2'], t),
                        self.lerp(c[idx]['end'], k[idx]['end'], t))
from svgpathtools import Path, Line, QuadraticBezier, CubicBezier, Arc, svg2paths, parse_path, wsvg
from pcbmode.utils.svg import absolute_to_relative_path

print("Build SVG Path from lines")


seg1 = CubicBezier(300+100j, 100+100j, 200+200j, 200+300j) # A cubic beginning at (300, 100) and ending at (200, 300)
seg2 = Line(200+300j, 250+350j) # A line beginning at (200, 300) and ending at (250, 350)
path = Path(seg1, seg2) # A path traversing the cubic and then the line

# (svgpathtools only creates absolute path co-ordinates)

print(path.d())



print("Create SVG")
#(svgpathtools only creates absolute path co-ordinates)

outline_path = parse_path("m 10.858333,11 c 2.140681,-0.340482 4.281363,-0.680964 6.422044,-1.0214454 1.69236,-1.0123173 3.384721,-2.0246345 5.077081,-3.0369518 1.2656,-2.1059322 2.531201,-4.2118644 3.796801,-6.31779663 0.663858,-2.34543537 1.327716,-4.69087077 1.991574,-7.03630647 -0.223524,-1.829043 -0.447047,-3.6580857 -0.670571,-5.4871287 -0.600087,-0.758457 -1.200175,-1.516914 -1.800262,-2.275371 -17.1166667,0 -34.2333333,0 -51.35,0 -0.600087,0.758457 -1.200175,1.516914 -1.800262,2.275371 -0.223524,1.829043 -0.447047,3.6580857 -0.670571,5.4871287 0.663858,2.3454357 1.327716,4.6908711 1.991574,7.03630647 1.2656,2.10593223 2.531201,4.21186443 3.796801,6.31779663 1.69236,1.0123173 3.384721,2.0246345 5.077081,3.0369518 2.140681,0.3404814 4.281363,0.6809634 6.422044,1.0214454 7.2388887,0 14.4777773,0 21.716666,0 z", current_pos=0)
wsvg(outline_path, filename='svg/out/output1.svg')

p = parse_path("m 4.6147194,11.014797 c 0.04717,0.459725 -0.00339,0.582458 0.024033,1.056225", current_pos=0)

print p

print("Parse SVG")
paths, attributes = svg2paths('svg/in/triangle_relative.svg')

for path in paths:
    print absolute_to_relative_path(path.d())
class byA_CubicBezier(byA_FrozenClass):
    def __init__(self, **kwargs):
        super(byA_CubicBezier, self).__init__(self)
        self._from = kwargs.get('P1')
        self._fromcontrol = kwargs.get('C1')
        self._tocontrol = kwargs.get('C2')
        self._to = kwargs.get('P2')
        assert isinstance(self._from, byA_Point)
        assert isinstance(self._fromcontrol, byA_Point)
        assert isinstance(self._tocontrol, byA_Point)
        assert isinstance(self._to, byA_Point)
        self._svgpathtools = CubicBezier(self._from.toRI(),
                                         self._fromcontrol.toRI(),
                                         self._tocontrol.toRI(),
                                         self._to.toRI())
        self._freeze("byA_CubicBezier")

    def toSVGWrite(self, drawing, **extra):
        """to the svgwrite syntax
        """
        return drawing.path(d=self.toStr(), **extra)

    def toStr(self):
        return Path(self._svgpathtools).d()

    def reverse(self):
        return byA_CubicBezier(P1=self._to,
                               C1=self._tocontrol,
                               C2=self._fromcontrol,
                               P2=self._from)

    def rotate(self, degre, origin=None):
        self._svgpathtools = self._svgpathtools.rotated(degre, origin)
        self._from.rotate(degre, origin)
        self._fromcontrol.rotate(degre, origin)
        self._tocontrol.rotate(degre, origin)
        self._to.rotate(degre, origin)

    def rotated(self, degre, origin=None):
        res = byA_CubicBezier(P1=self._from,
                              C1=self._fromcontrol,
                              C2=self._tocontrol,
                              P2=self._to)
        res.rotate(degre, origin)
        return res

    def split(self, t):
        P12 = self._from + t * (self._fromcontrol - self._from)
        P23 = self._fromcontrol + t * (self._tocontrol - self._fromcontrol)
        P34 = self._tocontrol + t * (self._to - self._tocontrol)
        P123 = P12 + t * (P23 - P12)
        P234 = P23 + t * (P34 - P23)
        P1234 = P123 + t * (P234 - P123)
        return (byA_CubicBezier(P1=self._from, C1=P12, C2=P123, P2=P1234),
                byA_CubicBezier(P1=P1234, C1=P234, C2=P34, P2=self._to))

    def lenght(self):
        line = byA_Line(P1=self._from, P2=self._to)
        l = line.lenght()
        points = self.courbe_bezier_3(
            [self._from, self._fromcontrol, self._tocontrol, self._to], l * 10)
        res = 0
        for point in range(0, len(points) - 1):
            line = byA_Line(P1=points[point], P2=points[point + 1])
            res += line.lenght()
        return res

    def combinaison_lineaire(self, A, B, u, v):
        assert isinstance(A, byA_Point)
        assert isinstance(B, byA_Point)
        return byA_Point(x=A._x * u + B._x * v, y=A._y * u + B._y * v)

    def point_bezier_3(self, points_control, t):
        x = (1 - t)**2
        y = t * t
        A = self.combinaison_lineaire(points_control[0], points_control[1],
                                      (1 - t) * x, 3 * t * x)
        B = self.combinaison_lineaire(points_control[2], points_control[3],
                                      3 * y * (1 - t), y * t)
        return byA_Point(x=A._x + B._x, y=A._y + B._y)

    def courbe_bezier_3(self, points_control, N):
        if len(points_control) != 4:
            raise SystemExit("4 points de controle")
        dt = 1.0 / N
        t = dt
        points_courbe = [points_control[0]]
        while t < 1.0:
            points_courbe.append(self.point_bezier_3(points_control, t))
            t += dt
        points_courbe.append(points_control[3])
        return points_courbe
Beispiel #16
0
def process_letter(font_char):
    try:
        font, char = font_char
        name = "{}_{}".format(char, os.path.splitext(font)[0])
        face = Face('data/fonts/ttfs/{}'.format(font))
        face.set_char_size(48 * 64)
        face.load_char(char)
        outline = face.glyph.outline
        contours = [-1] + outline.contours
        segment = []
        segments = []
        paths = []
        for i in range(len(outline.points)):
            segment.append(complex(*outline.points[i]).conjugate())
            tag = int(bin(outline.tags[i])[2])
            try:
                j = contours.index(i)
                if tag == 0:
                    segment.append(
                        complex(*outline.points[contours[j - 1] +
                                                1]).conjugate())
                    tag = 2
                else:
                    tag = 3
            except ValueError:
                pass
            if tag > 0:
                if len(segment) == 1:
                    pass
                elif len(segment) == 2:
                    segments.append(Line(*segment))
                elif len(segment) == 3:
                    segments.append(QuadraticBezier(*segment))
                elif len(segment) == 4:
                    segments.append(CubicBezier(*segment))
                else:
                    for k in range(len(segment) - 1):
                        A, C = segment[k:k + 2]
                        B = (A + C) / 2
                        segments.append(QuadraticBezier(A, B, C))

                if tag == 1:
                    segment = [complex(*outline.points[i]).conjugate()]
                elif tag == 2:
                    paths.append(Path(*segments))
                    segments = []
                    segment = []
                else:
                    segments.append(
                        Line(
                            segment[-1],
                            complex(*outline.points[contours[j - 1] +
                                                    1]).conjugate()))
                    paths.append(Path(*segments))
                    segments = []
                    segment = []

        xmin, xmax, ymin, ymax = paths2svg.big_bounding_box(paths)
        factor = 0.8 / max(xmax - xmin, ymax - ymin)
        for i, path in enumerate(paths):
            paths[i] = path.translated(complex(-xmin, -ymin)).scaled(factor)
        xmin, xmax, ymin, ymax = paths2svg.big_bounding_box(paths)
        xmargin = (1 - (xmax - xmin)) / 2
        ymargin = (1 - (ymax - ymin)) / 2
        for i, path in enumerate(paths):
            paths[i] = path.translated(complex(xmargin, ymargin))

        points = []
        surface = cairo.ImageSurface(cairo.Format.RGB24, opt.img_size,
                                     opt.img_size)
        ctx = cairo.Context(surface)
        ctx.scale(opt.img_size, opt.img_size)
        ctx.set_source_rgba(1, 1, 1)
        ctx.rectangle(0, 0, 1, 1)
        ctx.fill()

        ctx.set_source_rgb(0, 0, 0)
        ctx.new_path()
        ctx.set_line_width(0.02)
        for path in paths:
            ctx.move_to(path[0].bpoints()[0].real, path[0].bpoints()[0].imag)
            for seg in path:
                bpoints = seg.bpoints()
                if len(bpoints) == 2:
                    ctx.line_to(bpoints[1].real, bpoints[1].imag)
                elif len(bpoints) == 3:
                    ctx.curve_to(
                        bpoints[0].real * 1 / 3 + bpoints[1].real * 2 / 3,
                        bpoints[0].imag * 1 / 3 + bpoints[1].imag * 2 / 3,
                        bpoints[1].real * 2 / 3 + bpoints[2].real * 1 / 3,
                        bpoints[1].imag * 2 / 3 + bpoints[2].imag * 1 / 3,
                        bpoints[2].real, bpoints[2].imag)
                elif len(bpoints) == 4:
                    ctx.curve_to(bpoints[1].real, bpoints[1].imag,
                                 bpoints[2].real, bpoints[2].imag,
                                 bpoints[3].real, bpoints[3].imag)
            for t in np.linspace(0,
                                 1,
                                 num=opt.n_points_sampled // len(paths) + 1):
                points.append(path.point(t))
        ctx.fill()

        n_points = len(points)
        points = np.array(points,
                          dtype=np.complex64).view(np.float32).reshape([-1, 2])
        np.random.shuffle(points)
        np.save('data/fonts/points/{}.npy'.format(name), points)

        grid = np.mgrid[-0.25:1.25:opt.img_size * 1.5j,
                        -0.25:1.25:opt.img_size * 1.5j].T[:, :, None, :]
        distances = np.empty((grid.shape[0], grid.shape[1]))
        for i in range(grid.shape[0]):
            for j in range(grid.shape[0]):
                distances[i, j] = np.amin(
                    np.linalg.norm(grid[i, j] - points, axis=1))
        if not np.isnan(distances).any():
            np.save('data/fonts/distances/{}.npy'.format(name), distances)
            surface.write_to_png('data/fonts/pngs/{}.png'.format(name))
        else:
            return e
    except Exception as e:
        return e

    return None
Beispiel #17
0
def parse_path(pathdef, current_pos=0j, tree_element=None):
    # In the SVG specs, initial movetos are absolute, even if
    # specified as 'm'. This is the default behavior here as well.
    # But if you pass in a current_pos variable, the initial moveto
    # will be relative to that current_pos. This is useful.
    elements = list(_tokenize_path(pathdef))
    # Reverse for easy use of .pop()
    elements.reverse()

    if tree_element is None:
        segments = Path()
    else:
        segments = Path(tree_element=tree_element)

    start_pos = None
    command = None

    while elements:

        if elements[-1] in COMMANDS:
            # New command.
            last_command = command  # Used by S and T
            command = elements.pop()
            absolute = command in UPPERCASE
            command = command.upper()
        else:
            # If this element starts with numbers, it is an implicit command
            # and we don't change the command. Check that it's allowed:
            if command is None:
                raise ValueError(
                    "Unallowed implicit command in %s, position %s" %
                    (pathdef, len(pathdef.split()) - len(elements)))

        if command == 'M':
            # Moveto command.
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if absolute:
                current_pos = pos
            else:
                current_pos += pos

            # when M is called, reset start_pos
            # This behavior of Z is defined in svg spec:
            # http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
            start_pos = current_pos

            # Implicit moveto commands are treated as lineto commands.
            # So we set command to lineto here, in case there are
            # further implicit commands after this moveto.
            command = 'L'

        elif command == 'Z':
            # Close path
            if not (current_pos == start_pos):
                segments.append(Line(current_pos, start_pos))
            segments.closed = True
            current_pos = start_pos
            command = None

        elif command == 'L':
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if not absolute:
                pos += current_pos
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'H':
            x = elements.pop()
            pos = float(x) + current_pos.imag * 1j
            if not absolute:
                pos += current_pos.real
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'V':
            y = elements.pop()
            pos = current_pos.real + float(y) * 1j
            if not absolute:
                pos += current_pos.imag * 1j
            segments.append(Line(current_pos, pos))
            current_pos = pos

        elif command == 'C':
            control1 = float(elements.pop()) + float(elements.pop()) * 1j
            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control1 += current_pos
                control2 += current_pos
                end += current_pos

            segments.append(CubicBezier(current_pos, control1, control2, end))
            current_pos = end

        elif command == 'S':
            # Smooth curve. First control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'CS':
                # If there is no previous command or if the previous command
                # was not an C, c, S or s, assume the first control point is
                # coincident with the current point.
                control1 = current_pos
            else:
                # The first control point is assumed to be the reflection of
                # the second control point on the previous command relative
                # to the current point.
                control1 = current_pos + current_pos - segments[-1].control2

            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control2 += current_pos
                end += current_pos

            segments.append(CubicBezier(current_pos, control1, control2, end))
            current_pos = end

        elif command == 'Q':
            control = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control += current_pos
                end += current_pos

            segments.append(QuadraticBezier(current_pos, control, end))
            current_pos = end

        elif command == 'T':
            # Smooth curve. Control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'QT':
                # If there is no previous command or if the previous command
                # was not an Q, q, T or t, assume the first control point is
                # coincident with the current point.
                control = current_pos
            else:
                # The control point is assumed to be the reflection of
                # the control point on the previous command relative
                # to the current point.
                control = current_pos + current_pos - segments[-1].control

            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(QuadraticBezier(current_pos, control, end))
            current_pos = end

        elif command == 'A':
            radius = float(elements.pop()) + float(elements.pop()) * 1j
            rotation = float(elements.pop())
            arc = float(elements.pop())
            sweep = float(elements.pop())
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(Arc(current_pos, radius, rotation, arc, sweep,
                                end))
            current_pos = end

    return segments
Beispiel #18
0
    def testPathToPolyligne():
        continuous_path = SVGPath(
            CubicBezier(start=(540.305 + 223.059j),
                        control1=(541.074 + 230.176j),
                        control2=(542.559 + 237.961j),
                        end=(544.609 + 245.051j)),
            Line(start=(544.609 + 245.051j), end=(631.121 + 550.996j)),
            Line(start=(631.121 + 550.996j), end=(726.211 + 550.996j)),
            Line(start=(726.211 + 550.996j), end=(643.008 + 257.996j)),
            CubicBezier(start=(643.008 + 257.996j),
                        control1=(640.977 + 250.93j),
                        control2=(639.629 + 244.414j),
                        end=(638.965 + 237.961j)),
            CubicBezier(start=(638.965 + 237.961j),
                        control1=(636.172 + 212.078j),
                        control2=(648.184 + 197.805j),
                        end=(693.516 + 197.805j)),
            CubicBezier(start=(693.516 + 197.805j),
                        control1=(745.254 + 197.805j),
                        control2=(766.211 + 218.555j),
                        end=(776.504 + 254.133j)),
            Line(start=(776.504 + 254.133j), end=(860.754 + 550.996j)),
            Line(start=(860.754 + 550.996j), end=(955.859 + 550.996j)),
            Line(start=(955.859 + 550.996j), end=(869.336 + 245.051j)),
            CubicBezier(start=(869.336 + 245.051j),
                        control1=(848.594 + 172.637j),
                        control2=(806.074 + 113.762j),
                        end=(674.746 + 113.762j)),
            CubicBezier(start=(674.746 + 113.762j),
                        control1=(570.637 + 113.762j),
                        control2=(534.199 + 166.152j),
                        end=(540.305 + 223.059j)))

        discontinuous_path = SVGPath(
            CubicBezier(start=(1648.6 + 430.684j),
                        control1=(1651.47 + 457.266j),
                        control2=(1635.71 + 473.398j),
                        end=(1589.79 + 473.398j)),
            CubicBezier(start=(1589.79 + 473.398j),
                        control1=(1540.63 + 473.398j),
                        control2=(1512.46 + 452.051j),
                        end=(1502.33 + 417.781j)),
            Line(start=(1502.33 + 417.781j), end=(1455.62 + 253.477j)),
            CubicBezier(start=(1455.62 + 253.477j),
                        control1=(1454.41 + 248.309j),
                        control2=(1453.24 + 243.105j),
                        end=(1452.73 + 238.586j)),
            CubicBezier(start=(1452.73 + 238.586j),
                        control1=(1449.93 + 212.703j),
                        control2=(1465.2 + 197.805j),
                        end=(1511.74 + 197.805j)),
            CubicBezier(start=(1511.74 + 197.805j),
                        control1=(1560.88 + 197.805j),
                        control2=(1588.76 + 216.57j),
                        end=(1599.2 + 253.477j)),
            Line(start=(1599.2 + 253.477j), end=(1645.92 + 417.781j)),
            CubicBezier(start=(1645.92 + 417.781j),
                        control1=(1647.08 + 422.285j),
                        control2=(1648.21 + 426.863j),
                        end=(1648.6 + 430.684j)),
            CubicBezier(start=(1355.23 + 228.242j),
                        control1=(1355.92 + 234.695j),
                        control2=(1357.37 + 241.836j),
                        end=(1359.35 + 248.309j)),
            Line(start=(1359.35 + 248.309j), end=(1409.47 + 426.152j)),
            CubicBezier(start=(1409.47 + 426.152j),
                        control1=(1432.25 + 506.406j),
                        control2=(1486.96 + 557.488j),
                        end=(1608.54 + 557.488j)),
            CubicBezier(start=(1608.54 + 557.488j),
                        control1=(1710.74 + 557.488j),
                        control2=(1752.37 + 499.27j),
                        end=(1746.04 + 440.43j)),
            CubicBezier(start=(1746.04 + 440.43j),
                        control1=(1745.44 + 434.578j),
                        control2=(1743.96 + 427.441j),
                        end=(1742.02 + 420.996j)),
            Line(start=(1742.02 + 420.996j), end=(1692.08 + 245.051j)),
            CubicBezier(start=(1692.08 + 245.051j),
                        control1=(1669.06 + 162.938j),
                        control2=(1615.23 + 113.762j),
                        end=(1487.85 + 113.762j)),
            CubicBezier(start=(1487.85 + 113.762j),
                        control1=(1386.29 + 113.762j),
                        control2=(1348.96 + 170.012j),
                        end=(1355.23 + 228.242j)))
        polc = continuousPathToPolyligne(continuous_path)
        polc.plot(plt)
        pols = pathToPolylignes(discontinuous_path)
        for pol in pols:
            pts = pol.cpoints
            name = pol.name
            plt.plot(pts[:, 0], pts[:, 1], '.-', label=name)
        plt.legend()
        plt.show()
Beispiel #19
0
 def getSegment(path):
     return CubicBezier(complex(path['p0'][0], path['p0'][1]),
                        complex(path['c0'][0], path['c0'][1]),
                        complex(path['c1'][0], path['c1'][1]),
                        complex(path['p1'][0], path['p1'][1]))
def sample_points_from_font(font, char):
    try:
        face = Face('data/ttfs/{}.ttf'.format(font))
    except:
        face = Face('data/ttfs/{}.otf'.format(font))
    face.set_char_size(48 * 64)
    face.load_char(char)
    outline = face.glyph.outline
    contours = [-1] + outline.contours
    segment = []
    segments = []
    paths = []
    for i in range(len(outline.points)):
        segment.append(complex(*outline.points[i]).conjugate())
        tag = int(bin(outline.tags[i])[2])
        try:
            j = contours.index(i)
            if tag == 0:
                segment.append(
                    complex(*outline.points[contours[j - 1] + 1]).conjugate())
                tag = 2
            else:
                tag = 3
        except ValueError:
            pass
        if tag > 0:
            if len(segment) == 1:
                pass
            elif len(segment) == 2:
                segments.append(Line(*segment))
            elif len(segment) == 3:
                segments.append(QuadraticBezier(*segment))
            elif len(segment) == 4:
                segments.append(CubicBezier(*segment))
            else:
                for k in range(len(segment) - 1):
                    A, C = segment[k:k + 2]
                    B = (A + C) / 2
                    segments.append(QuadraticBezier(A, B, C))

            if tag == 1:
                segment = [complex(*outline.points[i]).conjugate()]
            elif tag == 2:
                paths.append(Path(*segments))
                segments = []
                segment = []
            else:
                segments.append(
                    Line(
                        segment[-1],
                        complex(*outline.points[contours[j - 1] +
                                                1]).conjugate()))
                paths.append(Path(*segments))
                segments = []
                segment = []

    xmin, xmax, ymin, ymax = paths2svg.big_bounding_box(paths)
    factor = 0.8 / max(xmax - xmin, ymax - ymin)
    for i, path in enumerate(paths):
        paths[i] = path.translated(complex(-xmin, -ymin)).scaled(factor)
    xmin, xmax, ymin, ymax = paths2svg.big_bounding_box(paths)
    xmargin = (1 - (xmax - xmin)) / 2
    ymargin = (1 - (ymax - ymin)) / 2
    for i, path in enumerate(paths):
        paths[i] = path.translated(complex(xmargin, ymargin))

    points = []
    for path in paths:
        for seg in path:
            length = seg.length()
            for a in np.linspace(0, 1, num=length * n_points_per_unit_length):
                points.append(seg.point(seg.ilength(a * length)))

    return [(p.real, p.imag) for p in points]