Пример #1
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"))
Пример #3
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)
Пример #4
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
Пример #5
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
Пример #6
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
Пример #7
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
Пример #8
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))
Пример #9
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
    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
Пример #11
0
    def onAnnotationAdded( self, strokes, annotation ):
        "Checks to see if an equals sign has been added"
        
        # Find the midpoints         
        ul,br = GeomUtils.strokelistBoundingBox( strokes )
        midpointY = (ul.Y + br.Y) / 2
        midpointX = (ul.X + br.X) / 2
        strokeLen = GeomUtils.strokeLength(strokes[0])

        for a in self.possibleAnnotations:
            s = a.Strokes[0]
            prevStrokeLen = GeomUtils.strokeLength(s)

            # test the the two segments are of similar length
            lengthRange = 0.4
            if prevStrokeLen * (1-lengthRange) < strokeLen < prevStrokeLen * (1+lengthRange):
                pass # were the right length
            else: # not the right length, so lets start again
                continue

            ul,br = GeomUtils.strokelistBoundingBox( [s] )
            prevMidpointY = (ul.Y + br.Y) / 2
            prevMidpointX = (ul.X + br.X) / 2

            # Test that the two segments are close enough horizontally
            if GeomUtils.pointDistance(midpointX, 0, prevMidpointX, 0) < prevStrokeLen * 0.4:
                pass # there are close enough horizontally
            else: # we start again
                continue

            # Test that the two segments are close enough vertically
            if GeomUtils.pointDistance(0,midpointY, 0, prevMidpointY) < prevStrokeLen * 0.5:
                pass # there are close enough vertically
            else: # we start again
                continue

            # we found a match
            self.possibleAnnotations.remove(a)
            self.getBoard().AnnotateStrokes( strokes + [s],  EqualsAnnotation(1))
            return


        # no match was found, add to the list of possible
        self.possibleAnnotations.append(annotation)
        return
Пример #12
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" )
Пример #13
0
 def drawAnno( self, a ):
     ul,br = GeomUtils.strokelistBoundingBox( a.Strokes )
     logger.debug(a.Strokes)
     height = ul.Y - br.Y
     midpointY = (ul.Y + br.Y) / 2
     midpointX = (ul.X + br.X) / 2
     left_x = midpointX - a.scale / 2.0
     right_x = midpointX + a.scale / 2.0
     #self.getBoard().getGUI().drawLine( left_x, midpointY, right_x, midpointY, color="#a0a0a0")
     y = br.Y
     self.getBoard().getGUI().drawText( br.X, y, a.text, size=15, color="#a0a0a0" )
Пример #14
0
    def findOnLeft( self, anno, list):
        bb_e = GeomUtils.strokelistBoundingBox( anno.Strokes )
        center_e = Point( (bb_e[0].X + bb_e[1].X) / 2.0, (bb_e[0].Y + bb_e[1].Y) / 2.0)

        v_offset = anno.scale / 4
        h_offset = anno.scale / 2

        for a in list:
            bb_a = GeomUtils.strokelistBoundingBox( a.Strokes )
            center_a = Point( (bb_a[0].X + bb_a[1].X) / 2.0, (bb_a[0].Y + bb_a[1].Y) / 2.0)

            # is it vertically alligned?
            if not ((center_e.Y < center_a.Y + v_offset) and (center_e.Y > center_a.Y - v_offset)):
                continue

            # is it to the Left?
            if center_e.X <= center_a.X:
                continue

            return a

        return None       
Пример #15
0
 def drawAnno( self, a ):
     if len(a.text) >= 1:
         ul,br = GeomUtils.strokelistBoundingBox( a.Strokes )
         logger.debug(a.Strokes)
         height = ul.Y - br.Y
         left_x = ul.X# - height/3
         right_x = br.X + height/2
         midpoint = (ul.Y + br.Y) / 2
         SketchGUI.drawLine( left_x, midpoint, right_x, midpoint, color="#a0a0a0")
         y = br.Y + 5
         for idx, text in enumerate(a.alternates):
             SketchGUI.drawText( br.X, y, text, size=20, color="#a0a0a0" )
             y -= 20
