示例#1
0
def _scoreStroke(stroke, template, sample_size = None):
    
    if sample_size is None:
        sample_size = len(template)
        
    sNorm = GeomUtils.strokeNormalizeSpacing(stroke, len(template))
    centr = GeomUtils.centroid(sNorm.Points)
    numPoints = len(sNorm.Points)
    
    point_vect = []
    templ_vect = []

    numPoints = len(template)
    if len(template) == len(sNorm.Points):
        for idx in range(0, numPoints, numPoints/sample_size ):
            templ_vect.append(template[idx].X)
            templ_vect.append(template[idx].Y)
            
            p = sNorm.Points[idx]
            point_vect.append(p.X - centr.X)
            point_vect.append(p.Y - centr.Y)
       
        angularDist = GeomUtils.vectorDistance(point_vect, templ_vect)
    else:
        angularDist = math.pi
    return angularDist
示例#2
0
    def drawAnno(self, a):
        bbox = GeomUtils.strokelistBoundingBox(a.Strokes)
        gui = self.getBoard().getGUI()
        drawBox = False
        if drawBox:  # Draw the logical box
            minScale = 20
            heights = [s.BoundTopLeft.Y - s.BoundBottomRight.Y for s in a.Strokes]
            bb_from = GeomUtils.strokelistBoundingBox(a.Strokes)
            from_scale = max(minScale, heights[len(heights) / 2])
#            from_scale = max(minScale, sum(heights)/float(len(heights)))
            tl = Point (bb_from[0].X - from_scale, bb_from[0].Y + from_scale / 2)
            br = Point (bb_from[1].X + from_scale, bb_from[1].Y - from_scale / 2)
            bb_from = (tl, br)
            gui.drawBox(tl, br, color="#FFFFFF")

        visLogger.debug("Drawing Anno: {}".format(a.latex))
        if a.latex and len(a.latex) > 0:
            try:
                if hasattr(gui, 'drawBitmap'):
                    if a.latex not in self._cachedPixbuf:
                        self._cachedPixbuf[a.latex] = pixbufFromLatex(a.latex)

                    pixbuf = self._cachedPixbuf[a.latex]
                    gui.drawBitmap(bbox[1].X, bbox[1].Y, pixbuf=pixbuf)
                else:
                    gui.drawText(bbox[1].X, bbox[1].Y, a.latex)
            except Exception as e:
                print "Cannot draw equation {}: {}".format(a.latex, e)
    def onStrokeAdded( self, stroke ):
        #If it's a closed figure, it is its own wall
        rtm_logger.debug("Stroke Added")
        newWallDict = {'closed': False, 'matches': {}}
        ep1 = stroke.Points[0]
        ep2 = stroke.Points[-1]
        strokeLen = GeomUtils.strokeLength(stroke)

        addToWalls = True
        if GeomUtils.pointDistanceSquared(ep1.X, ep1.Y, ep2.X, ep2.Y) < (strokeLen  * 0.05) ** 2:
            rtm_logger.debug("Closed stroke")
            newWallDict['closed'] = True

        rtm_logger.debug("Adding stroke as possible future wall")
        self.wallInfo[stroke] = newWallDict
        #self.linkStrokesTogether()

        for testStroke, wallDict in self.wallInfo.items():
            gran = min(len(stroke.Points), len(testStroke.Points))
            if wallDict['closed'] and GeomUtils.strokeContainsStroke(testStroke, stroke, granularity = gran):
                outStk = testStroke
                inStk = stroke
            elif newWallDict['closed'] and GeomUtils.strokeContainsStroke(stroke, testStroke, granularity = gran):
                outStk = stroke
                inStk = testStroke
            else:
                continue

            rtm_logger.debug("Found containment with another stroke")
            rtAnno = RaceTrackAnnotation(rightwalls = [outStk], leftwalls = [inStk]) 
            BoardSingleton().AnnotateStrokes([stroke, testStroke], rtAnno)
            del(self.wallInfo[testStroke])
            addToWalls = False
            break
