Beispiel #1
0
def remove_degenerate_segments(path):
#This function removes any segment that starts and ends at the same point
    new_path = Path()
    for seg in path:
        if seg.start!=seg.end:
            new_path.append(seg)
    return new_path
Beispiel #2
0
    def saveSVG(self, fn):
        pathsCK = self.paths['ck']
        pathsLL0 = self.paths['ll0']

        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]))

        # C/K
        ck = Path(getSegment(pathsCK[0]), getSegment(pathsCK[1]),
                  getSegment(pathsCK[2]), getSegment(pathsCK[3]))

        # L/L0
        ll0 = Path(getSegment(pathsLL0[0]))

        paths = [ck, ll0]
        pathAttributes = {
            "stroke-width": self.width,
            "stroke": "#000",
            "fill": "#fff"
        }

        svg_attributes = {"viewBox": "0 0 600 600", "x": "0px", "y": "0px"}

        attributes = [pathAttributes, pathAttributes]
        wsvg(paths,
             attributes=attributes,
             svg_attributes=svg_attributes,
             filename=fn)
Beispiel #3
0
def extract_text_font(root, metadata_file):
    glyphcodes = get_text_names_to_codes(metadata_file)
    # (2) Output bounding box svg
    for glyph in glyphs:
        if glyph.attrib["glyph-name"] not in glyphcodes:
            continue
        # set glyph id
        g_element = ET.SubElement(root, "g")
        name = glyph.attrib["glyph-name"]
        glyph_code = glyphcodes[name]
        #glyph_code = name.split("uni")[-1]
        g_element.set("c", glyph_code)
        g_element.set("n", name)

        # set bounding box values if present
        if "d" in glyph.attrib:
            path = Path(glyph.attrib["d"])
            xmin, xmax, ymin, ymax = path.bbox()
            g_element.set("x", str(round(xmin, 2)))
            g_element.set("y", str(round(ymin, 2)))
            g_element.set("w", str(round(xmax - xmin, 2)))
            g_element.set("h", str(round(ymax - ymin, 2)))
        else:
            g_element.set("x", str(0.0))
            g_element.set("y", str(0.0))
            g_element.set("w", str(0.0))
            g_element.set("h", str(0.0))

        # set set horiz-av-x
        horiz_adv_x = glyph.attrib[
            "horiz-adv-x"] if "horiz-adv-x" in glyph.attrib else ""
        if horiz_adv_x:
            g_element.set("h-a-x", horiz_adv_x)

    return root
Beispiel #4
0
def test_jump_reduction():
    paths = []
    rect_width = 100
    rect_height = rect_width / 2
    for i in range(3):
        y_offset = rect_width*i*1j
        corners = [rect_height, rect_width+rect_height,
                   rect_width+rect_height + rect_height*1j,
                   rect_height*1j+ rect_height]
        corners = [c+y_offset for c in corners]
        lines = [Line(start=corners[j], end=corners[(j+1) % len(corners)])
                 for j in range(len(corners))]
        _path = Path(*lines)
        _path = _path.rotated(i*20)
        paths += list(_path)

    max_y = max([p.start.imag for p in paths]+[p.end.imag for p in paths])
    max_x = max([p.start.real for p in paths]+[p.end.real for p in paths])
    filename = "test_jump_reduction.svg"
    viewbox = [0, -rect_height, max_x+2*rect_height, max_y+2*rect_height]
    dwg = Drawing(filename, width="10cm",
                  viewBox=" ".join([str(b) for b in viewbox]))
    dwg.add(dwg.path(d=Path(*paths).d()))
    dwg.save()
    dig = Digitizer()
    dig.filecontents = open(filename, "r").read()
    dig.svg_to_pattern()
    pattern_to_svg(dig.pattern, join(filename + ".svg"))
Beispiel #5
0
    def d(self, useSandT=False, use_closed_attrib=False, rel=False):
        """Returns a path d-string for the path object.
        For an explanation of useSandT and use_closed_attrib, see the
        compatibility notes in the README."""

        segments = [s._segment for s in self._segments]
        path = Path(*segments)
        return path.d(useSandT, use_closed_attrib, rel)
 def fill_trap(self, paths, color="gray"):
     side = shorter_side(paths)
     shapes = [[Path(*paths), "none", "black"],
               [Path(*paths[side:side + 3]), color, "none"]]
     side2 = side + 2
     shapes = self.fill_shape(side, side2, paths, shapes)
     write_debug("fill", shapes)
     return side, side2
 def _remove_zero_length_lines(cls, paths):
     new_paths = []
     for path in paths:
         pp = list(filter(lambda x: x.start != x.end, path))
         newpath = Path()
         for p in pp:
             newpath.append(p)
         new_paths.append(newpath)
     return new_paths
Beispiel #8
0
 def boundingRect(self, k=None):
     if k is not None:
         return self[k].bbox()
     else:
         Ls = []
         for path in self.paths:
             if path:
                 Ls.extend(path._segments)
         P = SVGPath(*Ls)
         return P.bbox()
Beispiel #9
0
def extract_smufl_font(root, metadata_file):
    glyphnames = get_supported_glyph_codes()
    metadata = get_json_content(metadata_file)
    glyph_anchors = metadata[
        "glyphsWithAnchors"] if "glyphsWithAnchors" in metadata else ""
    # extract alternate glyphs and append them if any
    alternate_glyphs = get_alternate_glyphs(glyphnames, metadata)
    if bool(alternate_glyphs):
        glyphnames.update(alternate_glyphs)

    # (1) Create xml file for each glyph
    write_xml_glyphs(glyphnames)

    # (2) Output bounding box svg
    for glyph in glyphs:
        # set glyph id
        glyph_code = glyph.attrib["glyph-name"][-4:]
        if glyph_code not in glyphnames:
            continue
        g_element = ET.SubElement(root, "g")
        g_element.set("c", glyph_code)

        # set bounding box values if present
        if "d" in glyph.attrib:
            path = Path(glyph.attrib["d"])
            xmin, xmax, ymin, ymax = path.bbox()
            g_element.set("x", str(round(xmin, 2)))
            g_element.set("y", str(round(ymin, 2)))
            g_element.set("w", str(round(xmax - xmin, 2)))
            g_element.set("h", str(round(ymax - ymin, 2)))
        else:
            g_element.set("x", str(0.0))
            g_element.set("y", str(0.0))
            g_element.set("w", str(0.0))
            g_element.set("h", str(0.0))

        # set set horiz-av-x
        if "horiz-adv-x" in glyph.attrib:
            g_element.set("h-a-x", glyph.get("horiz-adv-x"))
            if not float(g_element.get("w")):
                g_element.set("w", glyph.get("horiz-adv-x"))

        # add glyph anchors if present for current glyph
        current_glyphname = glyphnames[
            glyph_code] if glyph_code in glyphnames else ""
        if current_glyphname:
            g_element.set("n", current_glyphname)
            if current_glyphname in glyph_anchors:
                for key, value in glyph_anchors[current_glyphname].items():
                    a_element = ET.SubElement(g_element, "a")
                    a_element.set("n", key)
                    a_element.set("x", str(round(value[0], 2)))
                    a_element.set("y", str(round(value[1], 2)))

    return root
Beispiel #10
0
class byA_Path(byA_FrozenClass):
    def __init__(self, *segments, **kw):
        byA_FrozenClass.__init__(self)
        self._segments = Path()
        for p in segments:
            assert isinstance(p, byA_Line) or isinstance(p, byA_CubicBezier)
            if isinstance(p, byA_Line):
                self.insert(-1, p)
            if isinstance(p, byA_CubicBezier):
                self.insert(-1, p)
        if 'closed' in kw:
            self._segments.closed = kw['closed']  # DEPRECATED
        self._freeze("byA_Path")

    def insert(self, index, value):
        assert isinstance(value, byA_Line) or isinstance(
            value, byA_CubicBezier)
        if isinstance(value, byA_Line):
            self._segments.insert(index, value._svgline)
        if isinstance(value, byA_CubicBezier):
            self._segments.insert(index, value._svgcubicbezier)

    def append(self, value):
        assert isinstance(value, byA_Line) or isinstance(
            value, byA_CubicBezier)
        if isinstance(value, byA_Line):
            self._segments.append(value._svgline)
        if isinstance(value, byA_CubicBezier):
            self._segments.append(value._cubicbezier)

    def toStr(self):
        return self._segments.d()
Beispiel #11
0
    def findMiddleOfConnectingPath(self):
        #creates path starting of end of down_ladder1, go to nearest (with t> t0) up-ladder or if no up-ladder then down_ladder at end and repeat until getting to bottom of down_ladder0
        maxIts = 1000 #### Tolerance
        traveled_path = Path()
        iters = 0
        (irORcr_new,T_new) = self.down_ladder1
        doneyet = False
        while iters < maxIts and not doneyet:
            iters =iters+ 1

