Ejemplo n.º 1
0
 def fromFontpartsGlyph(klass, glyph):
     """Returns an *array of BezierPaths* from a FontParts glyph object."""
     paths = []
     if hasattr(glyph, "contours"):
         contouriterator = glyph.contours
     else:
         contouriterator = glyph
     for c in contouriterator:
         path = BezierPath()
         path.closed = False
         nodeList = []
         if hasattr(c, "points"):
             pointiterator = c.points
         else:
             pointiterator = c
         for p in pointiterator:
             if hasattr(p, "segmentType"):
                 t = p.segmentType
             else:
                 t = p.type
             nodeList.append(Node(p.x, p.y, t))
         path.activeRepresentation = NodelistRepresentation(path, nodeList)
         if nodeList[0].point == nodeList[-1].point:
             path.closed = True
         paths.append(path)
     return paths
Ejemplo n.º 2
0
def drawIt(s, c, segs):
    import matplotlib.pyplot as plt

    fig, ax = plt.subplots()
    s.plot(ax, drawNodes=False)
    c.plot(ax)
    for s in segs:
        BezierPath.fromSegments([s]).plot(ax, drawNodes=False, color="red")
    plt.show()
Ejemplo n.º 3
0
    def test_cubic_cubic(self):
        # q1 = Bezier(10,100, 90,30, 40,140, 220,220)
        # q2 = Bezier(5,150, 180,20, 80,250, 210,190)
        # console.log(q1.intersects(q2))
        q1 = CubicBezier(Point(10, 100), Point(90, 30), Point(40, 140),
                         Point(220, 220))
        q2 = CubicBezier(Point(5, 150), Point(180, 20), Point(80, 250),
                         Point(210, 190))
        i = q1.intersections(q2)
        # self.assertEqual(len(i),3)
        # self.assertAlmostEqual(i[0].point.x,81.7904225873)
        # self.assertAlmostEqual(i[0].point.y,109.899396337)
        # self.assertAlmostEqual(i[1].point.x,133.186831292)
        # self.assertAlmostEqual(i[1].point.y,167.148173322)
        # self.assertAlmostEqual(i[2].point.x,179.869157678)
        # self.assertAlmostEqual(i[2].point.y,199.661989162)
        import matplotlib.pyplot as plt
        fig, ax = plt.subplots()

        path = BezierPath()
        path.closed = False
        path.activeRepresentation = SegmentRepresentation(path, [q1])
        path.plot(ax)
        path.activeRepresentation = SegmentRepresentation(path, [q2])
        path.plot(ax)

        for n in i:
            circle = plt.Circle((n.point.x, n.point.y),
                                2,
                                fill=True,
                                color="red")
            ax.add_artist(circle)
 def test_cubic_line(self):
     q = CubicBezier(Point(100, 240), Point(30, 60), Point(210, 230),
                     Point(160, 30))
     l = Line(Point(25, 260), Point(230, 20))
     path = BezierPath()
     path.closed = False
     path.activeRepresentation = SegmentRepresentation(path, [q])
     i = q.intersections(l)
     self.assertEqual(len(i), 3)
     self.assertEqual(i[0].point, q.pointAtTime(0.117517031451))
     self.assertEqual(i[1].point, q.pointAtTime(0.518591792307))
     self.assertEqual(i[2].point, q.pointAtTime(0.867886610031))
Ejemplo n.º 5
0
 def fromFontpartsGlyph(klass, glyph):
   """Returns an *array of BezierPaths* from a FontParts glyph object."""
   paths = []
   for c in glyph.contours:
     path = BezierPath()
     path.closed = False
     nodeList = []
     for p in c.points:
       nodeList.append(Node(p.x,p.y,p.type))
     path.activeRepresentation = NodelistRepresentation(path, nodeList)
     if nodeList[0].point == nodeList[-1].point:
       path.closed = True
     paths.append(path)
   return paths
Ejemplo n.º 6
0
 def fromFontpartsGlyph(klass, glyph):
     """Returns an *array of BezierPaths* from a FontParts glyph object."""
     paths = []
     for c in glyph.contours:
         path = BezierPath()
         path.closed = False
         nodeList = []
         for p in c.points:
             nodeList.append(Node(p.x, p.y, p.type))
         path.activeRepresentation = NodelistRepresentation(path, nodeList)
         if nodeList[0].point == nodeList[-1].point:
             path.closed = True
         paths.append(path)
     return paths
Ejemplo n.º 7
0
 def test_addextremes(self):
     q = CubicBezier(Point(42, 135), Point(129, 242), Point(167, 77),
                     Point(65, 59))
     ex = q.findExtremes()
     self.assertEqual(len(ex), 2)
     path = BezierPath()
     path.closed = False
     path.activeRepresentation = SegmentRepresentation(path, [q])
     path.addExtremes()
     path.balance()
     segs = path.asSegments()
     self.assertEqual(len(segs), 3)
Ejemplo n.º 8
0
    def get_cached_glyph(self, name):
        if name in self.glyphcache: return self.glyphcache[name]
        paths = BezierPath.fromFonttoolsGlyph(self.font, name)
        pathbounds = []
        paths = list(filter(lambda p: p.length > 0, paths))
        for p in paths:
            p.hasAnchor = False
            p.glyphname = name
            if name in self.anchors:
                for a in self.anchors[name]:
                    if p.pointIsInside(Point(*a)): p.hasAnchor = True
            bounds = p.bounds()
            pathbounds.append(bounds)

        glyphbounds = BoundingBox()
        if pathbounds:
            for p in pathbounds:
                glyphbounds.extend(p)
        else:
            glyphbounds.tr = Point(0, 0)
            glyphbounds.bl = Point(0, 0)
        self.glyphcache[name] = {
            "name": name,
            "paths": paths,
            "pathbounds": pathbounds,
            "glyphbounds": glyphbounds,
            "category": categorize_glyph(self.font, name)[0],
            "pathconvexhull": None  # XXX
        }
        assert (len(self.glyphcache[name]["pathbounds"]) == len(
            self.glyphcache[name]["paths"]))
        return self.glyphcache[name]