示例#4
0
    def merg(self, to_anno, from_anno):

        bb_from = GeomUtils.strokelistBoundingBox( from_anno.Strokes )
        center_from = Point( (bb_from[0].X + bb_from[1].X) / 2.0, (bb_from[0].Y + bb_from[1].Y) / 2.0)
        tl = Point (center_from.X - from_anno.scale/ 2.0, center_from.Y + (from_anno.scale / 2.0) )
        br = Point (center_from.X + from_anno.scale/ 2.0, center_from.Y - (from_anno.scale / 2.0) )
        bb_from = (tl, br)

        bb_to = GeomUtils.strokelistBoundingBox( to_anno.Strokes )
        center_to = Point( (bb_to[0].X + bb_to[1].X) / 2.0, (bb_to[0].Y + bb_to[1].Y) / 2.0)
        tl = Point (center_to.X - to_anno.scale/ 2.0, center_to.Y + (to_anno.scale / 2.0) )
        br = Point (center_to.X + to_anno.scale/ 2.0, center_to.Y - (to_anno.scale / 2.0) )
        bb_to = (tl, br)

        if bb_from[0].X - bb_to[0].X > 0 :
            outText = to_anno.text + from_anno.text
        else :
            outText = from_anno.text + to_anno.text

        #Weight the scale per letter
        to_anno.scale = ( to_anno.scale * len(to_anno.text) + from_anno.scale * len(from_anno.text) )\
                        / float(len(to_anno.text) + len(from_anno.text))
        tc_logger.debug("MERGED: %s and %s to %s" % (to_anno.text, from_anno.text, outText))
        to_anno.text = outText
        to_anno.alternates = []

        return True
    def onStrokeAdded( self, stroke ):
        "Compare this stroke to all templates, and annotate those matching within some threshold."
        logger.debug("Scoring stroke")
        #strokeVector = ( len(stroke.Points), GeomUtils.pointListOrientationHistogram(GeomUtils.strokeNormalizeSpacing(stroke, numpoints = len(stroke.Points) / 3.0).Points) )
        strokeVector = generateFeatureVector(stroke)
        logger.debug("Stroke Vector: %s" % (str(strokeVector)))
        if self._matchVector == None:
            self._matchVector = strokeVector
        else:
            bb1 = GeomUtils.strokelistBoundingBox([stroke])
            for prevStk in self._features.keys():
                bb2 = GeomUtils.strokelistBoundingBox([prevStk])
                if GeomUtils.boundingboxOverlap(bb1, bb2):
                    self.overlaps.setdefault(stroke, set()).add(prevStk)
                    self.overlaps.setdefault(prevStk, set()).add(stroke)
            self._features[stroke] = strokeVector
            score = scoreVector(self._matchVector, strokeVector)
            logger.debug("  Distance %s from baseline" % (score) )
            if score < 0.02:
                self.getBoard().AnnotateStrokes([stroke], MultiStrokeAnnotation("Match"))

            for stk in self.overlaps.get(stroke, []):
                multiVect = addVectors( [self._features[stroke], self._features[stk] ] )
                logger.debug("Multiple vector: %s" % (str(multiVect)))
                score = scoreVector(self._matchVector, multiVect)
                logger.debug("  Distance %s from baseline" % (score) )
                if score < 0.02:
                    self.getBoard().AnnotateStrokes([stroke, stk], MultiStrokeAnnotation("Match"))