#            ##DEBUG sd;fjadsfljkjl;
#            if self.ring.path[0].start == (260.778+153.954j):
#                from misc4rings import dis
#                from svgpathtools import Line
#                p2d=[self.completed_path,
#                     self.down_ladder0[0].ORring.path,
#                     self.down_ladder1[0].ORring.path]
#                clrs = ['blue','green','red']
#                if iters>1:
#                    p2d.append(Path(*traveled_path))
#                    clrs.append('black')
#                lad0a = self.down_ladder0[0].ORring.path.point(self.down_ladder0[1])
#                lad0b = self.ORring.path[0].start
#                lad0 = Line(lad0a,lad0b)
#                lad1a = self.ORring.path[-1].end
#                lad1b = self.down_ladder1[0].ORring.path.point(self.down_ladder1[1])
#                lad1 = Line(lad1a,lad1b)
#                dis(p2d,clrs,lines=[lad0,lad1])
#                print abs(lad0.start-lad0.end)
#                print abs(lad1.start-lad1.end)
#                bla=1
#            ##end of DEBUG sd;fjadsfljkjl;
            
            traveled_path_part, irORcr_new, T_new = self.followPathBackwards2LadderAndUpDown(irORcr_new, T_new)

            for seg in traveled_path_part:
                traveled_path.append(seg)

            if irORcr_new == self:
                return traveled_path
#            if irORcr_new == self.down_ladder0[0]:
#                doneyet = True
#                irORcr_new_path = irORcr_new.ORring.path
#                if T_new != self.down_ladder0[1]:
#                    for seg in reversePath(cropPath(irORcr_new_path,self.down_ladder0[1],T_new)):
#                        traveled_path.append(seg)
#                break
            if (irORcr_new, T_new) == self.down_ladder0:
                return traveled_path

            if iters >= maxIts-1:
                raise Exception("findMiddleOfConnectingPath reached maxIts")
        return traveled_path
Beispiel #12
0
 def __init__(self, *segments, **kw):
     byA_FrozenClass.__init__(self)
     self._segments = Path()
     for p in segments:
         assert isinstance(p, byA_Line) or isinstance(p, byA_CubicBezier)
         if isinstance(p, byA_Line):
             self.insert(-1, p)
         if isinstance(p, byA_CubicBezier):
             self.insert(-1, p)
     if 'closed' in kw:
         self._segments.closed = kw['closed']  # DEPRECATED
     self._freeze("byA_Path")
def test_stack_paths2():
    blo = Path(*[
        Line(start=0, end=100),
        Line(start=100, end=100 + 100j),
        Line(start=100 + 100j, end=100j),
        Line(start=100j, end=0)
    ])
    all_paths = [blo, blo.translated(110)]
    attributes = [{"fill": "black"}, {"fill": "black"}]

    all_paths_new, attributes_new = stack_paths(all_paths, attributes)
    assert all_paths == all_paths_new
    assert attributes_new == attributes
 def fill_triangle(self, paths, color="green"):
     triangle_sides = [
         paths[0], paths[1],
         Line(start=paths[2].start, end=paths[0].start)
     ]
     shapes = [[Path(*paths), "none", "black"],
               [Path(*triangle_sides), color, "none"]]
     lengths = [p.length() for p in triangle_sides]
     side1 = argmax(lengths)
     lengths[side1] = 0
     side2 = argmax(lengths)
     shapes = self.fill_shape(side1, side2, triangle_sides, shapes)
     write_debug("fill", shapes)
Beispiel #15
0
def splitSingleLine(start_end, unitLength, toPoint=False):
    '''
    return strings
    :param start_end:
    :param unitLength:
    :return:
    '''
    if UB.pointEquals(start_end[0], start_end[1]):
        return []
    pathStr = getStraightPath(start_end)
    path = parse_path(pathStr)
    try:
        l = path.length()
        if l > unitLength:
            paths = []
            t = unitLength / l
            ts = 0
            te = t
            for i in range(int(math.ceil(l / unitLength))):
                seg = Line(path.point(ts), path.point(te))
                p = Path(seg)
                if toPoint:
                    paths.append([
                        UB.getPointFromComplex(path.point(ts)),
                        UB.getPointFromComplex(path.point(te))
                    ])
                else:
                    paths.append(p.d())

                ts += t
                te += t
                te = min(1, te)
            if toPoint:
                paths.append([
                    UB.getPointFromComplex(path.point(te)),
                    UB.getPointFromComplex(path.point(1))
                ])
            else:
                paths.append(
                    getStraightPath([
                        UB.getPointFromComplex(path.point(te)),
                        UB.getPointFromComplex(path.point(1))
                    ]))
            return paths
        if toPoint:
            return [start_end]
        else:
            return [pathStr]
    except Exception as e:
        print(start_end, "something wrong with the splitLine", e)
        return []
Beispiel #16
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 add_outline_path(self,
                         paths,
                         width,
                         height,
                         radii=dict(bl=3, br=3, tl=3, tr=3),
                         type="path"):

        path = Path(*paths)

        self.outline.shape.height = height
        self.outline.shape.width = width
        self.outline.shape.radii = radii
        self.outline.shape.type = type
        self.outline.shape.value = absolute_to_relative_path(path.d())
Beispiel #18
0
def displaySVGPaths_transects_old(ringList,data_transects,transect_angles,filename): #creates and saves an svf file displaying the input paths
    import svgwrite
    transectPaths = []
    for tran_index in range(len(data_transects)):
        tran_path = Path()
        for seg_index in range(len(data_transects[tran_index])-1):
            start_pt = data_transects[tran_index][seg_index]
            end_pt = data_transects[tran_index][seg_index+1]
            tran_path.append(Line(start_pt,end_pt))
        transectPaths.append(tran_path)

    ringPaths = [r.path for r in ringList]
    ringColors = [r.color for r in ringList]
    pathList = ringPaths+transectPaths
    colors = ringColors + ['black']*len(transectPaths)
    transect_nodes = [item for sublist in data_transects for item in sublist] #flatten data_transects
    transect_nodes = [(z.real,z.imag) for z in transect_nodes]
    center = ringList[0].center
    center = (center.real,center.imag)

    dwg = svgwrite.Drawing(filename+'_transects.svg',size=('2000px','2000px'),viewBox="0 0 2000 2000")
    dwg.add(dwg.rect(insert=(0, 0), size=('100%', '100%'), rx=None, ry=None, fill='white')) #add white background
    for i,p in enumerate(pathList):
        if isinstance(p,Path):
            ps = path2str(p)
        elif isinstance(p,Line) or isinstance(p,CubicBezier):
            ps = path2str(Path(p))
        else:
            ps = p
        dwg.add(dwg.path(ps, stroke=colors[i], fill='none'))
    #add a purple dot whenever a transect crosses a ring
    for pt in transect_nodes:
        dwg.add(dwg.circle(pt,1, stroke='purple', fill='purple'))
    #add a blue dot at the core/center of the sample
    dwg.add(dwg.circle(center,2, stroke='blue', fill='blue'))
    #add text giving angle in radians/2pi (so in [0,1]) at the end of each transect
    for k,theta in enumerate(transect_angles):
        try:
            if len(data_transects[k])>1:
                paragraph = dwg.add(dwg.g(font_size=14))
                n_vec = data_transects[k][-1]-data_transects[k][-2]
                n_vec = n_vec/abs(n_vec)
                text_coords = 10*n_vec + data_transects[k][-1]
                text_coords = (text_coords.real,text_coords.imag)
                paragraph.add(dwg.text('%.3f'%theta, text_coords))
            else:
                print('Skipping degenerate transect at angle %s'%theta)
        except:
            print('Skipping problemsome transect at angle %s'%theta)
    dwg.save()
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 #20
0
    def transform_side(sides, targets, angle_offset=0):
        def angle(point1, point2):
            diff = point1 - point2
            if diff.real == 0:
                return 90.0
            return atan(diff.imag / diff.real) * 180.0 / pi

        # change this so that it has two targets
        transformed_side = Path(*sides)
        source_angle = angle(transformed_side.end, transformed_side.start) - \
                       angle(targets[0], targets[1])
        transformed_side = transformed_side.rotated(-source_angle +
                                                    angle_offset)
        source = transformed_side.end if angle_offset == 0 else transformed_side.start
        diff = targets[1] - source
        transformed_side = transformed_side.translated(diff)
        draw_marker(targets[0], rgb(0, 200, 200))
        draw_marker(targets[1], rgb(0, 255, 255))
        transformed_diff = abs(transformed_side.start - transformed_side.end)
        targets_diff = abs(targets[0] - targets[1])
        if transformed_diff < targets_diff:
            transformed_side.insert(
                0, Line(start=targets[0], end=transformed_side.start))
        elif transformed_diff > targets_diff:
            # pop elements off until the transformed diff is smaller
            while transformed_diff > targets_diff:
                transformed_side.pop(0)
                transformed_diff = abs(transformed_side.start -
                                       transformed_side.end)
            print("path", transformed_side)
            print("path is longer", transformed_diff - targets_diff)
        return transformed_side
 def replace_point(self, ptbefore, ptafter):
     pathstr = self._g.elements[0].tostring()
     pathstr = pathstr.split('"')[3]
     pathbefore = parse_path(pathstr)
     pathafter = Path()
     for i in pathbefore:
         if isinstance(i, Line):
             if (isclose(i.start.real, ptbefore._x)
                     and isclose(i.start.imag, ptbefore._y)):
                 i.start = ptafter._x + 1j * ptafter._y
             if (isclose(i.end.real, ptbefore._x)
                     and isclose(i.end.imag, ptbefore._y)):
                 i.end = ptafter._x + 1j * ptafter._y
         pathafter.append(i)
     self.add(svgwrite.path.Path(d=pathafter.d()))
