Exemple #1
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
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()
Exemple #3
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)