示例#6
0
    def mergeCollections( self, from_anno, to_anno ):
        "merge from_anno into to_anno if possible"
        # check that they have compatable scales
        scale_diff = to_anno.scale / from_anno.scale
        if scale_diff>2.5 or scale_diff<0.4:
            return False
        # check that they are not overlapping
        bb_from = GeomUtils.strokelistBoundingBox( from_anno.Strokes )
        bb_to = GeomUtils.strokelistBoundingBox( to_anno.Strokes )
        if GeomUtils.boundingboxOverlap( bb_from, bb_to ):
            return False

        #  bb[0]-------+
        #   |          |
        #   |          |
        #   | (0,0)    |
        #   +--------bb[1]

        # check that they are next to each other
        if    abs( bb_from[1].X - bb_to[0].X ) > to_anno.scale * 0.75 \
          and abs( bb_from[0].X - bb_to[1].X ) > to_anno.scale * 0.75 :
            return False
        # check y's overlap
        if   bb_from[0].Y - bb_to[1].Y < 0 \
          or bb_to[0].Y - bb_from[1].Y < 0 :
            return False

        # now we know that we want to merge these text annotations
        if bb_from[0].X - bb_to[0].X > 0 :
            to_anno.text = to_anno.text + from_anno.text 
        else :
            to_anno.text = from_anno.text + to_anno.text 
        to_anno.scale = max( to_anno.scale, from_anno.scale )
        return True
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
示例#8
0
 def SaveTemplate(self, numSamples = TEMPLATE_SAMPLE):
     if len(self.StrokeList) > 0:
         last_stroke = self.StrokeList[-1]
         template_name = str(len(self.StrokeList))
         sNorm = GeomUtils.strokeNormalizeSpacing(last_stroke, numSamples)
         centroid = GeomUtils.centroid(sNorm.Points)
         sNorm = sNorm.translate(-1*centroid.X, -1 * centroid.Y)
         storeTemplate(sNorm, tag=template_name)
    def refreshTuringMachines(self):
        labelEdgeMatchingThresh = 2000 # how many times greater than the median we'll match edges

        labelEdgeMatches = {} # { label : {edge, distance} }

        for tmAnno in set(self.tmMap.keys()):
            BoardSingleton().RemoveAnnotation(tmAnno)
            del(self.tmMap[tmAnno])

        for textAnno in self.labelMap.keys():
            labelTL, labelBR = GeomUtils.strokelistBoundingBox(textAnno.Strokes)
            #Midpoint of the labe's bounding box
            labelCenterPt = Point ( (labelTL.X + labelBR.X) / 2.0, (labelTL.Y + labelBR.Y) / 2.0) 

            labelMatchDict = labelEdgeMatches.setdefault(textAnno, {}) 

            for graphAnno in self.graphMap:
                #Match edges to labels
                for edgeAnno in graphAnno.edge_set:
                    edgeLabelPoints = GeomUtils.strokeNormalizeSpacing(edgeAnno.tailstroke, 19).Points #Midpoint in the arrow-stroke
                    for elp in edgeLabelPoints:
                        dist = GeomUtils.pointDistanceSquared(elp.X, elp.Y, labelCenterPt.X, labelCenterPt.Y)
                        #labelMatchDict['allmatches'].append({'anno': edgeAnno, 'dist': dist})
                        if 'bestmatch' not in labelMatchDict or dist < labelMatchDict['bestmatch'][1]:
                            labelMatchDict['bestmatch'] = (edgeAnno, dist)

        #labelEdgeMatches contains each label paired with its best edge
        
        #Have each edge claim a label
        edge2LabelMatching = {}
        for textAnno, matchDict in labelEdgeMatches.items():
            if 'bestmatch' in matchDict: # and matchDict['bestmatch'][1] < labelEdgeMatchingThresh:
                edgeLabelList = edge2LabelMatching.setdefault(matchDict['bestmatch'][0], [])
                edgeLabelList.append(textAnno)
            else:
                tm_logger.debug("TextAnno %s not matched to an edge" % (textAnno.text))

        #Make the associations and add the turing machine annotation
        for graphAnno, tmAnno in self.graphMap.items():
            assocSet = set([graphAnno])
            shouldAddAnno = False
            if tmAnno == None:
                shouldAddAnno = True
                tmAnno = TuringMachineAnnotation(state_graph_anno = graphAnno)

            for edgeAnno in graphAnno.edge_set:
                if edge2LabelMatching.get(edgeAnno, None) is not None:
                    assocLabelsList = edge2LabelMatching[edgeAnno]
                    for label in assocLabelsList:
                        assocSet.add(label)
                        tmAnno.assocLabel2Edge(label, edgeAnno)

            if shouldAddAnno:
                BoardSingleton().AnnotateStrokes(tmAnno.getAssociatedStrokes(), tmAnno)
                self.tmMap[tmAnno] = assocSet
            else:
                BoardSingleton().UpdateAnnotation(tmAnno, new_strokes = tmAnno.getAssociatedStrokes())
                self.tmMap[tmAnno] = assocSet
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)
示例#11
0
    def onStrokeAdded( self, stroke ):
        "Watches for Strokes that look like an arrow to Annotate"
        ep1 = stroke.Points[0]
        ep2 = stroke.Points[-1]
        isArrowHead = False
        GeomUtils.ellipseAxisRatio(stroke)

        #Match single-stroke arrows
        tip, tail = _isSingleStrokeArrow(stroke)
        if tip is None or tail is None:
            revpts = list(stroke.Points)
            revpts.reverse()
            tip, tail = _isSingleStrokeArrow(Stroke(revpts))
        
        if  tip is not None and tail is not None:
            isArrowHead = False
            anno = ArrowAnnotation( tip, tail )
            BoardSingleton().AnnotateStrokes( [stroke],  anno)
        else:
            return
            if _isArrowHead(stroke, self.arrowHeadMatcher): #We've matched an arrowhead
                head = stroke
                isArrowHead = True
                strokeNorm = GeomUtils.strokeNormalizeSpacing(stroke, numpoints = 5)
                tip = strokeNorm.Points[2] #Middle normalized point is the tip
                
        
        #Match it to any tails we have
        if isArrowHead:
            matchedTails = self._matchHeadtoTail(head = stroke, point = tip)
            for headpoint, tail in matchedTails:
                #Orient the tail correctly
                if tail.Points[0] == headpoint:
                    endpoint = tail.Points[-1]
                else:
                    endpoint = tail.Points[0]
                anno = ArrowAnnotation(tip, endpoint)
                BoardSingleton().AnnotateStrokes([head, tail],anno)
        
        #Match it like a tail even if we think it's an arrowhead. Oh ambiguity!
        matchedHeads = self._matchHeadtoTail(tail = stroke, point = ep1)
        for tip, head in matchedHeads:
            anno = ArrowAnnotation(tip, ep2)
            BoardSingleton().AnnotateStrokes([head, stroke],anno)
            
        matchedHeads = self._matchHeadtoTail(tail = stroke, point = ep2)
        for tip, head in matchedHeads:
            anno = ArrowAnnotation(tip, ep1)
            BoardSingleton().AnnotateStrokes([head, stroke],anno)
        
        #Add this stroke to the pool for future evaluation
        self._endpoints.append( (ep1, stroke) )
        self._endpoints.append( (ep2, stroke) )
        if isArrowHead:
            self._arrowHeads.append( (tip, stroke) )