Пример #16
0
 def drawAnno( self, a ):
     if len(a.text) > 1:
         ul,br = GeomUtils.strokelistBoundingBox( a.Strokes )
         logger.debug(a.Strokes)
         height = ul.Y - br.Y
         midpointY = (ul.Y + br.Y) / 2
         midpointX = (ul.X + br.X) / 2
         left_x = midpointX - a.scale / 2.0
         right_x = midpointX + a.scale / 2.0
         #SketchGUI.drawLine( left_x, midpointY, right_x, midpointY, color="#a0a0a0")
         y = br.Y
         SketchGUI.drawText( br.X, y, a.text, size=15, color="#a0a0a0" )
         y -= 15
         for idx, text in enumerate(a.alternates):
             SketchGUI.drawText( br.X, y, text, size=10, color="#a0a0a0" )
             y -= 10
Пример #17
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

        logger.debug(a.Strokes)
        height = ul.Y - br.Y
        midpointY = (ul.Y + br.Y) / 2
        midpointX = (ul.X + br.X) / 2
        left_x = midpointX - a.scale / 2.0
        right_x = midpointX + a.scale / 2.0
        self.getBoard().getGUI().drawBox(ul, br, color="#a0a0a0");
        
        self.getBoard().getGUI().drawText( br.X - 15, br.Y, "X", size=15, color="#a0a0a0" )
Пример #18
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

        logger.debug(a.Strokes)
        height = ul.Y - br.Y
        midpointY = (ul.Y + br.Y) / 2
        midpointX = (ul.X + br.X) / 2
        left_x = midpointX - a.scale / 2.0
        right_x = midpointX + a.scale / 2.0
        self.getBoard().getGUI().drawBox(ul, br, color="#a0a0a0");
        #print "Drawing " + a.type + " with number " + str(a.number) + " and scale " + str(int(a.scale))
        if a.type == "X": 
            self.getBoard().getGUI().drawText( br.X + 10, ul.Y, str(a.number), size= int(a.scale), color="#a0a0a0" )
Пример #19
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

        logger.debug(a.Strokes)
        height = ul.Y - br.Y
        midpointY = (ul.Y + br.Y) / 2
        midpointX = (ul.X + br.X) / 2
        #left_x = midpointX - a.scale / 2.0
        #right_x = midpointX + a.scale / 2.0
        """
        self.getBoard().getGUI().drawBox(ul, br, color="#a0a0a0")
        """
        gui = self.getBoard().getGUI()
        color = "#0C00F0"
        gui.drawText( br.X - 15, br.Y, a.name , size=15, color=color )
        for s in a.Strokes:
            gui.drawStroke(s, width = 3, color = color)
            gui.drawStroke(s, width = 1, color = "#000000")