Ejemplo n.º 9
0
def calcStart(f, n, verbose):
    g = f['glyf'][n]
    #bs = BezierPath.fromFonttoolsGlyph(g, gset, f['glyf'])
    bs = BezierPath.fromFonttoolsGlyph(f, n)
    #    for b in bs:
    #        b.removeOverlap()
    bs = removeEncompassed(bs, verbose)
    segs = sum((b.asSegments() for b in bs), [])
    area = sum(s.area for s in segs)
    start = Octabox(segs)
    return start
Ejemplo n.º 10
0
    def test_overlap(self):
        nodes = [
            Node(698.0, 413.0, "offcurve"),
            Node(401.0, 179.0, "offcurve"),
            Node(401.0, 274.0, "curve"),
            Node(401.0, 368.0, "offcurve"),
            Node(315.0, 445.0, "offcurve"),
            Node(210.0, 445.0, "curve"),
            Node(104.0, 445.0, "offcurve"),
            Node(18.0, 368.0, "offcurve"),
            Node(18.0, 274.0, "curve"),
            Node(18.0, 179.0, "offcurve"),
            Node(439.0, 400.0, "offcurve"),
            Node(533.0, 405.0, "curve")
        ]
        p = BezierPath.fromNodelist(nodes)
        p.closed = True
        i = p.getSelfIntersections()
        self.assertEqual(len(i), 1)
        self.assertEqual(i[0].point, Point(377.714262786, 355.53493137))

        # import matplotlib.pyplot as plt
        # fig, ax = plt.subplots()
        # p.plot(ax)
        # for n in i:
        #   circle = plt.Circle((n.point.x, n.point.y), 2, fill=True, color="red")
        #   ax.add_artist(circle)
        # plt.show()

        p = BezierPath.fromNodelist([
            Node(310.0, 389.0, "line"),
            Node(453.0, 222.0, "line"),
            Node(289.0, 251.0, "line"),
            Node(447.0, 367.0, "line"),
            Node(578.0, 222.0, "line"),
            Node(210.0, -8.0, "line"),
        ])

        i = p.getSelfIntersections()
        self.assertEqual(len(i), 1)
        self.assertEqual(i[0].point, Point(374.448829525, 313.734583702))
Ejemplo n.º 11
0
def Rectangle(width, height, origin=None):
    """Returns a path representing an rectangle of given width and height.
  You can specify the `origin` as a Point."""
    if not origin:
        origin = Point(0, 0)
    tl = origin + west * width / 2.0 + north * height / 2.0
    tr = origin + east * width / 2.0 + north * height / 2.0
    bl = origin + west * width / 2.0 + south * height / 2.0
    br = origin + east * width / 2.0 + south * height / 2.0

    return BezierPath.fromSegments(
        [Line(tl, tr), Line(tr, br),
         Line(br, bl), Line(bl, tl)])
Ejemplo n.º 12
0
    def annotate_glyph(glyphname):
        paths = FontParts.fromFontpartsGlyph(font[glyphname])
        paths2 = []
        if drawarrows:
            for i in range(0, len(paths)):
                arrowP = paths[i].clone()
                arrowP.translate(arrowvector)
                arrowSeg, _ = (arrowP.asSegments())[0].splitAtTime(0.25)
                s = arrowSeg.start
                arrowPath = BezierPath.fromSegments([arrowSeg])
                # arrowPath.closed = False
                paths2.append(arrowPath)
                number = FontParts.fromFontpartsGlyph(
                    nf.numbersfont[nf.numbers[i]])
                # print(number[0].asNodelist())
                number[0].scale(0.05)
                number[0].translate(Point(s.x + 5, s.y + 5))
                number[0].closed = True
                paths2.append(number[0])
                # print('<text x="%s" y="%s">%i</text>' % (s.x+5.0,height-(s.y+5.0),1+i))
                # print('<path d="%s" stroke="black" stroke-width="2" fill="transparent" marker-end="url(#arrowhead)"/>\n' % path2svg([arrowSeg]))

        splitlist = []
        for i in range(0, len(paths)):
            for j in range(i + 1, len(paths)):
                one = paths[i]
                two = paths[j]
                for s1 in one.asSegments():
                    for s2 in two.asSegments():
                        for inter in s1.intersections(s2):
                            splitlist.append((inter.seg1, inter.t1))
                            splitlist.append((inter.seg2, inter.t2))

        for path in paths:
            path.splitAtPoints(splitlist)

        segs = []
        for i in range(0, len(paths)):
            segs = paths[i].asSegments()
            for s in segs:
                paths2.append(Circle(dotradius, origin=s.start))
                if s.length > dotspacing * dotradius:
                    closeEnough = int(s.length / (dotspacing * dotradius))
                    samples = s.regularSample(closeEnough)
                    for p in samples[1:]:
                        paths2.append(Circle(dotradius, origin=p))

        if len(segs) > 0:
            paths2.append(Circle(dotradius, origin=segs[-1].end))
        for p in paths2:
            FontParts.drawToFontpartsGlyph(font[glyphname], p)
Ejemplo n.º 13
0
 def __get_centreline(self, n1: str, n2: str) -> BezierPath:
     #=========================================================
     if (n1, n2) in self.__path_network.edges:
         edge = self.__path_network.edges[n1, n2]
         bezier_path = edge.get('geometry')
         if bezier_path is not None:
             if n1 == edge.get('start-node'):
                 return bezier_path
             else:
                 segments = [
                     bz.reversed() for bz in bezier_path.asSegments()
                 ]
                 segments.reverse()
                 return BezierPath.fromSegments(segments)
     return None
Ejemplo n.º 14
0
 def test_corners(self):
     nl = [
         Node(302.0, 492.0, "line"),
         Node(176.0, 432.0, "line"),
         Node(-51.0, 325.0, "offcurve"),
         Node(-74.0, 484.0, "offcurve"),
         Node(73.0, 570.0, "curve"),
         Node(85.0, 764.0, "offcurve"),
         Node(290.0, 748.0, "offcurve"),
         Node(418.0, 688.0, "curve"),
     ]
     path = BezierPath.fromNodelist(nl)
     path.closed = False
     for seg1, seg2 in path.segpairs():
         print(seg1.endAngle * 57.2958, seg2.startAngle * 57.2958)