示例#12
0
 def collectionFromItem( self, strokes, annotation ):
     text_anno = None # text_anno will be the return value
     if annotation.isType( CircleObserver.CircleAnnotation ):
         circle = annotation
         text_anno = TextAnnotation("0",circle.radius*2)
     if annotation.isType( LineObserver.LineAnnotation ):
         line = annotation
         # if the line is up/down then it is a one
         if GeomUtils.angleParallel( line.angle, 90 ) > 0.6:
             line_length = GeomUtils.pointDist( line.start_point, line.end_point )
             text_anno = TextAnnotation("1",line_length)
     return text_anno
示例#13
0
    def onStrokeAdded( self, stroke ):
        "Watches for Strokes with Circularity > threshold to Annotate"
        # need at least 6 points to be a line
        if stroke.length()<6:
            return

        linearity = GeomUtils.strokeLinearity( stroke )
        angle = GeomUtils.strokeOrientation( stroke )
        
        if( linearity > self.threshold ):
            lanno = LineAnnotation( linearity, angle, stroke.Points[0], stroke.Points[-1] )
            self.getBoard().AnnotateStrokes( [stroke], lanno )
示例#14
0
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
示例#15
0
 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
示例#16
0
def scoreStroke(stroke, template):
    sNorm = GeomUtils.strokeNormalizeSpacing(stroke, TEMPLATE_SAMPLE)
    centr = GeomUtils.centroid(sNorm.Points)
    point_vect = []
    templ_vect = []
    for q in template:
       templ_vect.append(q.X)
       templ_vect.append(q.Y)
    for p in sNorm.Points:
       point_vect.append(p.X - centr.X)
       point_vect.append(p.Y - centr.Y)
    angularDist = GeomUtils.vectorDistance(point_vect, templ_vect)
    return angularDist