Пример #20
0
    def onAnnotationAdded( self, strokes, annotation ):
        '''
        print "Annotation Added:"
        print annotation
        '''

        if annotation.isType(BinAnnotation):

            bb_a = GeomUtils.strokelistBoundingBox( annotation.Strokes )
            center_a = Point( (bb_a[0].X + bb_a[1].X) / 2.0, (bb_a[0].Y + bb_a[1].Y) / 2.0)
            tl = Point (center_a.X - annotation.scale/ 2.0, center_a.Y + (annotation.scale / 2.0) )
            br = Point (center_a.X + annotation.scale/ 2.0, center_a.Y - (annotation.scale / 2.0) )
            bb_a = (tl, br)

            for a in self.equalsAnnotations:
                bb_e = GeomUtils.strokelistBoundingBox( a.Strokes )
                center_e = Point( (bb_e[0].X + bb_e[1].X) / 2.0, (bb_e[0].Y + bb_e[1].Y) / 2.0)
                tl = Point (center_e.X - a.scale/ 2.0, center_e.Y + (a.scale / 2.0) )
                br = Point (center_e.X + a.scale/ 2.0, center_e.Y - (a.scale / 2.0) )
                bb_e = (tl, br)

                if bb_e[0].X < bb_a[1].X:
                    continue

                if   bb_e[0].Y - bb_a[1].Y < 0 \
                    or bb_a[0].Y - bb_e[1].Y < 0 :
                    continue
                
                # we have a matching stroke
                self.equalsAnnotations.remove(a)
                eAnno = EquationAnnotation(annotation.scale, "X", int(annotation.text,2))
                self.equationAnnotations.append(eAnno)
                self.getBoard().AnnotateStrokes( a.Strokes + strokes, eAnno )
                return
            # No match, so just add it to the list

            self.binAnnotations.append(annotation)
        elif annotation.isType(EqualsAnnotation):

            bb_e = GeomUtils.strokelistBoundingBox( annotation.Strokes )
            center_e = Point( (bb_e[0].X + bb_e[1].X) / 2.0, (bb_e[0].Y + bb_e[1].Y) / 2.0)
            tl = Point (center_e.X - annotation.scale/ 2.0, center_e.Y + (annotation.scale / 2.0) )
            br = Point (center_e.X + annotation.scale/ 2.0, center_e.Y - (annotation.scale / 2.0) )
            bb_e = (tl, br)

            for a in self.binAnnotations:
                bb_a = GeomUtils.strokelistBoundingBox( a.Strokes )
                center_a = Point( (bb_a[0].X + bb_a[1].X) / 2.0, (bb_a[0].Y + bb_a[1].Y) / 2.0)
                tl = Point (center_a.X - a.scale/ 2.0, center_a.Y + (a.scale / 2.0) )
                br = Point (center_a.X + a.scale/ 2.0, center_a.Y - (a.scale / 2.0) )
                bb_a = (tl, br)

                if bb_e[0].X < bb_a[1].X:
                    continue

                if   bb_e[0].Y - bb_a[1].Y < 0 \
                    or bb_a[0].Y - bb_e[1].Y < 0 :
                    continue
                
                # we have a matching stroke
                self.binAnnotations.remove(a)
                eAnno = EquationAnnotation(a.scale, "X", int(a.text,2))
                self.equationAnnotations.append(eAnno)
                self.getBoard().AnnotateStrokes( a.Strokes + strokes, eAnno )
                return
            # No match, so just add it to the list
            self.equalsAnnotations.append(annotation)
Пример #21
0
def _scoreStrokesForLetter(strokelist, letter):
    """Get the confidence score for a group of strokes matching a letter, normalized [0.0-1.0]"""
    retConfidence = 0.0
    #Recognition thresholds
    closedDistRatio = 0.22
    circularityThresh_0 = 0.80
    circularityThresh_1 = 0.20
    maxStraightCurvature = 0.6
    strokesBB = GeomUtils.strokelistBoundingBox(strokelist)

    if len(strokelist) == 0:
        return 0.0

    #The case of a single point
    if strokesBB[0].X == strokesBB[1].X and strokesBB[0].Y == strokesBB[1].Y:
        return 0.0

    #Recognize a zero
    if letter.upper() == "0":
        stroke = strokelist[0]
        strokeLen = max(GeomUtils.strokeLength(stroke), 1)
        normDist = max(3, strokeLen / 5) #granularity of point spacing -- at least 3
        head, tail = stroke.Points[0], stroke.Points[-1]

        endDist = GeomUtils.pointDistance(head.X, head.Y, tail.X, tail.Y)
        #If the endpoints are 1/thresh apart, actually close the thing
        isClosedShape = GeomUtils.pointDistanceSquared(head.X, head.Y, tail.X, tail.Y) \
                        < ( (strokeLen * closedDistRatio) ** 2 )

        if isClosedShape: #Close the shape back up
            s_norm = GeomUtils.strokeNormalizeSpacing( Stroke(stroke.Points + [stroke.Points[0]]) , normDist ) 
        else:
            s_norm = GeomUtils.strokeNormalizeSpacing( stroke , normDist ) 
        #curvatures = GeomUtils.strokeGetPointsCurvature(s_norm)
        circularity = GeomUtils.strokeCircularity( s_norm ) 

        if isClosedShape:
            retConfidence += 0.5
        if circularity > circularityThresh_0:
            retConfidence += 0.5
        return retConfidence
    #Recognize a one
    elif letter.upper() == "1":
        stroke = strokelist[0]
        strokeLen = max(GeomUtils.strokeLength(stroke), 1)
        normDist = max(3, strokeLen / 5) #granularity of point spacing -- at least 3
        s_norm = GeomUtils.strokeNormalizeSpacing( stroke , normDist ) 

        circularity = GeomUtils.strokeCircularity( s_norm ) 
        curvatures = GeomUtils.strokeGetPointsCurvature(s_norm)
        if max(curvatures) < maxStraightCurvature:
            retConfidence += 0.30
        if circularity < circularityThresh_1:
            retConfidence += 0.5
            if stroke.Points[0].X < stroke.Points[-1].X + strokeLen / 2.0 \
            and stroke.Points[0].X > stroke.Points[-1].X - strokeLen / 2.0:
                retConfidence += 0.2
        return retConfidence
    #Recognize a dash
    elif letter.upper() == "-":
        stroke = strokelist[0]
        strokeLen = max(GeomUtils.strokeLength(stroke), 1)
        normDist = max(3, strokeLen / 5) #granularity of point spacing -- at least 3
        s_norm = GeomUtils.strokeNormalizeSpacing( stroke , normDist ) 

        circularity = GeomUtils.strokeCircularity( s_norm ) 
        curvatures = GeomUtils.strokeGetPointsCurvature(s_norm)
        if max(curvatures) < maxStraightCurvature:
            retConfidence += 0.30
        if circularity < circularityThresh_1:
            retConfidence += 0.5
            if stroke.Points[0].Y < stroke.Points[-1].Y + strokeLen / 2.0 \
            and stroke.Points[0].Y > stroke.Points[-1].Y - strokeLen / 2.0:
                retConfidence += 0.2
        return retConfidence
    else:
        return 0.0