Ejemplo n.º 15
0
    def _curve_from_lines(self, point_tuple_list: list) -> list:
        error = 50.0
        cornerTolerance = 20.0
        maxSegments = 20
        curve_points = SCBezierPath().fromPoints(
            [SCPoint(p[0], p[1]) for p in point_tuple_list],
            error=1.0,
            cornerTolerance=1.0,
            maxSegments=10000,
        )

        # Reconvert the BezierPath segments to our segment type
        point_tuple_list = []
        first = True
        for segment in curve_points.asSegments():
            segment_tuple = []
            if first:
                # For the first segment, add the move point
                p = segment[0]
                point_tuple_list.append([(p.x, p.y)])
            for p in segment[1:]:
                segment_tuple.append((p.x, p.y))
            point_tuple_list.append(segment_tuple)
        return point_tuple_list
Ejemplo n.º 16
0
def get_bezier_paths(font, glyphname):
    """Retrieve beziers from a glyph

    Args:
        font: A Babelfont font

    Returns:
        An array of ``beziers.path.BezierPath`` objects representing the
        outlines of the glyph.
    """
    layer = font.default_master.get_glyph_layer(glyphname)
    layer.decompose()
    return BezierPath.fromDrawable(layer, glyphSet = { k:font.default_master.get_glyph_layer(k)
        for k in font.exportedGlyphs()
    })
Ejemplo n.º 17
0
 def test_inside(self):
   p = BezierPath.fromNodelist([
     Node(329,320,"line"),
     Node(564,190,"line"),
     Node(622,332,"offcurve"),
     Node(495,471,"offcurve"),
     Node(329,471,"curve"),
     Node(164,471,"offcurve"),
     Node(34,334,"offcurve"),
     Node(93,190,"curve")
   ])
   self.assertTrue(p.pointIsInside(Point(326,423)))
   self.assertFalse(p.pointIsInside(Point(326,123)))
   self.assertFalse(p.pointIsInside(Point(326,251)))
   self.assertTrue(p.pointIsInside(Point(526,251)))
   self.assertTrue(p.pointIsInside(Point(126,251)))
Ejemplo n.º 18
0
 def test_cf2(self):
     nodes = [
         Point(100, 50),
         Point(50, 150),
         Point(100, 220),
         Point(200, 200),
         Point(250, 80),
         Point(220, 50)
     ]
     path = BezierPath.fromPoints(nodes)
     segs = path.asSegments()
     self.assertEqual(len(segs), 2)
     self.assertEqual(segs[0].start, Point(100.0, 50.0))
     self.assertAlmostEqual(segs[0][1].x, 83.333333333)
     self.assertAlmostEqual(segs[0][1].y, 83.333333333)
     self.assertEqual(segs[0].end, Point(50.0, 150.0))
     self.assertAlmostEqual(segs[1][1].x, 50)
     self.assertEqual(segs[1].end, Point(220.0, 50.0))
Ejemplo n.º 19
0
def xheight_intersections(ttFont, glyph):
    glyphset = ttFont.getGlyphSet()
    if glyph not in glyphset:
        return []

    paths = BezierPath.fromFonttoolsGlyph(ttFont, glyph)
    if len(paths) != 1:
        return []
    path = paths[0]

    xheight = ttFont["OS/2"].sxHeight

    bounds = path.bounds()
    bounds.addMargin(10)
    ray = Line(Point(bounds.left, xheight), Point(bounds.right, xheight))
    intersections = []
    for seg in path.asSegments():
        intersections.extend(seg.intersections(ray))
    return sorted(intersections, key=lambda i: i.point.x)
Ejemplo n.º 20
0
def Ellipse(x_radius, y_radius, origin=None, superness=CIRCULAR_SUPERNESS):
    """Returns a path representing an ellipse of given x and y radii.
  You can specify the `origin` as a Point and the `superness` of the ellipse."""
    if not origin:
        origin = Point(0, 0)
    w = origin + west * x_radius
    e = origin + east * x_radius
    n = origin + north * y_radius
    s = origin + south * y_radius

    w_n = CubicBezier(w, w + north * y_radius * superness,
                      n + west * x_radius * superness, n)
    n_e = CubicBezier(n, n + east * x_radius * superness,
                      e + north * y_radius * superness, e)
    e_s = CubicBezier(e, e + south * y_radius * superness,
                      s + east * x_radius * superness, s)
    s_w = CubicBezier(s, s + west * x_radius * superness,
                      w + south * y_radius * superness, w)
    return BezierPath.fromSegments([w_n, n_e, e_s, s_w])
Ejemplo n.º 21
0
 def not_a_test_cf3(self):
     import matplotlib.pyplot as plt
     import math
     fig, ax = plt.subplots()
     points = [
         Point(100, 50),
         Point(50, 150),
         Point(150, 250),
         Point(200, 220),
         Point(250, 80),
         Point(220, 50)
     ]
     path = BezierPath.fromPoints(points)
     centroid = path.bounds().centroid
     path.rotate(centroid, math.pi / 2)
     path.balance()
     path.plot(ax)
     path.offset(Point(5, 5)).plot(ax, color="red")
     path.offset(Point(-5, -5)).plot(ax, color="green")
     plt.show()
Ejemplo n.º 22
0
 def test_splitatpoints(self):
   p = BezierPath.fromNodelist([
     Node(297.0,86.0,"offcurve"),
     Node(344.0,138.0,"offcurve"),
     Node(344.0,203.0,"curve"),
     Node(344.0,267.0,"offcurve"),
     Node(297.0,319.0,"offcurve"),
     Node(240.0,319.0,"curve"),
     Node(183.0,319.0,"offcurve"),
     Node(136.0,267.0,"offcurve"),
     Node(136.0,203.0,"curve"),
     Node(136.0,138.0,"offcurve"),
     Node(183.0,86.0,"offcurve"),
     Node(240.0,86.0,"curve"),
   ])
   splitlist = []
   for seg in p.asSegments():
     for t in seg.regularSampleTValue(5):
       splitlist.append((seg,t))
   p.splitAtPoints(splitlist)
   self.assertEqual(len(p.asSegments()),24)