Beispiel #22
0
def pattern_to_svg(pattern, filename):
    if isinstance(filename, str) or isinstance(filename, unicode):
        output_file = open(filename, "wb")
    else:
        output_file = filename
    paths = []
    colors = []
    scale_factor = 0.1  # scale from cm to mm from pes
    for block in pattern.blocks:
        block_paths = []
        last_stitch = None
        for stitch in block.stitches:
            if "JUMP" in stitch.tags:
                last_stitch = stitch
                continue
            if last_stitch is None:
                last_stitch = stitch
                continue
            block_paths.append(
                Line(start=last_stitch.complex * scale_factor,
                     end=stitch.complex * scale_factor))
            last_stitch = stitch
        if len(block_paths) > 0:
            colors.append(block.tuple_color)
            paths.append(Path(*block_paths))
    dims = overall_bbox(paths)
    mindim = max(dims[1] - dims[0], dims[3] - dims[2])
    print("in pattern to svg, overallbbox", overall_bbox(paths))
    if len(paths) == 0:
        print("warning: pattern did not generate stitches")
        return
    wsvg(paths, colors, filename=output_file, mindim=mindim)
def path_difference_shapely(path1, path2):
    try:
        poly1 = path_to_poly(path1)
    except (IndexError, ValueError) as e:
        return path1
    if not poly1.is_valid or not path2.closed:
        # output the shape to a debug file
        # write_debug("invalid1", [[shape_to_path(poly1), "black", "none"]])
        return path1

    poly2 = path_to_poly(path2)
    if not poly2.is_valid:
        # output the shape to a debug file
        # write_debug("invalid2", [[shape_to_path(poly2), "black", "none"]])
        return path1
    diff_poly = poly1.difference(poly2)
    if isinstance(diff_poly, Polygon):
        new_path = shape_to_path(diff_poly)
    elif isinstance(diff_poly, GeometryCollection) or isinstance(
            diff_poly, MultiPolygon):
        new_path = []
        for shape in diff_poly:
            # line objects have a length but no area
            new_path += shape_to_path(shape)
    else:
        print("not sure what to do with type:", type(diff_poly))
    # make a new path from these points
    return Path(*new_path)
Beispiel #24
0
    def initialize(self):
        current_grid = defaultdict(dict)
        # simplify paths to lines
        poly_paths = []
        for path in self.paths:
            if path.length() > MINIMUM_STITCH_LENGTH:
                num_segments = ceil(path.length() / MINIMUM_STITCH_LENGTH)
                for seg_i in range(int(num_segments)):
                    poly_paths.append(Line(start=path.point(seg_i/num_segments), end=path.point((seg_i+1)/num_segments)))
            else:
                poly_paths.append(Line(start=path.start, end=path.end))
        bbox = overall_bbox(self.paths)
        curr_x = int(bbox[0]/MINIMUM_STITCH_LENGTH)*MINIMUM_STITCH_LENGTH
        total_tests = int(bbox[1]-bbox[0])*int(bbox[3]-bbox[2])/(MINIMUM_STITCH_LENGTH*MINIMUM_STITCH_LENGTH)
        while curr_x < bbox[1]:
            curr_y = int(bbox[2]/MINIMUM_STITCH_LENGTH)*MINIMUM_STITCH_LENGTH

            while curr_y < bbox[3]:
                test_line = Line(start=curr_x + curr_y * 1j,
                                 end=curr_x + MINIMUM_STITCH_LENGTH + (
                                                               curr_y + MINIMUM_STITCH_LENGTH) * 1j)
                start = time()
                is_contained = path1_is_contained_in_path2(test_line, Path(*poly_paths))
                end = time()
                if is_contained:
                    current_grid[curr_x][curr_y] = False
                curr_y += MINIMUM_STITCH_LENGTH
            curr_x += MINIMUM_STITCH_LENGTH
        self.current_grid = current_grid
Beispiel #25
0
def transform_path(transform, path):
    if isinstance(path, str):
        return transform_path_string(transform, path)
    # if not a string, it's probably a Path object
    segments = path._segments
    for segment in segments:
        if isinstance(segment, CubicBezier):
            segment.start = transform_point(segment.start,
                                            matrix=transform,
                                            format="complex")
            segment.end = transform_point(segment.end,
                                          matrix=transform,
                                          format="complex")
            segment.control1 = transform_point(segment.control1,
                                               matrix=transform,
                                               format="complex")
            segment.control2 = transform_point(segment.control2,
                                               matrix=transform,
                                               format="complex")
        elif isinstance(segment, Line):
            segment.start = transform_point(segment.start,
                                            matrix=transform,
                                            format="complex")

            segment.end = transform_point(segment.end,
                                          matrix=transform,
                                          format="complex")
        else:
            raise ValueError("not sure how to handle {}".format(type(segment)))
    return Path(*segments)
    def cross_stitch_to_pattern(self, _image):
        # this doesn't work well for images with more than 2-3 colors
        max_dimension = max(_image.size)
        pixel_ratio = int(max_dimension * MINIMUM_STITCH_LENGTH / (4 * 25.4))
        if pixel_ratio != 0:
            _image = _image.resize(
                (_image.size[0] / pixel_ratio, _image.size[1] / pixel_ratio))
        pixels = posturize(_image)

        paths = []
        attrs = []

        for color in pixels:
            for pixel in pixels[color]:
                rgb = "#%02x%02x%02x" % (pixel[2][0], pixel[2][1], pixel[2][2])
                x = pixel[0]
                y = pixel[1]
                attrs.append({"fill": "none", "stroke": rgb})
                paths.append(
                    Path(
                        Line(start=x + 1j * y,
                             end=x + 0.5 * MINIMUM_STITCH_LENGTH + 1j *
                             (y + MINIMUM_STITCH_LENGTH))))
        debug_paths = [[path, attrs[i]["fill"], attrs[i]["stroke"]]
                       for i, path in enumerate(paths)]
        write_debug("png", debug_paths)
        self.all_paths = paths
        self.attributes = attrs
        self.scale = 1.0
        self.generate_pattern()
Beispiel #27
0
def flip_path(upside_down_path):
    path = []
    _, _, min_y, max_y = upside_down_path.bbox()
    offset = max_y + min_y
    for segment in upside_down_path._segments:
        if type(segment) is Line:
            path.append(
                Line(complex(segment.start.real, -segment.start.imag + offset),
                     complex(segment.end.real, -segment.end.imag + offset)))
        elif type(segment) is Arc:
            path.append(
                Arc(complex(segment.start.real,
                            -segment.start.imag + offset), segment.radius,
                    abs(180 - segment.rotation), segment.large_arc,
                    not segment.sweep,
                    complex(segment.end.real, -segment.end.imag + offset)))
        elif type(segment) is QuadraticBezier:
            path.append(
                QuadraticBezier(
                    complex(segment.start.real, -segment.start.imag + offset),
                    complex(segment.control.real,
                            -segment.control.imag + offset),
                    complex(segment.end.real, -segment.end.imag + offset)))
        else:
            raise ValueError(f"Unknown type: {type(segment)}")

    return Path(*path)