示例#17
0
 def SaveTemplate(self, sender, e, numSamples = TEMPLATE_SAMPLE):
     if len(self.StrokeList) > 0:
         #last_stroke = self.StrokeList[-1]
         pts = []
         for stk in self.StrokeList:
             pts.extend(stk.Points)
         templ_stroke = Stroke.Stroke(points= pts)
         template_name = TEMPLATE_TEXT.Text 
         if template_name.strip() == '':
             template_name = 'Blob'
         sNorm = GeomUtils.strokeNormalizeSpacing(templ_stroke, numSamples * len(self.StrokeList))
         centroid = GeomUtils.centroid(sNorm.Points)
         sNorm = sNorm.translate(-1*centroid.X, -1 * centroid.Y)
         storeTemplate(sNorm, len(self.StrokeList), tag=template_name)
     self.Clear()
示例#18
0
    def isToRight(self, stroke_to, stroke_from, scale):
        '''
            if from is to the right of to
        '''

        bb_from = GeomUtils.strokelistBoundingBox( [stroke_from] )
        center_from = Point( (bb_from[0].X + bb_from[1].X) / 2.0, (bb_from[0].Y + bb_from[1].Y) / 2.0)

        bb_to = GeomUtils.strokelistBoundingBox( [stroke_to] )
        center_to = Point( (bb_to[0].X + bb_to[1].X) / 2.0, (bb_to[0].Y + bb_to[1].Y) / 2.0)

        if 0 < center_from.X - center_to.X < self.horizDistRatio * scale:
            return True

        return False
示例#19
0
 def Score( self, strokelist, max_return = 1, interest = 0.2):
     "Compare these strokes to all templates, and return the best templates with their scores. "
     ROTATIONS = 16
     best_templ = None 
     for stroke_order in itertools.permutations(strokelist):
         pointlist = []
         for s in stroke_order:
             pointlist.extend(s.Points)
         new_stroke = Stroke.Stroke(points=pointlist)
         
         for name, template_set in self._templates.items():
             for template in template_set:
                 for angle in [2 * math.pi / ROTATIONS * i for i in range(ROTATIONS)]:
                     end_template = GeomUtils.rotateStroke(Stroke.Stroke(points=template), angle).Points
                     firstpass_score = _scoreStroke(new_stroke, end_template, 10)
                     if best_templ is not None and firstpass_score - 0.1 > best_templ['score']:
                         continue
                     score = _scoreStroke(new_stroke, end_template, len(end_template))
                     logger.debug("   '%s' ... %s" % (name, score))
             
                     if best_templ is None:
                         best_templ = {'score': score + 1}
                 
                     if score < best_templ['score']:
                         best_templ['name'] = name
                         best_templ['score'] = score
                         best_templ['template'] = end_template
     return best_templ
示例#20
0
    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
示例#21
0
 def _makeLetterAnnotation(self, strokelist, char, alternates):
     bb = GeomUtils.strokelistBoundingBox(strokelist)
     height = bb[0].Y - bb[1].Y
     width = bb[1].X - bb[0].X 
     scale = max(height, width, 1)
     retAnnotation = TextAnnotation(char,  (alternates,), [strokelist], scale)
     return retAnnotation
示例#22
0
    def onAnnotationAdded( self, strokes, annotation ):
        "Checks to see if an divide sign has been added"

        ul,br = GeomUtils.strokelistBoundingBox(strokes)
        height = ul.Y - br.Y
        self.getBoard().AnnotateStrokes( strokes, DivideAnnotation(height))
        return