Ejemplo n.º 23
0
def bezier_paths_from_arc_endpoints(r, phi, flagA, flagS, p1, p2, T):
    #====================================================================
    arc = arc_endpoints_to_centre(r, phi, flagA, flagS, p1, p2)
    end_theta = arc.theta + arc.delta_theta
    t = arc.theta
    dt = math.pi / 4
    segments = []
    while (t + dt) < end_theta:
        control_points = (BezierPoint(*T.transform_point(cp))
                          for cp in cubic_bezier_control_points(
                              arc.centre, arc.radii, phi, t, t + dt))
        segments.append(CubicBezier(*control_points))
        t += dt
    control_points = (BezierPoint(*T.transform_point(cp))
                      for cp in cubic_bezier_control_points(
                          arc.centre, arc.radii, phi, t, end_theta))
    segments.append(
        CubicBezier(*(tuple(control_points)[:3]),
                    BezierPoint(*T.transform_point(p2))))
    path = BezierPath.fromSegments(segments)
    path.closed = False
    return path
Ejemplo n.º 24
0
def outlines_dict(ttFont):
    return {g: BezierPath.fromFonttoolsGlyph(ttFont, g) for g in ttFont.getGlyphOrder()}
    def clip(self, clip, cliptype, flat=False):
        splitlist1 = []
        splitlist2 = []
        intersections = {}
        cloned = self.clone()
        clip = clip.clone()

        # Split all segments at intersections
        for s1 in self.asSegments():
            for s2 in clip.asSegments():
                for i in s1.intersections(s2):
                    if i.t1 > 1e-8 and i.t1 < 1 - 1e-8:
                        if i.seg1 == s1:
                            splitlist1.append((i.seg1, i.t1))
                            splitlist2.append((i.seg2, i.t2))
                        else:
                            splitlist2.append((i.seg1, i.t1))
                            splitlist1.append((i.seg2, i.t2))
                        intersections[i.point] = i

        logging.debug("Split list: %s" % splitlist1)
        logging.debug("Split list 2: %s" % splitlist2)
        cloned.splitAtPoints(splitlist1)
        clip.splitAtPoints(splitlist2)
        logging.debug("Self:")
        logging.debug(cloned.asSegments())
        logging.debug("Clip:")
        logging.debug(clip.asSegments())

        segs1unflattened = cloned.asSegments()
        segs2unflattened = clip.asSegments()

        # Replace with flattened versions, building a dictionary of originals
        segs1 = []
        reconstructionLUT = {}
        precision = 100.

        def fillLUT(flats):
            for line in flats:
                key = ((line.start * precision).rounded(),
                       (line.end * precision).rounded())
                reconstructionLUT[key] = (line._orig or line)
                key2 = ((line.end * precision).rounded(),
                        (line.start * precision).rounded())
                reconstructionLUT[key2] = (line._orig or line).reversed()

        for s in segs1unflattened:
            flats = s.flatten(2)
            fillLUT(flats)
            segs1.extend(flats)

        segs2 = []
        for s in segs2unflattened:
            flats = s.flatten(2)
            fillLUT(flats)
            segs2.extend(flats)

        # Leave it to the professionals
        subj = [(s[0].x * precision, s[0].y * precision) for s in segs1]
        clip = [(s[0].x * precision, s[0].y * precision) for s in segs2]
        pc = pyclipper.Pyclipper()
        pc.AddPath(clip, pyclipper.PT_CLIP, True)
        pc.AddPath(subj, pyclipper.PT_SUBJECT, True)
        paths = pc.Execute(cliptype, pyclipper.PFT_EVENODD,
                           pyclipper.PFT_EVENODD)
        outpaths = []

        # Now reconstruct Bezier segments from flattened paths
        def pairwise(points):
            a = (p for p in points)
            b = (p for p in points)
            next(b)
            for curpoint, nextpoint in zip(a, b):
                yield curpoint, nextpoint

        newpaths = []
        from beziers.path import BezierPath
        for p in paths:
            newpath = []
            for scaledstart, scaledend in pairwise(p):
                key = (Point(*scaledstart), Point(*scaledend))
                if key in reconstructionLUT and not flat:
                    orig = reconstructionLUT[key]
                    if len(newpath) == 0 or newpath[-1] != orig:
                        newpath.append(orig)
                else:
                    newpath.append(Line(key[0] / precision,
                                        key[1] / precision))
            outpaths.append(BezierPath.fromSegments(newpath))
        return outpaths
Ejemplo n.º 26
0
 def not_a_test_offset(self):
     b = DotMap({
         "closed":
         False,
         "nodes": [{
             "x": 412.0,
             "y": 500.0,
             "type": "line"
         }, {
             "x": 308.0,
             "y": 665.0,
             "type": "offcurve"
         }, {
             "x": 163.0,
             "y": 589.0,
             "type": "offcurve"
         }, {
             "x": 163.0,
             "y": 504.0,
             "type": "curve"
         }, {
             "x": 163.0,
             "y": 424.0,
             "type": "offcurve"
         }, {
             "x": 364.0,
             "y": 321.0,
             "type": "offcurve"
         }, {
             "x": 366.0,
             "y": 216.0,
             "type": "curve"
         }, {
             "x": 368.0,
             "y": 94.0,
             "type": "offcurve"
         }, {
             "x": 260.0,
             "y": 54.0,
             "type": "offcurve"
         }, {
             "x": 124.0,
             "y": 54.0,
             "type": "curve"
         }]
     })
     path = BezierPath()
     path.activeRepresentation = GSPathRepresentation(path, b)
     import matplotlib.pyplot as plt
     fig, ax = plt.subplots()
     path.addExtremes()
     path.plot(ax)
     for n in path.asSegments():
         p = n.tunniPoint
         if p:
             circle = plt.Circle((p.x, p.y), 1, fill=False, color="blue")
             ax.add_artist(circle)
         n.balance()
     path.translate(Point(5, 5))
     path.plot(ax, color="red")
     # o1 = path.offset(Point(10,10))
     # o2 = path.offset(Point(-10,-10))
     # o2.reverse()
     # o1.append(o2)
     # o1.plot(ax)
     plt.show()