Beispiel #28
0
    def save_points_as_svg_handler(points, size, image_number):
        # filename like file:///home/gdshen/Pictures/00000.jpg
        filename = os.path.join(project_path, svg_dir, image_number + '.svg')
        paths = []
        for i in range(size):
            start_point_x = points.property(i).property('startPoint').property(
                'X').toInt()
            start_point_y = points.property(i).property('startPoint').property(
                'Y').toInt()
            control_point_x = points.property(i).property(
                'controlPoint').property('X').toInt()
            control_point_y = points.property(i).property(
                'controlPoint').property('Y').toInt()
            target_point_x = points.property(i).property(
                'targetPoint').property('X').toInt()
            target_point_y = points.property(i).property(
                'targetPoint').property('Y').toInt()
            print(start_point_x, start_point_y, control_point_x,
                  control_point_y, target_point_x, target_point_y)
            paths.append(
                Path(
                    QuadraticBezier(complex(start_point_x, start_point_y),
                                    complex(control_point_x, control_point_y),
                                    complex(target_point_x, target_point_y))))

        wsvg(paths=paths, filename=filename)
Beispiel #29
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 #30
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
Beispiel #31
0
def test_generate_straight_stroke():
    dig = Digitizer()
    paths = [Path(*[Line(start=0, end=100), Line(start=100, end=100 + 100j),
                    Line(start=100 + 100j, end=100j), Line(start=100j, end=0)])]
    dig.stroke_color = (0, 0, 0)
    dig.scale = 1.0
    dig.generate_straight_stroke(paths)
    assert len(dig.stitches) > len(paths)
    def add_route(self,
                  paths,
                  layer='bottom',
                  stroke_width=0.4,
                  style="stroke",
                  type="path"):

        path = Path(*paths)

        self._add_route_to_layer(
            {
                "stroke-width": stroke_width,
                "style": style,
                "type": type,
                "value": absolute_to_relative_path(path.d())
            },
            layer=layer)
Beispiel #33
0
def displaySVGPaths_transects(ring_list, data_transects, transect_angles, skipped_angle_indices, fn=None):
    if not fn:
        filename = opt.output_directory + ring_list[0].svgname
    else:
        filename = fn

    transectPaths = []
    for tran_index in range(len(data_transects)):
        tran_path = Path()
        for seg_index in range(len(data_transects[tran_index]) - 1):
            start_pt = data_transects[tran_index][seg_index]
            end_pt = data_transects[tran_index][seg_index + 1]
            tran_path.append(Line(start_pt,end_pt))
        transectPaths.append(tran_path)

    ringPaths = [r.path for r in ring_list]
    ringColors = [r.color for r in ring_list]
    pathList = ringPaths + transectPaths
    colors = ringColors + ['black']*len(transectPaths)
    transect_nodes = [item for sublist in data_transects for item in sublist] # flatten data_transects
    nodes = transect_nodes + [ring_list[0].center]
    node_colors = ['purple']*len(transect_nodes) + ['blue']
    text = ['%.3f' % theta for idx, theta in enumerate(transect_angles)
            if idx not in skipped_angle_indices]
    text += ['skipped %.3f' % transect_angles[idx]
             for idx in skipped_angle_indices]
    text_path = []
    for tr in data_transects:
        end = tr[-1]
        last_seg = Line(tr[-2], tr[-1])
        u = last_seg.unit_tangent(1)
        text_path.append(Path(Line(end + 10*u, end + 100*u)))

    # handle skipped transects
    bdry_ring = max(ring_list, key=lambda ring: ring.maxR)
    bdry_length = bdry_ring.path.length()
    for idx in skipped_angle_indices:
        s = bdry_length * transect_angles[idx]
        T = inv_arclength(bdry_ring.path,  s)
        u = bdry_ring.path.normal(T)
        end = bdry_ring.path.point(T)
        text_path.append(Line(end + 10*u, end + 100*u))

    wsvg(pathList, colors, nodes=nodes, node_colors=node_colors, text=text,
         text_path=text_path, filename=filename+'_transects.svg')
Beispiel #34
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 #35
0
def printPath(path):
    """Prints path in a nice way.  path should be a Path, CubicBezier, Line, or
        list of CubicBezier objects and Line objects."""
    if not isinstance(path, Path):
        if isinstance(path, Line) or isinstance(path, CubicBezier):
            path = Path(path)
        elif all([isinstance(seg, Line) or isinstance(seg, CubicBezier) for seg
                  in path]):
            path = Path(*path)
        else:
            print "This path is not a path... and is neither a Line object nor a CubicBezier object."
            return
    try:
        path[0]
    except IndexError:
        print "This path seems to be empty."
        return

    output_string = ""

    for seg_index_, seg in enumerate(path):
        if seg_index_ != 0:
            output_string += "\n"
        if isinstance(seg, CubicBezier):
            tmp = []
            for z in cubPoints(seg):
                tmp += [z.real, z.imag]
            nicePts = "(%.1f + i%.1f, %.1f + i%.1f, %.1f + i%.1f, %.1f + i%.1f)" % tuple(
                tmp)
            output_string += "[%s] - CubicBezier: " % seg_index_ + nicePts
        elif isinstance(seg, Line):
            nicePts = "(%.1f + i%.1f, %.1f + i%.1f)" % (
            seg.start.real, seg.start.imag, seg.end.real, seg.end.imag,)
            output_string += "[%s] - Line       : " % seg_index_ + nicePts
        else:
            print("+" * 50)
            print(seg)
            raise Exception("This path contains a segment that is neither a Line nor a CubicBezier.")
    if path[0].start == path[-1].end:
        closure = "Closed"
    else:
        closure = "Open  "
    output_string += "\n" + "[*] " + closure + " : |path.point(0) - path.point(1)| = %s" % abs(
        path.point(0) - path.point(1))
    print(output_string)
Beispiel #36
0
 def __init__(self, ring):
     self.ring = ring
     self.innerCR_ring = None
     self.outerCR_ring = None
     self.completed_path = Path()
     self.overlap0 = False #This is related to a deprecated piece of code and must be False.
     self.overlap1 = False #This is related to a deprecated piece of code and must be False.
     self.corrected_start = None #set in case of overlap (point, seg,t) where seg is a segment in self and seg(t)=point
     self.corrected_end = None #set in case of overlap (point, seg,t) where seg is a segment in self and seg(t)=point
     self.ir_start = self.ring.point(0)
     self.ir_end = self.ring.point(1)
     self.up_ladders = []
     self.down_ladder0 = None #(irORcr0,T0) ~ startpoint down-ladder on this ir and (and T-val on connecting ring it connects at - irORcr0 can be incompleteRing object or completeRing object)
     self.down_ladder1 = None
     self.transect0fails = [] #records IRs are "below" self, but failed to provide a transect to self.ir_start
     self.transect1fails = [] #records IRs are "below" self, but failed to provide a transect to self.ir_end
     self.transect0found = False
     self.transect1found = False
     self.isCore = False
     self.ORring = self.ring