Пример #22
0
    def mergeCollections( self, from_anno, to_anno ):
        "merge from_anno into to_anno if possible"
        vertOverlapRatio = 0
        horizDistRatio = 2.3
        scaleDiffRatio = 2.0
        #if from_anno.scale > 0:
            #scale_diff = to_anno.scale / from_anno.scale
            #if scale_diff > scaleDiffRatio or scale_diff < 1/ float(scaleDiffRatio) :
                #tc_logger.debug("Not merging %s and %s: Scale Diff is %s" % (from_anno.text, to_anno.text, scale_diff))
                #return False
            #else:
                #return False

        #  bb[0]-------+
        #   |          |
        #   |          |
        #   | (0,0)    |
        #   +--------bb[1]
        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)

        # check that they are next to each other
        if    abs( bb_from[1].X - bb_to[0].X ) > to_anno.scale * horizDistRatio \
          and abs( bb_from[0].X - bb_to[1].X ) > to_anno.scale * horizDistRatio \
          and abs( bb_from[1].X - bb_to[0].X ) > from_anno.scale * horizDistRatio \
          and abs( bb_from[0].X - bb_to[1].X ) > from_anno.scale * horizDistRatio:
            #tc_logger.debug("Not merging %s and %s: horizontal distance too great" % (from_anno.text, to_anno.text))
            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 :
            #tc_logger.debug("Not merging %s and %s: vertical overlap too small" % (from_anno.text, to_anno.text))
            return False

        # check that they have compatible scales
        scale_diff1 = to_anno.scale / from_anno.scale
        scale_diff2 = from_anno.scale / to_anno.scale
        if scale_diff1 > scaleDiffRatio or scale_diff2 > scaleDiffRatio:
            tc_logger.debug("Not merging %s and %s: Scale Diff is %s" % (from_anno, to_anno, scale_diff1))
            return False

        # Order the letters properly from left to right
        out_letter_stroke_map = []
        outText = ""
        from_idx = 0
        to_idx = 0
        all_alternates = []
        while len(outText) < len(from_anno.text) + len(to_anno.text):
            #Get the BB for the next letter in from_anno
            if from_idx < len(from_anno.letter2strokesMap) and from_idx < len(from_anno.text):
                letter_bb_from = GeomUtils.strokelistBoundingBox(from_anno.letter2strokesMap[from_idx])
            else:
                letter_bb_from = None
                
            #Get the BB for the next letter in to_anno
            if to_idx < len(to_anno.letter2strokesMap) and to_idx < len(to_anno.text):
                letter_bb_to = GeomUtils.strokelistBoundingBox(to_anno.letter2strokesMap[to_idx])
            else:
                letter_bb_to = None

            if letter_bb_to is None and letter_bb_from is None:
                logger.warn("Trying to merge beyond available letters")
                break
            elif letter_bb_to is None or \
                   (letter_bb_from is not None and letter_bb_from[0].X < letter_bb_to[0].X ):
                #The next letter belongs to from_anno. Merge it
                outText += from_anno.alternates[from_idx][0]
                all_alternates.append(from_anno.alternates[from_idx]) #Merge the alternates for this letter, too
                out_letter_stroke_map.append(from_anno.letter2strokesMap[from_idx])
                from_idx += 1
            elif letter_bb_from is None or \
                   (letter_bb_to is not None and letter_bb_to[0].X <= letter_bb_from[0].X):
                #The next letter belongs to to_anno. Merge it
                outText += to_anno.alternates[to_idx][0]
                all_alternates.append(to_anno.alternates[to_idx]) #Merge the alternates for this letter, too
                out_letter_stroke_map.append(to_anno.letter2strokesMap[to_idx])
                to_idx += 1

        #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.letter2strokesMap = out_letter_stroke_map
        to_anno.alternates = tuple(all_alternates)
        return True