Ejemplo n.º 27
0
    def geometry(self) -> [GeometricShape]:
        """
        Returns:
            A list of geometric objects. This are LineStrings describing paths
            between nodes and possibly additional features (e.g. way markers)
            of the paths.
        """
        display_bezier_points = True  #False     ### To come from settings...
        if self.__path_layout == 'automatic':
            log("Automated pathway layout. Path ID: ", self.__path_id)
            evaluate_settings = self.__sheath.settings()
            # TODO: use evenly-distributed offsets for the final product.
            number_of_neurons = len(evaluate_settings['derivatives'])
            # locations = [0.01 + x*(0.99-0.01)/number_of_neurons for x in range(number_of_neurons)]
            location = 0.5
            geometry = []
            for scaffold, path_id, derivative in zip(
                    evaluate_settings['scaffolds'],
                    evaluate_settings['path_ids'],
                    evaluate_settings['derivatives']):
                scaffold.generate()
                connectivity = Connectivity(path_id, scaffold, derivative,
                                            location)
                auto_beziers = connectivity.get_neuron_line_beziers()
                path = BezierPath.fromSegments(auto_beziers)
                geometry.append(
                    GeometricShape(
                        shapely.geometry.LineString(bezier_sample(path))))
            end_nodes = set(self.__source_nodes)
            end_nodes.update(self.__target_nodes)
            for node in end_nodes:
                for edge in self.__graph.edges(node, data=True):
                    if edge[2].get('type') == 'terminal':
                        line = self.__line_from_edge(edge)
                        if line is not None:
                            geometry.append(GeometricShape(line))
            if display_bezier_points:
                for beziers in self.__sheath.path_beziers.values():
                    for bezier in beziers:
                        bz_pts = tuple([p.x, p.y] for p in bezier.points)
                        for pt in [bz_pts[0], bz_pts[3]]:
                            geometry.append(
                                GeometricShape(GeometricShape.circle(pt), {
                                    'type': 'bezier',
                                    'kind': 'bezier-end'
                                }))
                        for pt in bz_pts[1:3]:
                            geometry.append(
                                GeometricShape(GeometricShape.circle(pt), {
                                    'type': 'bezier',
                                    'kind': 'bezier-control'
                                }))
                        geometry.append(
                            GeometricShape(GeometricShape.line(*bz_pts[0:2]),
                                           {'type': 'bezier'}))
                        geometry.append(
                            GeometricShape(GeometricShape.line(*bz_pts[2:4]),
                                           {'type': 'bezier'}))

            return geometry

        # Fallback is centreline layout
        geometry = []
        for edge in self.__graph.edges.data():
            nerve = edge[2].get('nerve')
            properties = {'nerve': nerve} if nerve is not None else None
            bezier = edge[2].get('geometry')
            if self.__path_layout != 'linear' and bezier is not None:
                geometry.append(
                    GeometricShape(
                        shapely.geometry.LineString(bezier_sample(bezier)),
                        properties))
            else:
                line = self.__line_from_edge(edge)
                if line is not None:
                    geometry.append(GeometricShape(line, properties))
        return geometry
Ejemplo n.º 28
0
    def __get_geometry(self, shape, properties, transform):
    #======================================================
    ##
    ## Returns shape's geometry as `shapely` object.
    ##
        coordinates = []
        bezier_segments = []
        pptx_geometry = Geometry(shape)
        for path in pptx_geometry.path_list:
            bbox = (shape.width, shape.height) if path.w is None or path.h is None else (path.w, path.h)
            T = transform@DrawMLTransform(shape, bbox)

            moved = False
            first_point = None
            current_point = None
            closed = False

            for c in path.getchildren():
                if   c.tag == DML('arcTo'):
                    (wR, hR) = ((pptx_geometry.attrib_value(c, 'wR'),
                                 pptx_geometry.attrib_value(c, 'hR')))
                    stAng = radians(pptx_geometry.attrib_value(c, 'stAng'))
                    swAng = radians(pptx_geometry.attrib_value(c, 'swAng'))
                    p1 = ellipse_point(wR, hR, stAng)
                    p2 = ellipse_point(wR, hR, stAng + swAng)
                    pt = (current_point[0] - p1[0] + p2[0],
                          current_point[1] - p1[1] + p2[1])
                    large_arc_flag = 1 if swAng >= math.pi else 0
                    path = bezier_path_from_arc_endpoints(tuple2(wR, hR),
                                        0, large_arc_flag, 1,
                                        tuple2(*current_point), tuple2(*pt),
                                        T)
                    bezier_segments.extend(path.asSegments())
                    coordinates.extend(bezier_sample(path))
                    current_point = pt

                elif c.tag == DML('close'):
                    if first_point is not None and current_point != first_point:
                        coordinates.append(T.transform_point(first_point))
                    closed = True
                    first_point = None
                    # Close current pptx_geometry and start a new one...

                elif c.tag == DML('cubicBezTo'):
                    coords = [BezierPoint(*T.transform_point(current_point))]
                    for p in c.getchildren():
                        pt = pptx_geometry.point(p)
                        coords.append(BezierPoint(*T.transform_point(pt)))
                        current_point = pt
                    bz = CubicBezier(*coords)
                    bezier_segments.append(bz)
                    coordinates.extend(bezier_sample(bz))

                elif c.tag == DML('lnTo'):
                    pt = pptx_geometry.point(c.pt)
                    if moved:
                        coordinates.append(T.transform_point(current_point))
                        moved = False
                    coordinates.append(T.transform_point(pt))
                    current_point = pt

                elif c.tag == DML('moveTo'):
                    pt = pptx_geometry.point(c.pt)
                    if first_point is None:
                        first_point = pt
                    current_point = pt
                    moved = True

                elif c.tag == DML('quadBezTo'):
                    coords = [BezierPoint(*T.transform_point(current_point))]
                    for p in c.getchildren():
                        pt = pptx_geometry.point(p)
                        coords.append(BezierPoint(*T.transform_point(pt)))
                        current_point = pt
                    bz = QuadraticBezier(*coords)
                    bezier_segments.append(bz)
                    coordinates.extend(bezier_sample(bz))

                else:
                    log.warn('Unknown path element: {}'.format(c.tag))

        if len(bezier_segments) > 0:
            properties['bezier-path'] = BezierPath.fromSegments(bezier_segments)

        if closed:
            geometry = shapely.geometry.Polygon(coordinates)
        else:
            geometry = shapely.geometry.LineString(coordinates)
            if properties.get('closed', False):
                # Return a polygon if flagged as `closed`
                coordinates.append(coordinates[0])
                return shapely.geometry.Polygon(coordinates)
        return geometry
