def onAnnotationSuggested(self, anno_type, strokelist): """Called when the a list of strokes are suggested to yield an annotation of type anno_type.""" #First pass, assume we were just too strict with the distance/size thresholds knownHeads = [] knownTails = [] for tip, stk in self._arrowHeads: if stk in strokelist: knownHeads.append( (tip, stk) ) for ep, tail_stk in self._endpoints: if tail_stk in strokelist: for tip, head_stk in knownHeads: if head_stk == tail_stk: continue headEnds = ( head_stk.Points[0], head_stk.Points[-1] ) if GeomUtils.pointInAngleCone(ep, headEnds[0], tip, headEnds[1]): anno = ArrowAnnotation( tip, ep, headstroke= head_stk, tailstroke = tail_stk ) self.getBoard().AnnotateStrokes([head_stk, tail_stk],anno) logger.debug("Suggestion Response: Matched arrow with looser constraints") return #Second pass, we missed the arrowhead to begin with logger.warn("Not able to generate Arrow!") return
def _isPointWithHead(point, head, tip): "Returns true if point is close enough and within the cone of the head stroke" distanceThresh = 1 distanceThresh *= distanceThresh #Keep up with squared distances ep1 = head.Points[0] ep2 = head.Points[-1] # * tip # o o # o o # o o # o (x) o # midpoint # # * endpoint # o # o # o # (etc) midpoint = Point((ep1.X + ep2.X)/2, (ep1.Y + ep2.Y)/2) #Mid-way between the two endpoints of the arrowhead tip_to_endpoint = GeomUtils.pointDistanceSquared(point.X, point.Y, tip.X, tip.Y) tip_to_backofarrowhead = GeomUtils.pointDistanceSquared(tip.X, tip.Y, midpoint.X, midpoint.Y) endpoint_to_backofarrowhead = GeomUtils.pointDistanceSquared(point.X, point.Y, midpoint.X, midpoint.Y) #logger.debug("tip_to_endpoint: %s\n, tip_to_backofarrowhead: %s,\n endpoint_to_backofarrowhead: %s" % (tip_to_endpoint, tip_to_backofarrowhead, endpoint_to_backofarrowhead)) #Tail's endpoint is close to the end of the arrowhead, or even closer to the tip of the arrowhead if tip_to_backofarrowhead >= endpoint_to_backofarrowhead or tip_to_backofarrowhead >= tip_to_endpoint: if GeomUtils.pointInAngleCone(point, ep1, tip, ep2): return True return False
def _isPointWithHead(point, head, tip): "Returns true if point is close enough and within the cone of the head stroke" ep1 = head.Points[0] ep2 = head.Points[-1] midpoint = Point((ep1.X + ep2.X)/2, (ep1.Y + ep2.Y)/2) tip_to_endpoint = GeomUtils.pointDistanceSquared(point.X, point.Y, tip.X, tip.Y) tip_to_backofarrowhead = GeomUtils.pointDistanceSquared(tip.X, tip.Y, midpoint.X, midpoint.Y) if tip_to_endpoint < tip_to_backofarrowhead: if GeomUtils.pointInAngleCone(point, ep1, tip, ep2): return True return False
def _isPointWithHead(tailpoints, head, tip): "Returns true if point is close enough and within the cone of the head stroke" distanceThresh = 1 distanceThresh *= distanceThresh #Keep up with squared distances point = tailpoints[0] ep1 = head.Points[0] ep2 = head.Points[-1] # * tip # o o # o o # o o # o (x) o # midpoint # # * endpoint # o # o # o # (etc) midpoint = Point((ep1.X + ep2.X)/2, (ep1.Y + ep2.Y)/2) #Mid-way between the two endpoints of the arrowhead tip_to_endpoint = GeomUtils.pointDistanceSquared(point.X, point.Y, tip.X, tip.Y) tip_to_backofarrowhead = GeomUtils.pointDistanceSquared(tip.X, tip.Y, midpoint.X, midpoint.Y) endpoint_to_backofarrowhead = GeomUtils.pointDistanceSquared(point.X, point.Y, midpoint.X, midpoint.Y) #fuzz = math.sqrt(tip_to_backofarrowhead) #Number of pixels to fuzz the "in-angle-cone" test #logger.debug("tip_to_endpoint: %s\n, tip_to_backofarrowhead: %s,\n endpoint_to_backofarrowhead: %s" % (tip_to_endpoint, tip_to_backofarrowhead, endpoint_to_backofarrowhead)) #Tail's endpoint is close to the end of the arrowhead, or even closer to the tip of the arrowhead if tip_to_backofarrowhead >= endpoint_to_backofarrowhead or tip_to_backofarrowhead >= tip_to_endpoint: logger.debug("Distance from head-tip to tail-endpoint is good!") #Check the in-angle cone progressively down the tail epList = tailpoints[: len(tailpoints) / 3] for pt in epList: if GeomUtils.pointInAngleCone(pt, ep1, tip, ep2): logger.debug("Endpoint inside angle cone") return True return False