Beispiel #37
0
    def followPathBackwards2LadderAndUpDown(self, irORcr, T0):
        """irORcr is the path being followed, self is the IR to be completed
        returns (traveled_path,irORcr_new,t_new) made from the part of irORcr's
        path before T0 (and after ladder) plus the line from ladder (the first
        one that is encountered)"""
        rds = remove_degenerate_segments
        irORcr_path = irORcr.ORring.path
        thetaprekey = Theta_Tstar(T0)
        thetakey = lambda lad: thetaprekey.distfcn(lad[1])
        sorted_upLadders = sorted(irORcr.up_ladders, key=thetakey)

        if isinstance(irORcr, CompleteRing):
            ir_new, T = sorted_upLadders[0]
            if T != T0:
                reversed_path_followed = reversePath(cropPath(irORcr_path, T, T0))
            else:  # this happens when up and down ladder are at same location
                reversed_path_followed = Path()

            # add the ladder to reversed_path_followed
            if (irORcr, T) == ir_new.down_ladder0:
                if not ir_new.overlap0:
                    ladder = Line(irORcr_path.point(T), ir_new.irpoint(0))
                    reversed_path_followed.append(ladder)
                    T_ir_new = 0
                else:
                    T_ir_new = segt2PathT(ir_new.ring.path,
                                          ir_new.corrected_start[1],
                                          ir_new.corrected_start[2])
            elif (irORcr, T) == ir_new.down_ladder1:
                if not ir_new.overlap1:
                    ladder = Line(irORcr_path.point(T), ir_new.irpoint(1))
                    reversed_path_followed.append(ladder)
                    T_ir_new = 1
                else:
                    T_ir_new = segt2PathT(ir_new.ring.path,
                                          ir_new.corrected_end[1],
                                          ir_new.corrected_end[2])
            else:
                raise Exception("this case shouldn't be reached, mistake in "
                                "logic or didn't set downladder somewhere.")
            return rds(reversed_path_followed), ir_new, T_ir_new

        else:  # current ring to follow to ladder is incomplete ring
            irORcr_path = irORcr.ring.path
            for ir_new, T in sorted_upLadders:
                if T < T0:  # Note: always following path backwards
                    reversed_path_followed = irORcr_path.cropped(T, T0).reversed()
                    if (irORcr, T) == ir_new.down_ladder0:

                        if not ir_new.overlap0:
                            ladder = Line(irORcr_path.point(T), ir_new.irpoint(0))
                            reversed_path_followed.append(ladder)
                            T_ir_new = 0
                        else:
                            T_ir_new = segt2PathT(ir_new.ring.path,
                                                  ir_new.corrected_start[1],
                                                  ir_new.corrected_start[2])
                    elif (irORcr, T) == ir_new.down_ladder1:
                        if not ir_new.overlap1:
                            ladder = Line(irORcr_path.point(T), ir_new.irpoint(1))
                            reversed_path_followed.append(ladder)
                            T_ir_new = 1
                        else:
                            T_ir_new = segt2PathT(ir_new.ring.path,
                                                  ir_new.corrected_end[1],
                                                  ir_new.corrected_end[2])
                    else:
                        tmp_mes = ("this case shouldn't be reached, mistake "
                                   "in logic or didn't set downladder "
                                   "somewhere.")
                        raise Exception(tmp_mes)

                    return rds(reversed_path_followed), ir_new, T_ir_new

            # none of the upladder were between 0 and T0,
            # so use downladder at 0
            else:
                (irORcr_new, T_new) = irORcr.down_ladder0
                irORcr_new_path = irORcr_new.ORring.path

                ###Should T0==0 ever?
                if T0 != 0:
                    reversed_path_followed = irORcr.ring.path.cropped(0, T0).reversed()
                else:
                    reversed_path_followed = Path()

                if irORcr.overlap0 == False:
                    ladder = Line(irORcr_path.point(0), irORcr_new_path.point(T_new))
                    reversed_path_followed.append(ladder)
                return rds(reversed_path_followed), irORcr_new, T_new
Beispiel #38
0
def cropPath(path, T0, T1):  ###TOL uses isclose
    #    path = parse_path(path2str(path)) ###DEBUG (maybe can remove if speed demands it)
    if T1 == 1:
        seg1 = path[-1]
        t_seg1 = 1
        i1 = len(path) - 1
    else:
        (t_seg1, seg1) = pathT2tseg(path, T1)
        if isclose(t_seg1, 0):
            i1 = (seg_index(path, seg1) - 1) % len(path)
            seg1 = path[i1]
            t_seg1 = 1
        else:
            i1 = seg_index(path, seg1)
    if T0 == 0:
        seg0 = path[0]
        t_seg0 = 0
        i0 = 0
    else:
        (t_seg0, seg0) = pathT2tseg(path, T0)
        if isclose(t_seg0, 1):
            i0 = (seg_index(path, seg0) + 1) % len(path)
            seg0 = path[i0]
            t_seg0 = 0
        else:
            i0 = seg_index(path, seg0)

    if T0 < T1 and i0 == i1:
        new_path = Path(trimSeg(seg0, t_seg0, t_seg1))
    else:
        new_path = Path(trimSeg(seg0, t_seg0, 1))
        if T1 == T0:
            raise Exception("T0=T1 in cropPath.")
        elif T1 < T0:  # T1<T0 must cross discontinuity case
            if not path.isclosed():
                raise Exception(
                    "T1<T0 and path is open.  I think that means you put in the wrong T values.")
            else:
                for i in range(i0 + 1, len(path)):
                    new_path.append(path[i])
                for i in range(0, i1):
                    new_path.append(path[i])
        else:  # T0<T1 straight-forward case
            for i in range(i0 + 1, i1):
                new_path.append(path[i])

        if t_seg1 != 0:
            new_path.append(trimSeg(seg1, 0, t_seg1))

    # ####check this path is put together properly DEBUG ONLY
    # #check end
    # path_at_T1 = path.point(T1)
    # if new_path[-1].end != path_at_T1:
    #     if isNear(new_path[-1].end,path_at_T1):
    #         new_path[-1].end = path_at_T1
    #     else:
    #         raise Exception("Cropped path doesn't end where it should.")
    # #check start
    # path_at_T0 = path.point(T0)
    # if new_path[0].start != path_at_T0:
    #     if isNear(new_path[0].start, path_at_T0):
    #         new_path[0].start = path_at_T0
    #     else:
    #         raise Exception("Cropped path doesn't start where it should.")
    # #check inner joints
    # for i in range(len(new_path)-1):
    #     if new_path[i].end != new_path[i+1].start:
    #         if isNear(new_path[i].end, new_path[i+1].start):
    #             new_path[i].end = new_path[i+1].start
    #         else:
    #             raise Exception("Cropped path doesn't start where it should.")
    return new_path
Beispiel #39
0
class IncompleteRing(object):
    def __init__(self, ring):
        self.ring = ring
        self.innerCR_ring = None
        self.outerCR_ring = None
        self.completed_path = Path()
        self.overlap0 = False #This is related to a deprecated piece of code and must be False.
        self.overlap1 = False #This is related to a deprecated piece of code and must be False.
        self.corrected_start = None #set in case of overlap (point, seg,t) where seg is a segment in self and seg(t)=point
        self.corrected_end = None #set in case of overlap (point, seg,t) where seg is a segment in self and seg(t)=point
        self.ir_start = self.ring.point(0)
        self.ir_end = self.ring.point(1)
        self.up_ladders = []
        self.down_ladder0 = None #(irORcr0,T0) ~ startpoint down-ladder on this ir and (and T-val on connecting ring it connects at - irORcr0 can be incompleteRing object or completeRing object)
        self.down_ladder1 = None
        self.transect0fails = [] #records IRs are "below" self, but failed to provide a transect to self.ir_start
        self.transect1fails = [] #records IRs are "below" self, but failed to provide a transect to self.ir_end
        self.transect0found = False
        self.transect1found = False
        self.isCore = False
        self.ORring = self.ring

#    def __repr__(self):
#        return '<IncompleteRing based on ring = %s>' %self.ring
    def __eq__(self, other):
        if not isinstance(other, IncompleteRing):
            return NotImplemented
        if self.ring != other.ring:
            return False
        return True
    def __ne__(self, other):
        if not isinstance(other, CompleteRing):
            return NotImplemented
        return not self == other

    def set_inner(self, ring):
        self.innerCR_ring = ring
    def set_outer(self, ring):
        self.outerCR_ring = ring

    def sortUpLadders(self):
        self.up_ladders = sortby(self.up_ladders,1)
        self.up_ladders.reverse()