Пример #23
0
    def onAnnotationAdded( self, strokes, annotation ):
        '''
        print "Annotation Added:"
        print annotation
        '''
       
        if annotation.isType(ExpressionAnnotation):
            # check to see if there is an operation to the right of the num
            # and then an expression to the right of that operation
            left = None
            right = None
            op = self.findOnRight(annotation, self.opAnnotations)
            if op != None:
                right = self.findOnRight(op, self.expressionAnnotations)
                if right != None:
                    left = annotation
                    self.expressionAnnotations.remove(right)
            
            # if no expression was found to the right, search to the left
            if left == None:
                op = self.findOnLeft(annotation, self.opAnnotations)
                if op != None:
                    left = self.findOnLeft(op, self.expressionAnnotations)
                    if left != None:
                        right = annotation
                        self.expressionAnnotations.remove(left)
                
            if left != None:
                #print "Num Found"
                #print num
                s =  left.Strokes + op.Strokes + right.Strokes
                ul, br = GeomUtils.strokelistBoundingBox(s)
                e = ExpressionAnnotation(ul.Y - br.Y)
                left.parent = e
                right.parent = e
                e.left = left
                e.right = right
                e.op = op
                self.opAnnotations.remove(op)
                self.getBoard().AnnotateStrokes(s, e)
                #annotation.scale = ul.Y - br.Y
                #annotation.number = annotation.number + num.number
                #self.getBoard().UpdateAnnotation(annotation, s)
                #self.getBoard().RemoveAnnotation(num)
                return

            # This expression can't be added to any of the other parts
            # so we will properly order it then add it to the list of annotations
            top = self.order(annotation)
            print top
            self.expressionAnnotations.append(top)

        elif annotation.isType(NumAnnotation):
            e = ExpressionAnnotation(annotation.scale)
            e.number = annotation
            self.getBoard().AnnotateStrokes(strokes, e)

        elif annotation.isType(PlusAnnotation):
            self.opAnnotations.append(annotation)
        elif annotation.isType(MinusAnnotation):
            self.opAnnotations.append(annotation)
        elif annotation.isType(DivideAnnotation):
            self.opAnnotations.append(annotation)
        elif annotation.isType(MultAnnotation):
            self.opAnnotations.append(annotation)