Ejemplo n.º 29
0
    def __get_geometry(self, element, properties, transform):
    #=======================================================
    ##
    ## Returns path element as a `shapely` object.
    ##
        coordinates = []
        bezier_segments = []
        moved = False
        first_point = None
        current_point = None
        closed = False
        path_tokens = []

        T = transform@SVGTransform(element.attrib.get('transform'))
        if element.tag == SVG_NS('path'):
            path_tokens = list(parse_svg_path(element.attrib.get('d', '')))

        elif element.tag == SVG_NS('rect'):
            x = length_as_pixels(element.attrib.get('x', 0))
            y = length_as_pixels(element.attrib.get('y', 0))
            width = length_as_pixels(element.attrib.get('width', 0))
            height = length_as_pixels(element.attrib.get('height', 0))
            rx = length_as_pixels(element.attrib.get('rx'))
            ry = length_as_pixels(element.attrib.get('ry'))
            if width == 0 or height == 0: return None

            if rx is None and ry is None:
                rx = ry = 0
            elif ry is None:
                ry = rx
            elif rx is None:
                rx = ry
            rx = min(rx, width/2)
            ry = min(ry, height/2)
            if rx == 0 and ry == 0:
                path_tokens = ['M', x, y,
                               'H', x+width,
                               'V', y+height,
                               'H', x,
                               'V', y,
                               'Z']
            else:
                path_tokens = ['M', x+rx, y,
                               'H', x+width-rx,
                               'A', rx, ry, 0, 0, 1, x+width, y+ry,
                               'V', y+height-ry,
                               'A', rx, ry, 0, 0, 1, x+width-rx, y+height,
                               'H', x+rx,
                               'A', rx, ry, 0, 0, 1, x, y+height-ry,
                               'V', y+ry,
                               'A', rx, ry, 0, 0, 1, x+rx, y,
                               'Z']

        elif element.tag == SVG_NS('line'):
            x1 = length_as_pixels(element.attrib.get('x1', 0))
            y1 = length_as_pixels(element.attrib.get('y1', 0))
            x2 = length_as_pixels(element.attrib.get('x2', 0))
            y2 = length_as_pixels(element.attrib.get('y2', 0))
            path_tokens = ['M', x1, y1, x2, y2]

        elif element.tag == SVG_NS('polyline'):
            points = element.attrib.get('points', '').replace(',', ' ').split()
            path_tokens = ['M'] + points

        elif element.tag == SVG_NS('polygon'):
            points = element.attrib.get('points', '').replace(',', ' ').split()
            path_tokens = ['M'] + points + ['Z']

        elif element.tag == SVG_NS('circle'):
            cx = length_as_pixels(element.attrib.get('cx', 0))
            cy = length_as_pixels(element.attrib.get('cy', 0))
            r = length_as_pixels(element.attrib.get('r', 0))
            if r == 0: return None
            path_tokens = ['M', cx+r, cy,
                           'A', r, r, 0, 0, 0, cx, cy-r,
                           'A', r, r, 0, 0, 0, cx-r, cy,
                           'A', r, r, 0, 0, 0, cx, cy+r,
                           'A', r, r, 0, 0, 0, cx+r, cy,
                           'Z']

        elif element.tag == SVG_NS('ellipse'):
            cx = length_as_pixels(element.attrib.get('cx', 0))
            cy = length_as_pixels(element.attrib.get('cy', 0))
            rx = length_as_pixels(element.attrib.get('rx', 0))
            ry = length_as_pixels(element.attrib.get('ry', 0))
            if rx == 0 or ry == 0: return None
            path_tokens = ['M', cx+rx, cy,
                           'A', rx, ry, 0, 0, 0, cx, cy-ry,
                           'A', rx, ry, 0, 0, 0, cx-rx, cy,
                           'A', rx, ry, 0, 0, 0, cx, cy+ry,
                           'A', rx, ry, 0, 0, 0, cx+rx, cy,
                           'Z']

        elif element.tag == SVG_NS('image'):
            if 'id' in properties or 'class' in properties:
                width = length_as_pixels(element.attrib.get('width', 0))
                height = length_as_pixels(element.attrib.get('height', 0))
                path_tokens = ['M', 0, 0,
                               'H', width,
                               'V', height,
                               'H', 0,
                               'V', 0,
                               'Z']

        pos = 0
        while pos < len(path_tokens):
            if isinstance(path_tokens[pos], str) and path_tokens[pos].isalpha():
                cmd = path_tokens[pos]
                pos += 1
            # Else repeat previous command with new coordinates
            # with `moveTo` becoming `lineTo`
            elif cmd == 'M':
                cmd = 'L'
            elif cmd == 'm':
                cmd = 'l'

            if cmd not in ['s', 'S']:
                second_cubic_control = None
            if cmd not in ['t', 'T']:
                second_quad_control = None

            if cmd in ['a', 'A']:
                params = [float(x) for x in path_tokens[pos:pos+7]]
                pos += 7
                pt = params[5:7]
                if cmd == 'a':
                    pt[0] += current_point[0]
                    pt[1] += current_point[1]
                phi = radians(params[2])
                path = bezier_path_from_arc_endpoints(tuple2(*params[0:2]), phi, *params[3:5],
                                                        tuple2(*current_point), tuple2(*pt), T)
                bezier_segments.extend(path.asSegments())
                coordinates.extend(bezier_sample(path))
                current_point = pt

            elif cmd in ['c', 'C', 's', 'S']:
                coords = [BezierPoint(*T.transform_point(current_point))]
                if cmd in ['c', 'C']:
                    n_params = 6
                else:
                    n_params = 4
                    if second_cubic_control is None:
                        coords.append(BezierPoint(*T.transform_point(current_point)))
                    else:
                        coords.append(BezierPoint(*T.transform_point(
                            reflect_point(second_cubic_control, current_point))))
                params = [float(x) for x in path_tokens[pos:pos+n_params]]
                pos += n_params
                for n in range(0, n_params, 2):
                    pt = params[n:n+2]
                    if cmd.islower():
                        pt[0] += current_point[0]
                        pt[1] += current_point[1]
                    if n == (n_params - 4):
                        second_cubic_control = pt
                    coords.append(BezierPoint(*T.transform_point(pt)))
                bz = CubicBezier(*coords)
                bezier_segments.append(bz)
                coordinates.extend(bezier_sample(bz))
                current_point = pt

            elif cmd in ['l', 'L', 'h', 'H', 'v', 'V']:
                if cmd in ['l', 'L']:
                    params = [float(x) for x in path_tokens[pos:pos+2]]
                    pos += 2
                    pt = params[0:2]
                    if cmd == 'l':
                        pt[0] += current_point[0]
                        pt[1] += current_point[1]
                else:
                    param = float(path_tokens[pos])
                    pos += 1
                    if cmd == 'h':
                        param += current_point[0]
                    elif cmd == 'v':
                        param += current_point[1]
                    if cmd in ['h', 'H']:
                        pt = [param, current_point[1]]
                    else:
                        pt = [current_point[0], param]
                if moved:
                    coordinates.append(T.transform_point(current_point))
                    moved = False
                coordinates.append(T.transform_point(pt))
                current_point = pt

            elif cmd in ['m', 'M']:
                params = [float(x) for x in path_tokens[pos:pos+2]]
                pos += 2
                pt = params[0:2]
                if first_point is None:
                    # First `m` in a path is treated as `M`
                    first_point = pt
                else:
                    if cmd == 'm':
                        pt[0] += current_point[0]
                        pt[1] += current_point[1]
                current_point = pt
                moved = True

            elif cmd in ['q', 'Q', 't', 'T']:
                coords = [BezierPoint(*T.transform_point(current_point))]
                if cmd in ['q', 'Q']:
                    n_params = 4
                else:
                    n_params = 2
                    if second_quad_control is None:
                        coords.append(BezierPoint(*T.transform_point(current_point)))
                    else:
                        coords.append(BezierPoint(*T.transform_point(
                            reflect_point(second_quad_control, current_point))))
                params = [float(x) for x in path_tokens[pos:pos+n_params]]
                pos += n_params
                for n in range(0, n_params, 2):
                    pt = params[n:n+2]
                    if cmd.islower():
                        pt[0] += current_point[0]
                        pt[1] += current_point[1]
                    if n == (n_params - 4):
                        second_quad_control = pt
                    coords.append(BezierPoint(*T.transform_point(pt)))
                bz = QuadraticBezier(*coords)
                bezier_segments.append(bz)
                coordinates.extend(bezier_sample(bz))
                current_point = pt

            elif cmd in ['z', 'Z']:
                if first_point is not None and current_point != first_point:
                    coordinates.append(T.transform_point(first_point))
                closed = True
                first_point = None

            else:
                log.warn('Unknown path command: {}'.format(cmd))

        if len(bezier_segments) > 0:
            properties['bezier-path'] = BezierPath.fromSegments(bezier_segments)

        if closed and len(coordinates) >= 3:
            geometry = shapely.geometry.Polygon(coordinates)
        elif properties.get('closed', False) and len(coordinates) >= 3:
            # Return a polygon if flagged as `closed`
            coordinates.append(coordinates[0])
            geometry = shapely.geometry.Polygon(coordinates)
        elif len(coordinates) >= 2:
            geometry = shapely.geometry.LineString(coordinates)
        else:
            geometry = None
        return geometry