# this as my newer cleaned up version, but I broke it i think (7-19-16)
    # def addSegsToCP(self, segs, tol_closure=opt.tol_isApproxClosedPath):
    #     """input a list of segments to append to self.completed_path
    #     this function will stop adding segs if a seg endpoint is near the
    #     completed_path startpoint"""
    #     if len(segs)==0:
    #         raise Exception("No segs given to insert")
    #
    #     # Iterate through segs to check if segments join together nicely
    #     # and (fix them if need be and) append them to completed_path
    #     for seg in segs:
    #         # This block checks if cp is (nearly) closed.
    #         # If so, closes it with a Line, and returns the fcn
    #         if len(self.completed_path)!=0:
    #             cp_start, cp_end = self.completed_path[0].start, self.completed_path[-1].end
    #             if abs(cp_start - cp_end) < tol_closure:
    #                 if cp_start==cp_end:
    #                 # then do nothing else and return
    #                     return
    #                 else:
    #                 # then close completed_path with a line and return
    #                     self.completed_path.append(Line(cp_start, cp_end))
    #                     return
    #
    #             elif seg.start != self.completed_path[-1].end:
    #                 # then seg does not start at the end of completed_path,
    #                 # fix it then add it on
    #                 current_endpoint = self.completed_path[-1].end
    #                 if abs(seg.start - current_endpoint) <  tol_closure:
    #                     # then seg is slightly off from current end of
    #                     # completed_path, fix seg and insert it into
    #                     # completed_path
    #                     if isinstance(seg, CubicBezier):
    #                         P0, P1, P2, P3 = seg.bpoints()
    #                         newseg = CubicBezier(current_endpoint, P1, P2, P3)
    #                     elif isinstance(seg, Line):
    #                         newseg = Line(current_endpoint, seg.end)
    #                     else:
    #                         raise Exception('Path segment is neither Line '
    #                                         'object nor CubicBezier object.')
    #                     self.completed_path.insert(len(self.completed_path), newseg)
    #                 else:
    #                     raise Exception("Segment being added to path does not "
    #                                     "start at path endpoint.")
    #             else:
    #                 # then seg does not need to be fixed, so go ahead and insert it
    #                 self.completed_path.insert(len(self.completed_path), seg)

    def addSegsToCP(self, segs, tol_closure=opt.tol_isApproxClosedPath):
    #input a list of segments to append to self.completed_path
    #this function will stop adding segs if a seg endpoint is near the completed_path startpoint
        if len(segs)==0:
            raise Exception("No segs given to insert")

        #Iterate through segs to check if segments join together nicely
        #and (fix them if need be and) append them to completed_path
        for seg in segs:
            #This block checks if cp is (nearly) closed.
            #If so, closes it with a Line, and returns the fcn
            if len(self.completed_path)!=0:
                cp_start, cp_end = self.completed_path[0].start, self.completed_path[-1].end
                if abs(cp_start - cp_end) < tol_closure:
                    if cp_start==cp_end:
                    #then do nothing else and return
                        return
                    else:
                    #then close completed_path with a line and return
                        self.completed_path.append(Line(cp_start,cp_end))
                        return

            if len(self.completed_path)!=0 and seg.start != self.completed_path[-1].end:
            #then seg does not start at the end of completed_path, fix it then add it on
                current_endpoint = self.completed_path[-1].end
                if abs(seg.start - current_endpoint) <  tol_closure:
                #then seg is slightly off from current end of completed_path, fix seg and insert it into completed_path
                    if isinstance(seg,CubicBezier):
                        P0,P1,P2,P3 = cubPoints(seg)
                        newseg = CubicBezier(current_endpoint,P1,P2,P3)
                    elif isinstance(seg,Line):
                        newseg = Line(current_endpoint,seg.end)
                    else:
                        raise Exception('Path segment is neither Line object nor CubicBezier object.')
                    self.completed_path.insert(len(self.completed_path),newseg)
                else:
                    raise Exception("Segment being added to path does not start at path endpoint.")
            else:
            #then seg does not need to be fixed, so go ahead and insert it
                self.completed_path.insert(len(self.completed_path),seg)

    def addConnectingPathToCP(self, connecting_path, seg0, t0, seg1, t1):
        # first find orientation by checking whether t0 is closer to start or end.
        T0, T1 = segt2PathT(connecting_path, seg0, t0), segt2PathT(connecting_path, seg1, t1)
        i0, i1 = connecting_path.index(seg0), connecting_path.index(seg1)
        first_seg = reverseSeg(trimSeg(seg1, 0, t1))
        last_seg = reverseSeg(trimSeg(seg0, t0, 1))

        if T0 > T1:  # discontinuity between intersection points
            if isApproxClosedPath(connecting_path):
                middle_segs = [reverseSeg(connecting_path[i1-i]) for i in range(1, (i1-i0) % len(connecting_path))]
            else:
                raise Exception("ir jumps another ir's gap.  This case is not "
                                "implimented yet")
        elif T0 < T1:  # discontinuity NOT between intersection points
            middle_segs = [reverseSeg(connecting_path[i1+i0-i]) for i in range(i0 + 1, i1)]
        else:
            raise Exception("T0=T1, this means there's a bug in either "
                            "pathXpathIntersections fcn or "
                            "trimAndAddTransectsBeforeCompletion fcn")

        # first seg
        if isDegenerateSegment(first_seg):
            tmpSeg = copyobject(middle_segs.pop(0))
            tmpSeg.start = first_seg.start
            first_seg = tmpSeg
        if first_seg.end == self.completed_path[0].start:
            self.completed_path.insert(0,first_seg)
        else:
            printPath(first_seg)
            printPath(last_seg)
            printPath(connecting_path)
            raise Exception("first_seg is set up wrongly")

        # middle segs
        self.addSegsToCP(middle_segs)

        # last seg
        if isDegenerateSegment(last_seg):
            middle_segs[-1].end = last_seg.end
        else:
            self.addSegsToCP([last_seg])

    def trimAndAddTransectsBeforeCompletion(self):

        # Retrieve transect endpoints if necessary
        (irORcr0, T0), (irORcr1, T1) = self.down_ladder0, self.down_ladder1
        tr0_start_pt = irORcr0.ORring.point(T0)
        tr1_end_pt = irORcr1.ORring.point(T1)

        if not self.overlap0:
            # then no overlap at start, add transect0 to beginning of
            # connected path (before the ir itself)
            i0 = -1
            startSeg = Line(tr0_start_pt, self.ir_start)
        else:
            # overlap at start, trim the first seg in the ir (don't connect
            # anything, just trim)
            i0 = self.ring.path.index(self.corrected_start[1])
            startSeg = trimSeg(self.corrected_start[1], self.corrected_start[2],1)
        if not self.overlap1:
            # then no overlap at end to add transect1 to connected path
            # (append to end of the ir)
            i1 = len(self.ring.path)
            endSeg = Line(self.ir_end, tr1_end_pt)
        else:
            # overlap at end, trim the last seg in the ir (don't connect
            # anything, just trim)
            i1 = self.ring.path.index(self.corrected_end[1])
            endSeg = trimSeg(self.corrected_end[1], 0, self.corrected_end[2])

        # first seg
        if isDegenerateSegment(startSeg):
            tmpSeg = copyobject(self.ring.path[i0 + 1])
            tmpSeg.start = startSeg.start
            startSeg = tmpSeg
            i0 += 1
            self.addSegsToCP([startSeg])
        else:
            self.addSegsToCP([startSeg])

        # middle segs
        if i0 + 1 != i1:
            self.addSegsToCP([self.ring.path[i] for i in range(i0+1, i1)])

        # last seg
        if isDegenerateSegment(endSeg):
            self.completed_path[-1].end = endSeg.end
        else:
            self.addSegsToCP([endSeg])

    def irpoint(self, pos):
        return self.ring.point(pos)

    def area(self):
        if not isinstance(self.completed_path,Path):
            return "Fail"
        if (self.completed_path is None or not isApproxClosedPath(self.completed_path)):
            # raise Exception("completed_path not complete.  Distance between start and end: %s"%abs(self.completed_path.point(0) - self.completed_path.point(1)))
            return "Fail"
        return areaEnclosed(self.completed_path)

    def type(self, colordict):
        for (key, val) in colordict.items():
            if self.ring.color == val:
                return key
        else:
            raise Exception("Incomplete Ring color not in colordict... you shouldn't have gotten this far.  Bug detected.")