Пример #24
0
    def mergeCollections( self, from_anno, to_anno ):
        "merge from_anno into to_anno if possible"
        #FIXME: New annotation assumed to be to the right. (Does not handle inserting text in the middle)
        # check that they have compatable scales
        vertOverlapRatio = 0
        scaleDiffRatio = 1.5
        scale_diff = to_anno.scale / from_anno.scale
        if scale_diff> scaleDiffRatio or 1/float( scale_diff ) > scaleDiffRatio :
            tc_logger.debug("Not merging %s and %s: Scale Diff is %s" % (to_anno.text, from_anno.text, scale_diff))
            return False
        # check that they are not overlapping
        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 not GeomUtils.boundingboxOverlap( bb_from, bb_to ):
            tc_logger.debug("Not merging Bounding boxes don't overlap")
            return False
        """

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

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

        # sort the strokes so they are in order from left to right
        to_anno.Strokes.sort(key = self.getSortItem);
        from_anno.Strokes.sort(key = self.getSortItem);
        first = from_anno.Strokes[0] # left most
        last = from_anno.Strokes[len(from_anno.Strokes)-1] # right most

        # check if from to the left of to?
        if self.isToLeft(to_anno.Strokes[0], last, to_anno.scale):
            return self.merg(to_anno, from_anno)

        # check if from is to the right of to?
        if self.isToRight(to_anno.Strokes[len(to_anno.Strokes)-1], first, to_anno.scale):
            return self.merg(to_anno, from_anno)

        # check if from is inserted somewhere inside to
        for i in range(len(to_anno.Strokes)):
            if self.isToRight(to_anno.Strokes[i], first, to_anno.scale)\
            and self.isToLeft(to_anno.Strokes[i+1], last, to_anno.scale):
                return self.merg(to_anno, from_anno)

        return False
Пример #25
0
 def getSortItem(self, stroke):
     return GeomUtils.strokelistBoundingBox( [stroke] )[0].X
Пример #26
0
    def drawAnno( self, a ):
        edge_label_size = 15
        tape_label_size = 20
        active_color = "#BF5252"
        active_width = 7.0
        state_graph = a.state_graph_anno
        for from_node, connection_list in state_graph.connectMap.items():
            if from_node is not None:
                nodeColor = "#FFFFFF"
                if from_node == a.active_state:
                    nodeColor = active_color
                x, y = ( from_node.center.X, from_node.center.Y )
                self.getBoard().getGUI().drawCircle (x, y, radius=(from_node.radius / 2.0), color=nodeColor, width=3.0)

            #GeomUtils.strokeSmooth(edge.tailstroke, width = len(edge.tailstroke.Points) / 3).drawMyself()
            for edge, to_node in connection_list:
                if edge == a.leading_edge['edge']:
                    edgeColor = active_color
                else:
                    edgeColor = "#FFFFFF"
                if to_node is not None:
                    nodeColor = "#FFFFFF"
                    nodeWidth = 3.0
                    if to_node == a.active_state:
                        nodeColor = active_color
                        nodeWidth = active_width
                    x, y = ( to_node.center.X, to_node.center.Y )
                    self.getBoard().getGUI().drawCircle (x, y, radius=(to_node.radius / 2.0), color=nodeColor, fill="", width=nodeWidth)
                #Draw the smoothed tail
                if from_node is not None:
                    if edge.direction == "tail2head": #Connect the tail more closely to the edge
                        smooth_tail = Stroke([from_node.center] + edge.tailstroke.Points + [edge.tip])
                    else:
                        smooth_tail = Stroke([edge.tip] + edge.tailstroke.Points + [from_node.center])
                else:
                    smooth_tail = edge.tailstroke
                smooth_tail = GeomUtils.strokeSmooth(smooth_tail, width = len(edge.tailstroke.Points) / 3, preserveEnds = True)
                smooth_tail.drawMyself(color=edgeColor)

                #Draw the smoothed head
                ep1, ep2 = ( edge.headstroke.Points[0], edge.headstroke.Points[-1] )
                smooth_head = Stroke([ep1, edge.tip, ep2])
                smooth_head.drawMyself(color = edgeColor)

                if edge in a.edge2labels_map:
                    #Determine label offset
                     
                    for label in a.edge2labels_map[edge]:
                        textColor = "#FFFFFF"
                        if label == a.leading_edge['label']:
                            tm_logger.debug("Drawing leading label: %s" % (label.text))
                            textColor = active_color
                        tl, br = GeomUtils.strokelistBoundingBox(label.Strokes)

                        label_point = Point ((tl.X + br.X) / 2.0, br.Y)
                        label_point.X -= edge_label_size
                        label_point.Y -= edge_label_size
                        #label_point = smooth_tail.Points[len(smooth_tail.Points)/2]
                        self.getBoard().getGUI().drawText (label_point.X, label_point.Y, InText=label.text, size=edge_label_size, color=textColor)
                    #endfor
                #endif
            #end for edge
        #end for from_node

        #Draw the tape string
        tl, br = GeomUtils.strokelistBoundingBox(a.Strokes)
        tape_label_pt = Point( \
            ((tl.X + br.X) / 2.0) - (len(a.tape_string) + 2) * tape_label_size / 2.0 , \
            br.Y - tape_label_size)

        for curIdx, tapeChar in enumerate(['-'] + a.tape_string + ['-']):
            curPt = Point(tape_label_pt.X + curIdx * tape_label_size, tape_label_pt.Y)
            charColor = "#FFFFFF"
            if curIdx - 1== a.tape_idx:
                charColor = active_color
            self.getBoard().getGUI().drawText (curPt.X, curPt.Y, InText=tapeChar, size=tape_label_size, color=charColor)
Пример #27
0
    def refreshTuringMachines(self):

        #Remove all of the current Turing Machines
        for tmAnno in set(self.tmMap.keys()):
            self.getBoard().RemoveAnnotation(tmAnno)
            del(self.tmMap[tmAnno])
        
        #Match all of the labels we've seen with their closest edges
        #    in any graph
        labelEdgeMatches = {} # { label : {edge, distance} }
        for textAnno in self.labelMap.keys():
            labelTL, labelBR = GeomUtils.strokelistBoundingBox(textAnno.Strokes)
            #Midpoint of the label'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:
                #Check to make sure the label doesn't share strokes with the graph structure
                skipThisGraph = False
                for textStroke in textAnno.Strokes:
                    if textStroke in graphAnno.Strokes:
                        skipThisGraph = True
                        break
                if skipThisGraph:
                    continue
                
                #Match edges to labels
                for edgeAnno in graphAnno.edge_set:
                    #Find the best choice among 19 evenly spaced points along the edge tailstroke
                    edgeLabelPoints = GeomUtils.strokeNormalizeSpacing(edgeAnno.tailstroke, 19).Points
                    for elp in edgeLabelPoints:
                        dist = GeomUtils.pointDistanceSquared(elp.X, elp.Y, labelCenterPt.X, labelCenterPt.Y)
                        if 'bestmatch' not in labelMatchDict or dist < labelMatchDict['bestmatch']['dist']:
                            labelMatchDict['bestmatch'] = {'edge': edgeAnno, 'dist': dist}

        #labelEdgeMatches contains each label paired with its best edge
        
        #Get the median size
        sizes = sorted([anno.scale for anno in self.labelMap.keys()])

        if len(sizes) > 0:
            medianSize = sizes[len(sizes) / 2]
        else:
            medianSize = 0

        #Have each edge claim a label
        edge2LabelMatching = {}
        for textAnno, matchDict in labelEdgeMatches.items():
            if 'bestmatch' in matchDict \
                and textAnno.scale < medianSize * TuringMachineCollector.LABELMATCH_DISTANCE[1] \
                and textAnno.scale > medianSize * TuringMachineCollector.LABELMATCH_DISTANCE[0]: 
                edgeLabelList = edge2LabelMatching.setdefault(matchDict['bestmatch']['edge'], [])
                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 edgeAnno in edge2LabelMatching:
                    assocLabelsList = edge2LabelMatching[edgeAnno]
                    for label in assocLabelsList:
                        assocSet.add(label)
                        tmAnno.assocLabel2Edge(label, edgeAnno)

            if shouldAddAnno:
                self.getBoard().AnnotateStrokes(tmAnno.getAssociatedStrokes(), tmAnno)
                self.tmMap[tmAnno] = assocSet
            else:
                self.getBoard().UpdateAnnotation(tmAnno, new_strokes = tmAnno.getAssociatedStrokes())
                self.tmMap[tmAnno] = assocSet
Пример #28
0
    def onAnnotationAdded( self, strokes, annotation ):
        "Checks to see if an multiply sign has been added"

        # Find the midpoints         
        ul,br = GeomUtils.strokelistBoundingBox( strokes )
        midpointY = (ul.Y + br.Y) / 2
        midpointX = (ul.X + br.X) / 2
        strokeLen = GeomUtils.strokeLength(strokes[0])

        if annotation.isType(DirectedLine.BT_LineAnnotation):
            possibleAnnotations = self.possibleAnnotations_TB
            otherPossibleAnnotations = self.possibleAnnotations_BT
        elif annotation.isType(DirectedLine.TB_LineAnnotation):
            possibleAnnotations = self.possibleAnnotations_BT
            otherPossibleAnnotations = self.possibleAnnotations_TB

        print len(possibleAnnotations)

        for a in possibleAnnotations:
            s = a.Strokes[0]
            prevStrokeLen = GeomUtils.strokeLength(s)

            # test the the two segments are of similar length
            lengthRange = 0.4
            if prevStrokeLen * (1-lengthRange) < strokeLen < prevStrokeLen * (1+lengthRange):
                pass # were the right length
            else: # not the right length, so lets start again
                continue

            ul,br = GeomUtils.strokelistBoundingBox( [s] )
            prevMidpointY = (ul.Y + br.Y) / 2
            prevMidpointX = (ul.X + br.X) / 2

            # Test that the two segments are close enough horizontally
            if GeomUtils.pointDistance(midpointX, 0, prevMidpointX, 0) < prevStrokeLen * 0.25:
                pass # there are close enough horizontally
            else: # we start again
                continue

            # Test that the two segments are close enough vertically
            if GeomUtils.pointDistance(0,midpointY, 0, prevMidpointY) < prevStrokeLen * 0.25:
                pass # there are close enough vertically
            else: # we start again
                continue

            # we found a match
            possibleAnnotations.remove(a)

            annos = s.findAnnotations()

            annos += self.getBoard().FindAnnotations(strokelist = strokes)

            for i in annos:
                self.getBoard().RemoveAnnotation(i)

            ul,br = GeomUtils.strokelistBoundingBox( strokes + [s] )
            height = ul.Y - br.Y
            self.getBoard().AnnotateStrokes( strokes + [s],  MultAnnotation(height))
            return


        # no match was found, add to the list of possible
        otherPossibleAnnotations.append(annotation)
        return
Пример #29
0
    def mergeCollections( self, from_anno, to_anno ):
        "merge from_anno into to_anno if possible"
        #FIXME: New annotation assumed to be to the right. (Does not handle inserting text in the middle)
        # check that they have compatable scales
        vertOverlapRatio = 0
        horizDistRatio = 2.0
        scaleDiffRatio = 1.5
        scale_diff = to_anno.scale / from_anno.scale
        if scale_diff> scaleDiffRatio or 1/float( scale_diff ) > scaleDiffRatio :
            tc_logger.debug("Not merging %s and %s: Scale Diff is %s" % (to_anno.text, from_anno.text, scale_diff))
            return False
        # check that they are not overlapping
        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 not GeomUtils.boundingboxOverlap( bb_from, bb_to ):
            tc_logger.debug("Not merging Bounding boxes don't overlap")
            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 * horizDistRatio \
          and abs( bb_from[0].X - bb_to[1].X ) > to_anno.scale * horizDistRatio \
          and abs( bb_from[1].X - bb_to[0].X ) > from_anno.scale * horizDistRatio \
          and abs( bb_from[0].X - bb_to[1].X ) > from_anno.scale * horizDistRatio:
            tc_logger.debug("Not merging: horizontal distance too great")
            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 :
            tc_logger.debug("Not merging: vertical overlap too small")
            return False

        # now we know that we want to merge these text annotations
        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