示例#23
0
    def displayDataManager(self):
        """Paint whatever the display manager wants on the board"""
        global HEIGHT, WIDTH, BOARDSCALE
        self.ResetBoard()
        print self.dataset.participants[self.participant].diagrams[self.diagram].type

        xMax = 0
        yMax = 0
        xMin = sys.maxint
        yMin = sys.maxint

        par = self.participant
        dig = self.diagram


        # Finds the min and max points so we can scale the data to fit on the screen
        for stkNum, inkStroke in self.dataset.participants[par].diagrams[dig].InkStrokes.items():
            stroke = traceStroke(inkStroke.stroke)
            ul,br = GeomUtils.strokelistBoundingBox([stroke])
            xMax = max(ul.X, br.X, xMax)
            yMax = max(ul.Y, br.Y, yMax)
            xMin = min(ul.X, br.X, xMin)
            yMin = min(ul.Y, br.Y, yMin)

        # Find the distance that the strokes take up
        # the "+ 20" is so we can have a 10 pixle buffer around the edges

        setBoardScale(xMax, yMax)


        labelStrokeMap = {} #Maps groupLabel : set(strokes)
        for stkNum, inkStroke in self.dataset.participants[par].diagrams[dig].InkStrokes.items():
            #print inkStroke.id
            stroke = inkStroke.stroke
            for groupLabel in self.dataset.participants[par].diagrams[dig].groupLabels:
                if stroke.id in groupLabel.ids:
                    labelStrokeMap.setdefault(groupLabel, set()).add(stroke)
            points = []
            
            """
            # scale each point to it's new position
            for p in stroke.Points:
                x = (p.X - xMin) * scaleFactor + 10 # the "+10 is for the 10 pixle boarder
                # y axis points in the data manager are inverted compaired to our screen
                # so we invert them
                y = HEIGHT - ((p.Y - yMin) * scaleFactor + 10)
                points.append(Point(x,y))
            """

            # create a new stroke out of the scaled points and add it to the board.
            #s = Stroke(points)
            s = inkStroke.stroke
            self.Board.AddStroke(s)
            self.StrokeList.append(s)
            # Annotate the stroke with the type given in the data manager

        for groupLabel, strokeSet in labelStrokeMap.items():
            self.Board.AnnotateStrokes(list(strokeSet), 
                                       DataManager.DataManagerAnnotation(groupLabel.type))
示例#24
0
    def drawMyself( self ):
        for a in self.annotation_list:
            center = GeomUtils.centroid(a.Strokes[0].Points) #Ugly hack to get the center of the annotation!
            templ_stroke = Stroke.Stroke(a.template)
            templ_stroke = templ_stroke.translate(center.X, center.Y)

            SketchGUI.drawText(center.X, center.Y, InText=a.name)
            SketchGUI.drawStroke(templ_stroke, color="#F050F0")
示例#25
0
    def mergeCollections(self, from_anno, to_anno):
        "merge from_anno into to_anno if they are naer enough to each other"
        minScale = 30
        vertOverlapRatio = 0
        horizOverlapRatio = 0
        groupingDistScale = 0.4  # multiplier for the median scale of how far to check around
                                # The strokes
        def annoScale(anno):
            """Helper function to get the scale of this annotation"""
            heights = [s.BoundTopLeft.Y - s.BoundBottomRight.Y for s in anno.Strokes]
#            scale = max(minScale, heights[len(heights)/2]) # median
            scale = sum(heights) / float(max(1, len(heights)))
            return max(scale, minScale)

        #  bb[0]-------+
        #   |          |
        #   |          |
        #   |          |
        #   +--------bb[1]
        # (0,0)

        from_scale = annoScale(from_anno)
        bb_from = GeomUtils.strokelistBoundingBox(from_anno.Strokes)
        tl = Point (bb_from[0].X - from_scale, bb_from[0].Y + from_scale * groupingDistScale)
        br = Point (bb_from[1].X + from_scale, bb_from[1].Y - from_scale * groupingDistScale)
        bb_from = (tl, br)

        to_scale = annoScale(to_anno)
        bb_to = GeomUtils.strokelistBoundingBox(to_anno.Strokes)
        tl = Point (bb_to[0].X - to_scale, bb_to[0].Y + to_scale * groupingDistScale)
        br = Point (bb_to[1].X + to_scale, bb_to[1].Y - to_scale * groupingDistScale)
        bb_to = (tl, br)
        # check x's overlap
        if   bb_from[1].X - bb_to[0].X < horizOverlapRatio \
          or bb_to[1].X - bb_from[0].X < horizOverlapRatio :
            logger.debug("Not merging %s and %s: horizontal overlap too small" % (from_anno, to_anno))
            return False

        # check y's overlap
        if   bb_from[0].Y - bb_to[1].Y < vertOverlapRatio \
          or bb_to[0].Y - bb_from[1].Y < vertOverlapRatio :
            logger.debug("Not merging %s and %s: vertical overlap too small" % (from_anno, to_anno))
            return False

        self.annoQueue.put(to_anno)
        return True