#    def info(self,cp_index):
#    ###### "complete ring index, complete?, inner BrookID, outer BrookID, inner color, outer color, area, area Ignoring IRs, averageRadius, minR, maxR, IRs contained"
#        return str(cp_index) + "," + "Incomplete"+"," + "N/A" + ", " + self.ring.brook_tag + "," + "N/A" + ", " + self.ring.color +"," + str(self.area()) +", "+ "N/A"+","+str(self.ring.aveR())+","+str(self.ring.minR)+","+str(self.ring.maxR)+","+"N/A"

    def info(self, cp_index, colordict):
        ###### "complete ring index, type, # of IRs contained, minR, maxR, aveR, area, area Ignoring IRs"
        return str(cp_index)+","+self.type(colordict)+","+"N/A"+","+str(self.ring.minR)+","+ str(self.ring.maxR)+","+str(self.ring.aveR())+","+str(self.area())+","+"N/A"

    def followPathBackwards2LadderAndUpDown(self, irORcr, T0):
        """irORcr is the path being followed, self is the IR to be completed
        returns (traveled_path,irORcr_new,t_new) made from the part of irORcr's
        path before T0 (and after ladder) plus the line from ladder (the first
        one that is encountered)"""
        rds = remove_degenerate_segments
        irORcr_path = irORcr.ORring.path
        thetaprekey = Theta_Tstar(T0)
        thetakey = lambda lad: thetaprekey.distfcn(lad[1])
        sorted_upLadders = sorted(irORcr.up_ladders, key=thetakey)

        if isinstance(irORcr, CompleteRing):
            ir_new, T = sorted_upLadders[0]
            if T != T0:
                reversed_path_followed = reversePath(cropPath(irORcr_path, T, T0))
            else:  # this happens when up and down ladder are at same location
                reversed_path_followed = Path()

            # add the ladder to reversed_path_followed
            if (irORcr, T) == ir_new.down_ladder0:
                if not ir_new.overlap0:
                    ladder = Line(irORcr_path.point(T), ir_new.irpoint(0))
                    reversed_path_followed.append(ladder)
                    T_ir_new = 0
                else:
                    T_ir_new = segt2PathT(ir_new.ring.path,
                                          ir_new.corrected_start[1],
                                          ir_new.corrected_start[2])
            elif (irORcr, T) == ir_new.down_ladder1:
                if not ir_new.overlap1:
                    ladder = Line(irORcr_path.point(T), ir_new.irpoint(1))
                    reversed_path_followed.append(ladder)
                    T_ir_new = 1
                else:
                    T_ir_new = segt2PathT(ir_new.ring.path,
                                          ir_new.corrected_end[1],
                                          ir_new.corrected_end[2])
            else:
                raise Exception("this case shouldn't be reached, mistake in "
                                "logic or didn't set downladder somewhere.")
            return rds(reversed_path_followed), ir_new, T_ir_new

        else:  # current ring to follow to ladder is incomplete ring
            irORcr_path = irORcr.ring.path
            for ir_new, T in sorted_upLadders:
                if T < T0:  # Note: always following path backwards
                    reversed_path_followed = irORcr_path.cropped(T, T0).reversed()
                    if (irORcr, T) == ir_new.down_ladder0:

                        if not ir_new.overlap0:
                            ladder = Line(irORcr_path.point(T), ir_new.irpoint(0))
                            reversed_path_followed.append(ladder)
                            T_ir_new = 0
                        else:
                            T_ir_new = segt2PathT(ir_new.ring.path,
                                                  ir_new.corrected_start[1],
                                                  ir_new.corrected_start[2])
                    elif (irORcr, T) == ir_new.down_ladder1:
                        if not ir_new.overlap1:
                            ladder = Line(irORcr_path.point(T), ir_new.irpoint(1))
                            reversed_path_followed.append(ladder)
                            T_ir_new = 1
                        else:
                            T_ir_new = segt2PathT(ir_new.ring.path,
                                                  ir_new.corrected_end[1],
                                                  ir_new.corrected_end[2])
                    else:
                        tmp_mes = ("this case shouldn't be reached, mistake "
                                   "in logic or didn't set downladder "
                                   "somewhere.")
                        raise Exception(tmp_mes)

                    return rds(reversed_path_followed), ir_new, T_ir_new

            # none of the upladder were between 0 and T0,
            # so use downladder at 0
            else:
                (irORcr_new, T_new) = irORcr.down_ladder0
                irORcr_new_path = irORcr_new.ORring.path

                ###Should T0==0 ever?
                if T0 != 0:
                    reversed_path_followed = irORcr.ring.path.cropped(0, T0).reversed()
                else:
                    reversed_path_followed = Path()

                if irORcr.overlap0 == False:
                    ladder = Line(irORcr_path.point(0), irORcr_new_path.point(T_new))
                    reversed_path_followed.append(ladder)
                return rds(reversed_path_followed), irORcr_new, T_new

    def findMiddleOfConnectingPath(self):
        #creates path starting of end of down_ladder1, go to nearest (with t> t0) up-ladder or if no up-ladder then down_ladder at end and repeat until getting to bottom of down_ladder0
        maxIts = 1000 #### Tolerance
        traveled_path = Path()
        iters = 0
        (irORcr_new,T_new) = self.down_ladder1
        doneyet = False
        while iters < maxIts and not doneyet:
            iters =iters+ 1

#            ##DEBUG sd;fjadsfljkjl;
#            if self.ring.path[0].start == (260.778+153.954j):
#                from misc4rings import dis
#                from svgpathtools import Line
#                p2d=[self.completed_path,
#                     self.down_ladder0[0].ORring.path,
#                     self.down_ladder1[0].ORring.path]
#                clrs = ['blue','green','red']
#                if iters>1:
#                    p2d.append(Path(*traveled_path))
#                    clrs.append('black')
#                lad0a = self.down_ladder0[0].ORring.path.point(self.down_ladder0[1])
#                lad0b = self.ORring.path[0].start
#                lad0 = Line(lad0a,lad0b)
#                lad1a = self.ORring.path[-1].end
#                lad1b = self.down_ladder1[0].ORring.path.point(self.down_ladder1[1])
#                lad1 = Line(lad1a,lad1b)
#                dis(p2d,clrs,lines=[lad0,lad1])
#                print abs(lad0.start-lad0.end)
#                print abs(lad1.start-lad1.end)
#                bla=1
#            ##end of DEBUG sd;fjadsfljkjl;
            
            traveled_path_part, irORcr_new, T_new = self.followPathBackwards2LadderAndUpDown(irORcr_new, T_new)

            for seg in traveled_path_part:
                traveled_path.append(seg)

            if irORcr_new == self:
                return traveled_path
#            if irORcr_new == self.down_ladder0[0]:
#                doneyet = True
#                irORcr_new_path = irORcr_new.ORring.path
#                if T_new != self.down_ladder0[1]:
#                    for seg in reversePath(cropPath(irORcr_new_path,self.down_ladder0[1],T_new)):
#                        traveled_path.append(seg)
#                break
            if (irORcr_new, T_new) == self.down_ladder0:
                return traveled_path

            if iters >= maxIts-1:
                raise Exception("findMiddleOfConnectingPath reached maxIts")
        return traveled_path

    def hardComplete(self, tol_closure=opt.tol_isApproxClosedPath):
        self.trimAndAddTransectsBeforeCompletion()
        meatOf_connecting_path = self.findMiddleOfConnectingPath()  ###this is a Path object
        self.addSegsToCP(meatOf_connecting_path)
        cp_start,cp_end = self.completed_path[0].start, self.completed_path[-1].end

        #check newly finished connecting_path is closed
        if abs(cp_start - cp_end) >= tol_closure:
            raise Exception("Connecting path should be finished but is not closed.")

        #test for weird .point() bug where .point(1) != end
        if (abs(cp_start - self.completed_path.point(0)) >= tol_closure or
            abs(cp_end - self.completed_path.point(1)) >= tol_closure):
            self.completed_path = parse_path(path2str(self.completed_path))
            raise Exception("weird .point() bug where .point(1) != end... I just added this check in on 3-5-15, so maybe if this happens it doesn't even matter.  Try removing this code-block... or change svgpathtools.Path.point() method to return one or the other.")

    def findTransect2endpointFromInnerPath_normal(self,irORcr_innerPath,innerPath,T_range,Tpf,endBin):
        #Tpf: If The T0 transect intersects self and the T1 does not, then Tpf should be True, otherwise it should be false.
        #Note: If this endpoint's transect is already found, then this function returns (False,False,False,False)
        #Returns: (irORcr,nL,seg_irORcr,t_irORcr) where irORcr is the inner path that the transect, nL, leaves from and seg_irORcr and t_irORcr correspond to innerPath and nL points from seg_irORcr.point(t_irORcr) to the desired endpoint
        #Note: irORcr will differ from irORcr_innerPath in the case where irORcr_innerPath admits a transect but this transect intersects with a (less-inner) previously failed path.  The less-inner path is then output.
        (T0,T1) = T_range
        if T1<T0:
            if T1==0:
                T1=1
            else:
                Exception("I don't think T_range should ever have T0>T1.  Check over findTransect2endpointsFromInnerPath_normal to see if this is acceptable.")

        if endBin == 0 and self.transect0found:
            return False, False, False, False
        elif endBin == 1 and self.transect1found:
             return False, False, False, False
        elif endBin not in {0,1}:
            raise Exception("endBin not a binary - so there is a typo somewhere when calling this fcn")

        if irORcr_innerPath.isCore:
            return irORcr_innerPath, Line(irORcr_innerPath.inner.path.point(0), self.irpoint(endBin)), irORcr_innerPath.inner.path[0], 0  # make transect from center (actually path.point(0)) to the endpoint

        maxIts = 100 ##### tolerance
        its = 0
        while (abs(innerPath.point(T0) - innerPath.point(T1)) >= opt.tol_isApproxClosedPath
               and its <= maxIts):
            its += 1
            T = float((T0+T1))/2
            center = self.ring.center
            nL = normalLineAtT_toInner_intersects_withOuter(T,innerPath,self.ring.path,center)[0] #check if transect from innerPath.point(T) intersects with outerPath
            if Tpf: #p x f
                if nL != False:  #p p f
                    T0 = T
                else: #p f f
                    T1 = T
            else: #f x p
                if nL != False: #f p p
                    T1 = T
                else: #f f p
                    T0 = T
