Exemplo n.º 1
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()
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)])
Exemplo n.º 3
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)
Exemplo n.º 4
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
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])
Exemplo n.º 6
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
    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
Exemplo n.º 8
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
Exemplo n.º 9
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
Exemplo n.º 10
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)
Exemplo n.º 11
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
Exemplo n.º 12
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