Ejemplo n.º 30
0
    def __extract_components(self) -> None:
        #======================================
        """
        Extracts and stores centreline components (i.e, coordinates & derivatives)
        in a dictionary for every nerve set. Each nerve set is a dict with keys
        corresponding to the keys in self.__continuous_paths.
        """
        node_geometry = self.__path_network.nodes(data='geometry')
        for path_id, path_nodes in self.__continuous_paths.items():
            # First derive the segments that connect the path's nodes
            centrelines = []
            node_regions = []
            for node_1, node_2 in pairwise(path_nodes):
                centreline = self.__get_centreline(node_1, node_2)
                if len(centrelines) > 0:
                    ##join_region = node_geometry[node_1]
                    # Join previous and current centreline in circle centred at region's centroid
                    join_region = node_geometry[node_1].centroid.buffer(
                        JOIN_RADIUS)
                    joined_beziers = join_beziers_in_region(
                        centrelines[-1], join_region, centreline)

                    # Adjust previous centreline
                    segments = centrelines[-1].asSegments()
                    segments[-1] = joined_beziers[0]
                    centrelines[-1] = BezierPath.fromSegments(segments)

                    # Add centreline of join
                    centrelines.append(
                        BezierPath.fromSegments(joined_beziers[1:2]))
                    node_regions.append((None, None))

                    # Adjust current centreline
                    segments = centreline.asSegments()
                    segments[0] = joined_beziers[2]
                    centreline = BezierPath.fromSegments(segments)

                centrelines.append(centreline)
                node_regions.append(
                    (node_geometry[node_1], node_geometry[node_2]))

            # Get the path segment for each centreline
            path_segments = []
            for n, centreline in enumerate(centrelines):
                regions = node_regions[n]
                path_segment = PathSegment(
                    regions[0],
                    centreline,
                    regions[1],
                    subdivision_parts=(1 if regions[0] is None else
                                       NUMBER_OF_BEZIER_PARTS))
                path_segments.append(path_segment)

            # And use them to set the control points for the path's centreline sheath
            for path_segment in path_segments:
                control_points = path_segment.control_points
                if len(self.__control_points[path_id]) == 0:
                    self.__control_points[path_id].append(control_points[0])
                self.__control_points[path_id].extend(control_points[1:])

            # The sheath starts and ends at the respective node centroids
            self.__control_points[path_id][0].set_position(
                path_segments[0].start_point)
            self.__control_points[path_id][-1].set_position(
                path_segments[-1].end_point)
