def linesPointAtEachother(linepair1, linepair2): ep1 = linepair1[1] ep2 = linepair2[1] pointsToRadius = max(15, 0.26 * GeomUtils.pointDistance(ep1.X, ep1.Y, ep2.X, ep2.Y) ) #Span out the valid radius at about 30 degrees l1_to_l2 = GeomUtils.linePointsTowards(linepair1[0], linepair1[1], linepair2[1], pointsToRadius) l2_to_l1 = GeomUtils.linePointsTowards(linepair2[0], linepair2[1], linepair1[1], pointsToRadius) ss_logger.debug("l1 points to l2: %s" % (l1_to_l2)) ss_logger.debug("l2 points to l1: %s" % (l2_to_l1)) return (l1_to_l2 and l2_to_l1)
def _matchHeadtoTail(self, head = None, tail = None, point = None): """Input head stroke or tail stroke. If head is specified, match it to a tail. If tail is specified, match it to a head. Parameter 'point' should be the tip if head is specified, the end-point if tail is specified. Returns a list of tuples: (tip, head_stroke) if tail is specified, (endpoint, tail_stroke) if head is specified.""" retlist = [] if point is None: return retlist if head is not None and tail is None: #Head is specified, find the tail tip = point ep1, ep2 = head.Points[0], head.Points[-1] headBreadth = GeomUtils.pointDistance(ep1.X, ep1.Y, ep2.X, ep2.Y) for endpoint, tailStroke in self._endpoints: if GeomUtils.strokeLength(head) < GeomUtils.strokeLength(tailStroke) \ and _isPointWithHead(endpoint, head, tip): #Make sure the proportions aren't totally off logger.debug("Head stroke has a tail close and within cone") pointingLength = len(tailStroke.Points) / 5 #headToTail if endpoint == tailStroke.Points[0]: linept1, linept2 = tailStroke.Points[pointingLength], endpoint elif endpoint== tailStroke.Points[-1]: linept1, linept2 = tailStroke.Points[-pointingLength], endpoint pointsTo = GeomUtils.linePointsTowards(linept1, linept2, tip, headBreadth) if pointsTo: retlist.append( (endpoint, tailStroke) ) elif tail is not None and head is None: #Find the head endpoint = point pointingLength = len(tail.Points) / 5 #headToTail if endpoint == tail.Points[0]: linept1, linept2 = tail.Points[pointingLength], endpoint elif endpoint== tail.Points[-1]: linept1, linept2 = tail.Points[-pointingLength], endpoint for tip, headStroke in self._arrowHeads: ep1, ep2 = headStroke.Points[0], headStroke.Points[-1] headBreadth = GeomUtils.pointDistance(ep1.X, ep1.Y, ep2.X, ep2.Y) if GeomUtils.strokeLength(headStroke) < GeomUtils.strokeLength(tail) \ and _isPointWithHead(endpoint, headStroke, tip): logger.debug("Tail stroke is close and within cone of an arrowhead") pointsTo = GeomUtils.linePointsTowards(linept1, linept2, tip, headBreadth) if pointsTo: retlist.append( (tip, headStroke) ) return retlist
def tipToNode( self, arrow_anno, circle_anno ): "return true if the tip of the arrow points to the circle" lineDist = min(10, max(len(arrow_anno.tailstroke.Points) / 10, 1)) #Check the last 10th of the stroke points the right way #lineseg: two points from arrow "neck" to arrowhead tip #lineseg2: two points from arrow "neck" to last point in tail stroke if arrow_anno.direction == "tail2head": lineSeg = ( arrow_anno.tailstroke.Points[-lineDist], arrow_anno.tip ) lineSeg2 = ( arrow_anno.tailstroke.Points[-lineDist], arrow_anno.tailstroke.Points[-1] ) else: #direction == 'head2tail' lineSeg = ( arrow_anno.tailstroke.Points[lineDist], arrow_anno.tip ) lineSeg2 = ( arrow_anno.tailstroke.Points[lineDist], arrow_anno.tailstroke.Points[0] ) if GeomUtils.pointDist( arrow_anno.tip, circle_anno.center ) < circle_anno.radius* DiGraphAnnotation.MATCHING_DISTANCE: if GeomUtils.linePointsTowards( lineSeg[0], lineSeg[1], circle_anno.center, circle_anno.radius * DiGraphAnnotation.POINTSTO_DISTANCE): return True if GeomUtils.linePointsTowards( lineSeg2[0], lineSeg2[1], circle_anno.center, circle_anno.radius * DiGraphAnnotation.POINTSTO_DISTANCE): return True return False
def tailToNode( self, arrow_anno, circle_anno ): "return true if the tail of the arrow comes from the circle" lineDist = max(len(arrow_anno.tailstroke.Points) / 10, 1) #Check the last 10th of the stroke points the right way if arrow_anno.direction == "tail2head": lineSeg = ( arrow_anno.tailstroke.Points[lineDist], arrow_anno.tailstroke.Points[0] ) else: #direction == 'head2tail' lineSeg = ( arrow_anno.tailstroke.Points[-lineDist], arrow_anno.tailstroke.Points[-1] ) if GeomUtils.pointDist( arrow_anno.tail, circle_anno.center ) < circle_anno.radius* DiGraphAnnotation.MATCHING_DISTANCE: if GeomUtils.linePointsTowards( lineSeg[0], lineSeg[1], circle_anno.center, circle_anno.radius * DiGraphAnnotation.POINTSTO_DISTANCE): return True return False
def _matchHeadtoTail(self, head = None, tail = None, point = None): """Input head stroke or tail stroke. If head is specified, match it to a tail. If tail is specified, match it to a head. Parameter 'point' should be the tip if head is specified, the end-point if tail is specified. Returns a list of tuples: (tip, head_stroke) if tail is specified, (endpoint, tail_stroke) if head is specified.""" retlist = [] if point is None: return retlist headStroke = head tailStroke = tail if headStroke is not None and tail is None: #Head is specified, find the tail tip = point ep1, ep2 = headStroke.Points[0], headStroke.Points[-1] headBreadth = GeomUtils.pointDistance(ep1.X, ep1.Y, ep2.X, ep2.Y) for endpoint, origStk, tailStroke in self._endpoints: pointingLength = len(tailStroke.Points) / 10 if endpoint == tailStroke.Points[0]: #Treat as drawn head2tail tailpoints = tailStroke.Points linept1, linept2 = tailStroke.Points[pointingLength], endpoint elif endpoint== tailStroke.Points[-1]: #Treat as drawn tail2head tailpoints = list(reversed(tailStroke.Points)) linept1, linept2 = tailStroke.Points[-(pointingLength+1)], endpoint headLen = GeomUtils.strokeLength(headStroke) tailLen = GeomUtils.strokeLength(tailStroke) pointWithHead = _isPointWithHead(tailpoints, headStroke, tip) if headLen < tailLen * 2 \ and pointWithHead: logger.debug("Head stroke has a tail close and within cone") #headToTail pointsTo = GeomUtils.linePointsTowards(linept1, linept2, tip, headBreadth) if pointsTo: logger.debug(" Tail points to head") retlist.append( (endpoint, origStk) ) else: logger.debug(" Tail does NOT point to head") else: if headLen < tailLen * 2: logger.debug(" Head stroke scale is okay for this arrowhead") else: logger.debug(" Head stroke scale is BAD for this arrowhead") logger.debug(" Head Len: %s, tail Len: %s" % (headLen, tailLen)) if not pointWithHead: logger.debug(" Head stroke is NOT close or within cone of an arrowhead\n") else: logger.debug(" Head stroke is close and within cone of an arrowhead\n") elif tailStroke is not None and headStroke is None: #Find the head endpoint = point pointingLength = len(tailStroke.Points) / 10 if endpoint == tailStroke.Points[0]: #Treat as drawn head2tail tailpoints = tailStroke.Points linept1, linept2 = tailStroke.Points[pointingLength], endpoint elif endpoint== tailStroke.Points[-1]: #Treat as drawn tail2head tailpoints = list(reversed(tailStroke.Points)) linept1, linept2 = tailStroke.Points[-pointingLength], endpoint for tip, origStk, headStroke in self._arrowHeads: ep1, ep2 = headStroke.Points[0], headStroke.Points[-1] headBreadth = GeomUtils.pointDistance(ep1.X, ep1.Y, ep2.X, ep2.Y) headLen = GeomUtils.strokeLength(headStroke) tailLen = GeomUtils.strokeLength(tailStroke) pointWithHead = _isPointWithHead(tailpoints, headStroke, tip) if headLen < tailLen * 2\ and pointWithHead: logger.debug("Tail stroke is close and within cone of an arrowhead") pointsTo = GeomUtils.linePointsTowards(linept1, linept2, tip, headBreadth) if pointsTo: logger.debug(" Tail points to head") retlist.append( (tip, origStk) ) else: logger.debug(" Tail does NOT point to head") else: if headLen < tailLen * 2: logger.debug(" Tail stroke scale is okay for this arrowhead") else: logger.debug(" Tail stroke scale is BAD for this arrowhead") logger.debug(" Head Len: %s, tail Len: %s" % (headLen, tailLen)) if not pointWithHead: logger.debug(" Tail stroke is NOT close or within cone of an arrowhead\n") else: logger.debug(" Tail stroke is close and within cone of an arrowhead\n") return retlist