#            ###DEBUG asdfkljhjdkdjjjdkkk
#            if self.ORring.point(0)==(296.238+285.506j):
#                from misc4rings import dis
#                print "endBin=%s\nT0=%s\nT=%s\nT1=%s\n"%(endBin,T0,T,T1)
#                if isNear(innerPath.point(T0),innerPath.point(T1)):
#                    print "Exit Criterion Met!!!"
#                    if nL==False:
#                        nLtmp = normalLineAtT_toInner_intersects_withOuter(T,innerPath,self.ring.path,center,'debug')[0]
#                    else:
#                        nLtmp = nL
#                    dis([innerPath,self.ring.path,Path(nLtmp)],['green','red','blue'],nodes=[center,innerPath.point(T0),innerPath.point(T1)],node_colors=['blue','green','red'])
#                    bla=1
#            ###end of DEBUG asdfkljhjdkdjjjdkkk
            if its>=maxIts:
                raise Exception("while loop for finding transect by bisection reached maxIts without terminating")
        if nL != False: #x p x
            t_inner, seg_inner = pathT2tseg(innerPath, T)
        else: #x f x
            if Tpf: #p f f
                nL = normalLineAtT_toInner_intersects_withOuter(T0,innerPath,self.ring.path,center)[0]
                (t_inner,seg_inner) = pathT2tseg(innerPath,T0)
            else: #f f p
                nL = normalLineAtT_toInner_intersects_withOuter(T1,innerPath,self.ring.path,center)[0]
                (t_inner,seg_inner) = pathT2tseg(innerPath,T1)
        transect_info = (irORcr_innerPath,nL,seg_inner,t_inner)

        ###Important Note: check that transect does not go through any other rings while headed to its target endpoint (Andy has note explaining this "7th case")
        ###If this intersection does happen... just cut off the line at the intersection point - this leads to transect not being normal to the ring it emanates from.
        if endBin == 0:
            failed_IRs_2check = self.transect0fails
        else:
            failed_IRs_2check = self.transect1fails
        keyfcn = lambda x: x.ORring.sort_index
        failed_IRs_2check = sorted(failed_IRs_2check,key=keyfcn)
        tr_line = transect_info[1]
        exclusions = [] #used to check the line from closest_pt to endpoint doesn't intersect
        num_passed = 0
        run_again = True
        while run_again:
            run_again = False
            for idx,fIR in enumerate(failed_IRs_2check):
                num_passed +=1
                if idx in exclusions:
                    continue
                intersectionList = pathXpathIntersections(Path(tr_line),fIR.ring.path)
                if len(intersectionList) == 0:
                    continue
                else:
                    if len(intersectionList) > 1:
                        print("Warning: Transect-FailedPath intersection check returned multiple intersections.  This is possible, but should be very rare.")
    #                (seg_tl, seg_fIR, t_tl, t_fIR) = intersectionList[0]
                    t_fIR,seg_fIR = closestPointInPath(self.ORring.point(endBin),fIR.ring.path)[1:3]
                    fIR_closest_pt = seg_fIR.point(t_fIR)
                    if endBin:
                        new_nonNormal_transect = Line(self.ring.path[-1].end,fIR_closest_pt)
                    else:
                        new_nonNormal_transect = Line(fIR_closest_pt,self.ring.path[0].start)
                    transect_info = (fIR,new_nonNormal_transect,seg_fIR,t_fIR)
                    exclusions += range(idx+1)
                    run_again = True
                    break
        return transect_info

    def findTransects2endpointsFromInnerPath_normal(self,irORcr_innerPath,innerPath):
        """Finds transects to both endpoints (not just that specified by
        endBin - see outdated description below)
        Note: This fcn will attempt to find transects for endpoints where the
        transects have not been found and will return (False, False, False)
        for those that have.
        Returns: (irORcr,nL,seg_irORcr,t_irORcr) where irORcr is the inner
        path that the transect, nL, leaves from and seg_irORcr and t_irORcr
        correspond to innerPath and nL points from seg_irORcr.point(t_irORcr)
        to the desired endpoint.
        Note: irORcr will differ from irORcr_innerPath in the case where
        irORcr_innerPath admits a transect but this transect intersects with a
        (less-inner) previously failed path.  The less-inner path is then
        output."""
        #Outdated Instructions
        #This fcn is meant to find the transect line from (and normal to) the
        # inner path that goes through OuterPt.  It does this using the
        # bisection method.
        #INPUT: innerPath and outerPath are Path objects, center is a point
        # representing the core, endBin specifies which end point in outerPath
        # we hope to find the transect headed towards (so must be a 0 or a 1)
        #OUTPUT: Returns (transect_Line,inner_seg,inner_t) where normal_line
        # is the transverse Line object normal to innerPath intersecting
        # outerPath at outerPt or, if such a line does not exist, returns
        # (False,False,False,False)
        # inner_seg is the segment of innerPath that this normal transect line
        # begins at, s.t. seg.point(inner_t) = transect_Line.point(0)

        outerPath = self.ring.path
        center = self.ring.center

        tol_numberDetectionLines_transectLine_normal = 20 ##### tolerance
        N = tol_numberDetectionLines_transectLine_normal

#        if self.transect0found and not self.transect1found:
#            return (False,False,False,False), self.findTransect2endpointFromInnerPath_normal(innerPath)
#        if not self.transect0found and self.transect1found:
#            return self.findTransect2endpoint0FromInnerPath_normal(innerPath), (False,False,False,False)
#        if self.transect0found and self.transect1found:
#            raise Exception("Both transects already found... this is a bug.")

        # For a visual explanation of the following code block and the six
        # cases, see Andy's "Gap Analysis of Transects to Endpoints"

        # check if transect from innerPath.point(0) intersect with outerPath
        nL_from0, seg_from0, t_from0 = normalLineAtT_toInner_intersects_withOuter(0, innerPath, outerPath, center)
        if isApproxClosedPath(innerPath):
            (nL_from1,seg_from1,t_from1) = (nL_from0,seg_from0,t_from0)
        else:
            #check if transect from innerPath.point(1) intersect with outerPath
            nL_from1, seg_from1, t_from1 = normalLineAtT_toInner_intersects_withOuter(1, innerPath, outerPath, center)
        #Case: TF
        if nL_from0 and not nL_from1:
            return (False,False,False,False), self.findTransect2endpointFromInnerPath_normal(irORcr_innerPath,innerPath,(0,1),True,1)
        #Case: FT
        if (not nL_from0) and nL_from1:
            return self.findTransect2endpointFromInnerPath_normal(irORcr_innerPath,innerPath,(0,1),False,0), (False,False,False,False)

        # determine All, None, or Some (see notes in notebook on this agorithm
        # for explanation)
        max_pass_Tk = 0
        min_pass_Tk = 1
        max_fail_Tk = 0
        min_fail_Tk = 1
        somePass = False
        someFail = False
        dT = float(1)/(N-1)
        for k in range(1,N-1):
            Tk = k*dT
            nLk, outer_segk, outer_tk = normalLineAtT_toInner_intersects_withOuter(Tk, innerPath, outerPath, center)
            if nLk != False:
                somePass = True
                if Tk > max_pass_Tk:
                    max_pass_Tk = Tk
#                    max_pass = (nLk,outer_segk,outer_tk)
                if Tk < min_pass_Tk:
                    min_pass_Tk = Tk
#                    min_pass = (nLk,outer_segk,outer_tk)
            else:
                someFail = True
                if Tk > max_fail_Tk:
                    max_fail_Tk = Tk
#                    max_fail = (nLk,outer_segk,outer_tk)
                if Tk < min_fail_Tk:
                    min_fail_Tk = Tk
#                    min_fail = (nLk,outer_segk,outer_tk)

        if somePass and someFail:
            #Case: TT & only some pass    [note: TT & some iff TT & T0>T1]
            if nL_from0 and nL_from1:
                Trange0 = (max_fail_Tk, (max_fail_Tk + dT)%1)
                Tpf0 = False
                Trange1 = ((min_fail_Tk - dT)%1, min_fail_Tk)
                Tpf1 = True
            #Case: FF & only some pass
            elif (not nL_from0) and (not nL_from1):
                Trange0 = ((min_pass_Tk - dT)%1, min_pass_Tk)
                Tpf0 = False
                Trange1 = (max_pass_Tk, (max_pass_Tk + dT)%1)
                Tpf1 = True
            for Ttestindex,T2test in enumerate(Trange0 + Trange1): #debugging only
                if T2test>1 or T2test < 0:
                    print Ttestindex
                    print T2test
                    raise Exception()
            args = irORcr_innerPath, innerPath, Trange0, Tpf0, 0
            tmp1 = self.findTransect2endpointFromInnerPath_normal(*args)
            args = irORcr_innerPath, innerPath, Trange1, Tpf1, 1
            tmp2 = self.findTransect2endpointFromInnerPath_normal(*args)
            return tmp1, tmp2
        #Cases: (TT & all) or (FF & none)    [note: TT & all iff TT & T0<T1]
        else:
            return (False, False, False, False), (False, False, False, False)