示例#26
0
def classifyArrowhead(board, stroke):
    """Following the class 1 semantics, this classifies arrowheads"""
    if _isArrowHead(stroke, arrowHeadMatcher):
        #                * (tip-point)
        #              o   o
        #             o      o
        #            o         o
        #          o            o
        
        #Get the endpoints/tip point as max curvature
        strokeNorm = GeomUtils.strokeNormalizeSpacing(stroke, numpoints = 7)
        curvatures = GeomUtils.strokeGetPointsCurvature(strokeNorm)
        ptIdx = curvatures.index(max(curvatures))
        tip = strokeNorm.Points[ptIdx] #Middle is the point of max curvature
        annotation = ArrowHeadAnnotation(stroke.Points[0], tip, stroke.Points[-1])
        return annotation
    return None
示例#27
0
    def onStrokeAdded( self, stroke ):
        "Watches for Strokes with Circularity > threshold to Annotate"
        # need at least 6 points to be a circle
	if stroke.length()<6:
            return
        strokeLen = GeomUtils.strokeLength(stroke)
        distCutoff = NodeMarker.CLOSED_DIST_THRESH * (strokeLen ** 2)
	#s_norm = GeomUtils.strokeNormalizeSpacing( stroke, 20 ) 
        ep1 = stroke.Points[0]
        ep2 = stroke.Points[-1]

        epDist = GeomUtils.pointDistanceSquared(ep1.X, ep1.Y, ep2.X, ep2.Y)
        if epDist <= distCutoff:
            avgDist = GeomUtils.averageDistance( stroke.Center, stroke.Points )
            self.getBoard().AnnotateStrokes([stroke], DiGraphNodeAnnotation(0, stroke.Center, avgDist))
        else:
            node_log.debug("Not a node: endpoint distance %s > %s" % (epDist, distCutoff))
示例#28
0
 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
示例#29
0
    def onStrokeAdded( self, stroke ):
        "Watches for Strokes with Circularity > threshold to Annotate"
        # need at least 6 points to be a circle
	if stroke.length()<6:
            return
	s_norm = GeomUtils.strokeNormalizeSpacing( stroke, 20 ) 
	s_chop = GeomUtils.strokeChopEnds( s_norm, 0.20 ) 
        circ_norm = GeomUtils.strokeCircularity( s_norm ) 
        circ_chop = GeomUtils.strokeCircularity( s_chop ) 

        logger.debug( "stroke: %s", [str(p) for p in s_norm.Points] )
        logger.debug( "potential circles (%f,%f) <> %f", circ_norm, circ_chop, self.threshold )

        if( circ_norm>self.threshold or circ_chop>self.threshold):
            cen = stroke.Center
            avgDist = GeomUtils.averageDistance( cen, stroke.Points )
            anno = CircleAnnotation( circ_norm, cen, avgDist )
            BoardSingleton().AnnotateStrokes( [stroke],  anno)
示例#30
0
    def drawAnno( self, a ):
        ul,br = GeomUtils.strokelistBoundingBox( a.Strokes )
        spaceing = 5
        ul.X -= spaceing
        ul.Y += spaceing
        br.X += spaceing
        br.Y -= spaceing

        self.getBoard().getGUI().drawBox(ul, br, color="#a0a0a0");
        self.getBoard().getGUI().drawText( br.X - 15, br.Y, a.text, size=15, color="#a0a0a0" )