Ejemplo n.º 31
0
  def clip(self,clip,cliptype):
    import pyclipper
    splitlist1 = []
    splitlist2 = []
    intersections = {}
    cloned = self.clone()
    clip = clip.clone()

    # Split all segments at intersections
    for s1 in self.asSegments():
      for s2 in clip.asSegments():
        for i in s1.intersections(s2):
          if i.t1 > 1e-8 and i.t1 < 1-1e-8:
            if i.seg1 == s1:
              splitlist1.append((i.seg1,i.t1))
              splitlist2.append((i.seg2,i.t2))
            else:
              splitlist2.append((i.seg1,i.t1))
              splitlist1.append((i.seg2,i.t2))
            intersections[i.point] = i

    logging.debug("Split list: %s" % splitlist1)
    logging.debug("Split list 2: %s" % splitlist2)
    cloned.splitAtPoints(splitlist1)
    clip.splitAtPoints(splitlist2)
    logging.debug("Self:")
    logging.debug(cloned.asSegments())
    logging.debug("Clip:")
    logging.debug(clip.asSegments())

    segs1unflattened = cloned.asSegments()
    segs2unflattened = clip.asSegments()

    # Replace with flattened versions, building a dictionary of originals
    segs1 = []
    reconstructionLUT = {}
    precision = 100.

    def fillLUT(flats):
      for line in flats:
        key = ((line.start * precision).rounded(), (line.end * precision).rounded())
        reconstructionLUT[key] = (line._orig or line)
        key2 = ((line.end * precision).rounded(), (line.start * precision).rounded())
        reconstructionLUT[key2] = (line._orig or line).reversed()

    for s in segs1unflattened:
      flats = s.flatten(2)
      fillLUT(flats)
      segs1.extend(flats)

    segs2 = []
    for s in segs2unflattened:
      flats = s.flatten(2)
      fillLUT(flats)
      segs2.extend(flats)

    # Leave it to the professionals
    subj = [(s[0].x*precision, s[0].y*precision) for s in segs1]
    clip = [(s[0].x*precision, s[0].y*precision) for s in segs2]
    pc = pyclipper.Pyclipper()
    pc.AddPath(clip, pyclipper.PT_CLIP, True)
    pc.AddPath(subj, pyclipper.PT_SUBJECT, True)
    paths = pc.Execute(cliptype, pyclipper.PFT_EVENODD, pyclipper.PFT_EVENODD)
    outpaths = []

    # Now reconstruct Bezier segments from flattened paths
    def pairwise(points):
      a = (p for p in points)
      b = (p for p in points)
      next(b)
      for curpoint,nextpoint in zip(a, b):
        yield curpoint, nextpoint

    newpaths = []
    from beziers.path import BezierPath
    for p in paths:
      newpath = []
      for scaledstart,scaledend in pairwise(p):
        key = (Point(*scaledstart), Point(*scaledend))
        if key in reconstructionLUT:
          orig = reconstructionLUT[key]
          if len(newpath) == 0 or newpath[-1] != orig:
            newpath.append(orig)
        else:
          newpath.append(Line(key[0]/precision, key[1]/precision))
      outpaths.append(BezierPath.fromSegments(newpath))
    return outpaths
Ejemplo n.º 32
0
    def test_representations(self):
        b = DotMap({
            "closed":
            True,
            "nodes": [{
                "x": 385.0,
                "y": 20.0,
                "type": "offcurve"
            }, {
                "x": 526.0,
                "y": 79.0,
                "type": "offcurve"
            }, {
                "x": 566.0,
                "y": 135.0,
                "type": "curve"
            }, {
                "x": 585.0,
                "y": 162.0,
                "type": "offcurve"
            }, {
                "x": 566.0,
                "y": 260.0,
                "type": "offcurve"
            }, {
                "x": 484.0,
                "y": 281.0,
                "type": "curve"
            }, {
                "x": 484.0,
                "y": 407.0,
                "type": "offcurve"
            }, {
                "x": 381.0,
                "y": 510.0,
                "type": "offcurve"
            }, {
                "x": 255.0,
                "y": 510.0,
                "type": "curve"
            }, {
                "x": 26.0,
                "y": 281.0,
                "type": "line"
            }, {
                "x": 26.0,
                "y": 155.0,
                "type": "offcurve"
            }, {
                "x": 129.0,
                "y": 20.0,
                "type": "offcurve"
            }, {
                "x": 255.0,
                "y": 20.0,
                "type": "curve"
            }]
        })

        path = BezierPath()
        path.activeRepresentation = GSPathRepresentation(path, b)
        nl = path.asNodelist()
        self.assertEqual(len(nl), 13)
        self.assertIsInstance(nl[1], Node)
        self.assertEqual(nl[1].type, "offcurve")
        self.assertAlmostEqual(nl[1].x, 526.0)

        segs = path.asSegments()
        self.assertEqual(len(segs), 5)
        self.assertIsInstance(segs[1], CubicBezier)
        self.assertIsInstance(segs[2], Line)