private double computeRecognitionQuality()
        {
            int totalShapes   = 0;
            int correctShapes = 0;

            foreach (Sketch.Shape correctShape in _original.Shapes)
            {
                ShapeType originalType = correctShape.Type;

                if (_toCompare.ShapesL.Exists(delegate(Sketch.Shape s) { return(s.Equals(correctShape)); }))
                {
                    Sketch.Shape resultShape = _toCompare.ShapesL.Find(delegate(Sketch.Shape s) { return(s.Equals(correctShape)); });
                    ShapeType    resultType  = resultShape.Type;

                    totalShapes++;

                    if (resultType == originalType)
                    {
                        correctShapes++;
                    }
                }
            }

            return((double)correctShapes / totalShapes);
        }
예제 #2
0
        /// <summary>
        /// Determine a shape's orientation based on the angles of incoming and outgoing
        /// wires. This method is highly reliable (numerous user studies have shown that
        /// users don't draw wires coming into a gate at meaningless orientations), but
        /// it is sometimes off by 180 degrees (by which I mean Pi, since we are working
        /// in radians).
        ///
        /// NOTE: Currently, this code is not used. HOWEVER, it is extremely reliable. Often
        /// moreso than the orientation obtained from the image recognizer. The refiner should
        /// be able to use this information.
        /// </summary>
        /// <param name="shape1">The shape to check.</param>
        /// <param name="sketch">The sketch containing the shape.</param>
        public override double OrientShape(Sketch.Shape shape, Sketch.Sketch sketch)
        {
            if (shape.Classification == LogicDomain.GATE_CLASS)
            {
                // The gate's angle based on its connected wires.
                double connectionsAngle  = 0;
                double numConnectedWires = 0;

                // Check the slope orientation of adjacent wires
                foreach (Sketch.Shape connectedShape in shape.ConnectedShapes)
                {
                    if (connectedShape.Type.Classification == LogicDomain.WIRE_CLASS)
                    {
                        Sketch.EndPoint endpoint = shape.ClosestEndpointFrom(connectedShape);
                        double          slope    = endpoint.Slope;
                        // negated since our y-axis is inverted (positive-y is down)
                        connectionsAngle -= Math.Atan(Math.Abs(slope));
                        numConnectedWires++;
                    }
                }

                // Get the average angle
                connectionsAngle = connectionsAngle / numConnectedWires;

                // Connections angle is currently in the range [-Pi, Pi], so add Pi
                return(connectionsAngle + Math.PI);
            }
            return(0);
        }
예제 #3
0
        /// <summary>
        /// Look at a particular shape's orientation angle (relative to horizontal)
        /// and correct it if necessary.
        ///
        /// Note: Although the image recognizer gives an orientation angle,
        /// we are not using it. Originally, we did use it, then calculated a new
        /// orientation angle using wire slopes. The new orientation angle replaced
        /// the original angle unless they were close to each other. However,
        /// now we've commented that out and are using only the wire slopes.
        ///
        /// Actually, we do use image recognizer orientation angle, but only
        /// for NOT gates, since both sides of NOT gates have one wire.
        /// </summary>
        /// <param name="shape1">The shape to check.</param>
        /// <param name="sketch">The sketch containing the shape.</param>
        public override void OrientShape(Sketch.Shape shape, Sketch.Sketch sketch)
        {
            if (shape.Classification == LogicDomain.GATE_CLASS && shape.Type != LogicDomain.NOT)
            {
                // The gate's angle based on it's connected wires.
                double connectionsAngle  = 0;
                double numConnectedWires = 0;

                // Check the slope orientation of adjacent wires
                foreach (Sketch.Shape connectedShape in shape.ConnectedShapes)
                {
                    if (connectedShape.Type.Classification == LogicDomain.WIRE_CLASS)
                    {
                        Sketch.EndPoint endpoint = shape.ClosestEndpointFrom(connectedShape);
                        double          slope    = endpoint.Slope;
                        // negated since our y-axis is inverted.
                        connectionsAngle -= Math.Atan(Math.Abs(slope));
                        numConnectedWires++;
                    }
                }

                // Get the average angle
                connectionsAngle = connectionsAngle / numConnectedWires;

                //// Check if the two angles are close enough
                //if (Math.Abs(orientationAngle - connectionsAngle) % Math.PI < CLOSE_ENOUGH ||
                //    Math.PI % Math.Abs(orientationAngle - connectionsAngle) < CLOSE_ENOUGH)
                //    shape.Orient = shape.Orient; // Don't change anything.
                //else
                //    // Use the connections rather than the template rotation angle
                //    shape.Orient = connectionsAngle;

                shape.Orientation = connectionsAngle;
            }
        }
        /// <summary>
        /// Recognize what gate a shape is using the ComboRecgonizer,
        /// and update the shape with the results.
        /// </summary>
        /// <param name="shape">
        /// The shape to recognize (should be a gate)
        /// </param>
        public override void recognize(Sketch.Shape shape, Featurefy.FeatureSketch featureSketch)
        {
            // Initialize variables to store results in
            ShapeType bestType        = new ShapeType();
            float     bestProbability = 0F;
            double    bestOrientation;

            // Recognize the shape and pick out the best option
            Dictionary <ShapeType, double> alternativeTypes = Recognize(shape, out bestOrientation);

            foreach (KeyValuePair <ShapeType, double> pair in alternativeTypes)
            {
                ShapeType type = pair.Key;
                double    prob = pair.Value;
                if (prob > bestProbability)
                {
                    bestType        = type;
                    bestProbability = (float)prob;
                }
            }

            // Update the shape to reflect this recognition
            shape.setRecognitionResults(
                bestType,
                bestProbability,
                alternativeTypes,
                bestOrientation);
        }
예제 #5
0
        private double computeRecognitionQuality()
        {
            int totalShapes   = 0;
            int correctShapes = 0;

            foreach (Sketch.Shape correctShape in _original.Shapes)
            {
                ShapeType originalType = correctShape.Type;

                if (originalType.Equals(new ShapeType())) // skip unidentified shapes
                {
                    continue;
                }

                if (_toCompare.ShapesL.Exists(delegate(Sketch.Shape s) { return(s.GeometricEquals(correctShape)); }))
                {
                    Sketch.Shape resultShape = _toCompare.ShapesL.Find(delegate(Sketch.Shape s) { return(s.GeometricEquals(correctShape)); });
                    ShapeType    resultType  = resultShape.Type;

                    totalShapes++;

                    if (resultType == originalType)
                    {
                        correctShapes++;
                    }
                }
            }

            return((double)correctShapes / totalShapes);
        }
예제 #6
0
        private ConfusionMatrix <ShapeType> computeRecognitionConfusionMatrix()
        {
            ConfusionMatrix <ShapeType> result = new ConfusionMatrix <ShapeType>();

            foreach (Sketch.Shape correctShape in _original.Shapes)
            {
                if (IGNORE_CLASSIFICATIONS.Contains(correctShape.Classification.ToLower()))
                {
                    continue;
                }

                ShapeType originalType = correctShape.Type;

                if (originalType.Equals(new ShapeType())) // skip unidentified shapes
                {
                    continue;
                }

                if (_toCompare.ShapesL.Exists(delegate(Sketch.Shape s) { return(s.GeometricEquals(correctShape)); }))
                {
                    Sketch.Shape resultShape = _toCompare.ShapesL.Find(delegate(Sketch.Shape s) { return(s.GeometricEquals(correctShape)); });
                    ShapeType    resultType  = resultShape.Type;

                    // Record stats
                    result.increment(originalType, resultType);
                }
            }

            return(result);
        }
예제 #7
0
        /// <summary>
        /// Find the two closest shapes to the given shape in the sketch.
        /// </summary>
        /// <param name="shape">Given shape</param>
        /// <param name="sketch">Sketch we are working with</param>
        /// <returns>List of the two closest shapes to the given shape</returns>
        private List <Sketch.Shape> twoClosest(Sketch.Shape shape, Sketch.Sketch sketch)
        {
            double d1 = double.PositiveInfinity; // closer of the two
            double d2 = double.PositiveInfinity; // farther of the two

            Sketch.Shape closest1 = null;
            Sketch.Shape closest2 = null;

            foreach (Sketch.Shape otherShape in sketch.Shapes)
            {
                if (otherShape != shape) // Make sure the shape isn't close to itself
                {
                    double d = sketch.minDistance(shape, otherShape);
                    if (d < d1) // then d is also less than d2
                    {
                        d2       = d1;
                        closest2 = closest1;

                        d1       = d;
                        closest1 = otherShape;
                    }
                    else if (d < d2) // if we're here, then d1 < d < d2
                    {
                        d2       = d;
                        closest2 = otherShape;
                    }
                }
            }

            List <Sketch.Shape> closeShapes = new List <Sketch.Shape>();

            closeShapes.Add(closest1);
            closeShapes.Add(closest2);
            return(closeShapes);
        }
예제 #8
0
        /// <summary>
        /// Draws "ghost" gate for the supplied shape and sets the hoverGate (does nothing if shape is not
        /// a gate)
        /// </summary>
        /// <param name="gate"></param>
        /// <param name="pos"></param>
        public void DrawFeedback(Sketch.Shape shape, bool isHoverGate = false, bool drawingOneGate = true)
        {
            if (!Domain.LogicDomain.IsGate(shape.Type) || ShapeToGate.ContainsKey(shape))
            {
                return;
            }

            KeyValuePair <List <string>, List <string> > shapeIO;

            ShapeToIO.TryGetValue(shape, out shapeIO);
            GhostGate ghostGate = new GhostGate(shape, ref sketchPanel, ref gateDrawer, gateRotated, shapeIO);

            ShapeToGate[shape] = ghostGate;

            ghostGate.SubscribeEvents();

            currGhosts.Add(ghostGate);

            if (isHoverGate)
            {
                hoverGate = ghostGate;

                //if (shape.UserLabeled)
                //  hoverGate.ShowDrawingAdvice();
            }

            if (shape.UserLabeled)
            {
                ghostGate.ShowDrawingAdvice();
            }
        }
예제 #9
0
        /// <summary>
        /// Returns whether or not the strokes that make up a shape were
        /// drawn consecutively
        /// </summary>
        /// <param name="sketch">The sketch that contains the shape</param>
        /// <param name="shape">The shape to be checked</param>
        /// <returns>Whether or not the shape was drawn consecutively</returns>
        public bool isConsecutive(Sketch.Sketch sketch, Sketch.Shape shape)
        {
            Substroke[] strokes    = shape.Substrokes;
            Substroke   sub1       = strokes[0];
            bool        inShape    = false;
            int         shapeIndex = 0;

            for (int i = 0; i < sketch.Substrokes.Length; i++)
            {
                Substroke str = sketch.Substrokes[i];
                if (!inShape && str.Equals(sub1))
                {
                    inShape = true;
                }
                if (shapeIndex == strokes.Length)
                {
                    break;
                }
                if (inShape)
                {
                    sub1 = strokes[shapeIndex];
                    if (!sub1.Equals(str))
                    {
                        return(false);
                    }
                    shapeIndex++;
                }
            }
            return(true);
        }
예제 #10
0
        private List <Tuple <Shape, ShapeType> > computeRecognitionMistakes()
        {
            List <Tuple <Shape, ShapeType> > result = new List <Tuple <Shape, ShapeType> >();

            foreach (Sketch.Shape correctShape in _original.Shapes)
            {
                ShapeType originalType = correctShape.Type;

                if (originalType.Equals(new ShapeType())) // skip unidentified shapes
                {
                    continue;
                }

                if (_toCompare.ShapesL.Exists(delegate(Sketch.Shape s) { return(s.GeometricEquals(correctShape)); }))
                {
                    Sketch.Shape resultShape = _toCompare.ShapesL.Find(delegate(Sketch.Shape s) { return(s.GeometricEquals(correctShape)); });
                    ShapeType    resultType  = resultShape.Type;

                    if (resultType != originalType)
                    {
                        result.Add(Tuple.Create(resultShape, originalType));
                    }
                }
            }

            return(result);
        }
예제 #11
0
        /// <summary>
        /// Change the value of a specified input in the circuit
        /// and update the ink colors accordingly
        /// </summary>
        /// <param name="name">the name of the input used in the circuit</param>
        /// <param name="value">the value (0 or 1) to set it to</param>
        private void setInputValue(Sketch.Shape inputShape, int value)
        {
            sketchPanel.Circuit.setInputValue(inputShape, value);

            colorWiresByValue();
            if (displayingClean)
            {
                ShowToggles();
            }
        }
예제 #12
0
        /// <summary>
        /// Update the recognizer to learn from an example shape.
        ///
        /// Precondition: shape has a valid type
        /// </summary>
        /// <param name="shape">the shape to learn</param>
        public override void learnFromExample(Sketch.Shape shape)
        {
            // If we made a mistake in recognition, make note of that
            BitmapSymbol bs = base.findTemplate(shape.TemplateName);

            if (bs != null && bs.SymbolType != shape.Type)
            {
                _templateUsage[bs.SymbolType][bs] -= errorSubtraction;
            }
            // Update the list of templates accordingly
            removeExample(shape.Type);
            Add(shape.Type, shape.SubstrokesL, shape.createBitmap(100, 100, true));
        }
예제 #13
0
        /// <summary>
        /// Returns the bounding box for the given shape in ink space coordinates.  Optionall colors the strokes
        /// the default color for non-wire symbols.
        /// <see cref="UIConstants.TextFeedbackMechanismSymbolColor"/>
        /// </summary>
        /// <param name="shape">the shape for which the bounding box will be calculated</param>
        /// <param name="substroke2InkTable">A hashtable mapping Ink Stroke IDs to Sketch Substroke IDs.
        /// This hashtable allows the Feedback Mechanism to assocate Ink Strokes drawn to screen
        /// with their corresponding (labeled) Sketch substrokes.</param>
        /// <param name="colorStrokes">True iff the microsoft ink strokes should be colored while calculating
        /// the bounding box (for efficiency's sake).</param>
        /// <returns>A System.Drawing.Rectangle representing the bounding box
        /// for the given shape (in ink space coordinates)</returns>
        private Rectangle calculateBoundingBox(Sketch.Shape shape, Hashtable substroke2InkTable, bool colorStrokes)
        {
            // Compute the bounding box of all the ink strokes
            // associated with this shape
            Rectangle boundingBox = Rectangle.Empty;

            foreach (Sketch.Substroke substroke in shape.Substrokes)
            {
                if (!substroke2InkTable.Contains(substroke.XmlAttrs.Id))
                {
                    // If, for some reason, there is no ink stroke
                    // that corresponds to this substroke, skip it
                    continue;
                }

                Microsoft.Ink.Stroke iStroke = (Microsoft.Ink.Stroke)substroke2InkTable[substroke.XmlAttrs.Id];

                if (colorStrokes)
                {
                    iStroke.DrawingAttributes.Color = UIConstants.TextFeedbackMechanismSymbolColor;
                }

                Rectangle strokeBox = iStroke.GetBoundingBox();

                if (boundingBox.IsEmpty)
                {
                    boundingBox = strokeBox;
                }
                else
                {
                    if (strokeBox.X < boundingBox.X)
                    {
                        boundingBox.X = strokeBox.X;
                    }
                    if (strokeBox.Y < boundingBox.Y)
                    {
                        boundingBox.Y = strokeBox.Y;
                    }
                    if (strokeBox.Bottom > boundingBox.Bottom)
                    {
                        boundingBox.Height = strokeBox.Bottom - boundingBox.Y;
                    }
                    if (strokeBox.Right > boundingBox.Right)
                    {
                        boundingBox.Width = strokeBox.Right - boundingBox.X;
                    }
                }
            }

            return(boundingBox);
        }
예제 #14
0
        /// <summary>
        /// Returns a list of all the points that make up a shape
        /// </summary>
        /// <param name="shape">The shape</param>
        /// <returns>a list of all the points within the shape</returns>
        public List <Point> findPointsInShape(Sketch.Shape shape)
        {
            List <Substroke> subs   = shape.SubstrokesL;
            List <Point>     points = new List <Point>();

            foreach (Substroke sub in subs)
            {
                foreach (Point p in sub.Points)
                {
                    points.Add(p);
                }
            }
            return(points);
        }
예제 #15
0
        /// <summary>
        /// Recognizes a shape and updates values in shape (through setRecognitionResults).
        /// Also notes which template was used for template ranking purposes.
        /// </summary>
        /// <param name="shape"></param>
        /// <param name="featureSketch"></param>
        /// <returns></returns>
        public override RecognitionInterfaces.RecognitionResult recognize(Sketch.Shape shape, Featurefy.FeatureSketch featureSketch)
        {
            // Gaaghaghagahga
            // C# has one flaw, and I found it:
            // http://www.simple-talk.com/community/blogs/simonc/archive/2010/07/14/93495.aspx
            // In short, we have to cast the result from the base class because that method
            // must return a generic "RecognitionResult" and cannot return the better
            // "ImageRecognitionResult," even though doing so would be perfectly type-safe. =(

            ImageRecognitionResult result = (ImageRecognitionResult)base.recognize(shape, featureSketch);
            ShapeType type         = result.Type;
            string    templateName = result.TemplateName;

            ++_templateUsage[type][base.findTemplate(templateName)]; // increment the number of times that BitmapSymbol has been used
            return(result);
        }
예제 #16
0
        /// <summary>
        /// Prints errors from parsing the circuit.
        /// </summary>
        private void printErrors()
        {
            if (_parseErrors.Count == 0)
            {
                return;
            }

            Console.WriteLine("The following errors arose in parsing the circuit:");
            foreach (ParseError error in _parseErrors)
            {
                Console.WriteLine(error.Explanation);
                Sketch.Shape errShape = error.Where;
            }

            Console.WriteLine();
        }
예제 #17
0
        /// <summary>
        /// Refreshes the underlying data structures corresponding to the inkStroke after the
        /// inkStroke has been modified (moved or resized)
        /// </summary>
        /// <param name="inkStroke">The Ink Stroke to modify</param>
        public void UpdateInkStroke(System.Windows.Ink.Stroke inkStroke)
        {
            // Delete the old stroke but save its shape for the new Stroke
            Sketch.Shape oldShape = GetSketchSubstrokeByInk(inkStroke).ParentShape;
            DeleteStroke(inkStroke);

            // Add the new stroke to the Sketch and put it in the old Shape
            AddStroke(inkStroke);
            Sketch.Substroke newSubstroke = GetSketchSubstrokeByInk(inkStroke);
            if (oldShape != null)
            {
                oldShape.AddSubstroke(newSubstroke);
                if (!Sketch.ShapesL.Contains(oldShape))
                {
                    Sketch.AddShape(oldShape);
                }
            }
        }
        /// <summary>
        /// Update the Naive Bayes classifier to learn from an example shape.
        /// </summary>
        /// <param name="shape"></param>
        public void Learn(Sketch.Shape shape)
        {
            double believedOrientation;
            Dictionary <string, object> features = GetIndRecognitionResults(shape, out believedOrientation);

            // Since the combo classifier is trained with such a large
            // number of training examples (1600+), each additional
            // learning example has an extremely small effect.
            // However, we want the error-corrected learning to have a
            // more meaningful effect. So, we add the same example
            // multiple times to the bayes classifier.

            for (int i = 0; i < 5; i++) // MAGIC NUMBER
            {
                _comboClassifier.AddExample(shape.Type, features);
            }

            _comboClassifier.UpdateClassifier();
        }
예제 #19
0
        /// <summary>
        /// Returns the time it took to draw the shape
        /// </summary>
        /// <param name="shape">The shape</param>
        /// <returns>total time it took to draw the shape in ms</returns>
        public ulong findShapeTime(Sketch.Shape shape)
        {
            double       minTime = Double.PositiveInfinity;
            double       maxTime = Double.NegativeInfinity;
            List <Point> points  = findPointsInShape(shape);

            foreach (Point p in points)
            {
                if ((Double)(p.Time) < minTime)
                {
                    minTime = p.Time;
                }
                if ((Double)(p.Time) > maxTime)
                {
                    maxTime = (Double)(p.Time);
                }
            }
            return((ulong)(maxTime - minTime));
        }
예제 #20
0
        /// <summary>
        /// Update the input mapping dictionary to reflect an input
        /// recently added to the circuit
        /// </summary>
        /// <param name="input">The shape (label) corresponding to the input</param>
        private void addInput(Sketch.Shape inputShape)
        {
            if (debug)
            {
                Console.WriteLine("Trying to add " + inputShape.Type.Name + " called " + inputShape.Name + " to inputs");
            }

            ListSet <String> strokeIDs = new ListSet <String>();

            foreach (Sketch.Substroke substroke in inputShape.Substrokes)
            {
                strokeIDs.Add(sketchPanel.InkSketch.GetInkStrokeIDBySubstroke(substroke));
            }

            if (!inputMapping.ContainsKey(inputShape))
            {
                inputMapping.Add(inputShape, strokeIDs);
            }
        }
예제 #21
0
        /// <summary>
        /// Update the output mapping dictionary to reflect an output
        /// recently added to the circuit
        /// </summary>
        /// <param name="ouput">The shape (label) corresponding to the output</param>
        public void addOutput(Sketch.Shape outputShape)
        {
            if (debug)
            {
                Console.WriteLine("Trying to add " + outputShape.Type + " called " + outputShape.Name + " to outputs");
            }

            ListSet <String> strokeIDs = new ListSet <string>();

            foreach (Sketch.Substroke substroke in outputShape.Substrokes)
            {
                strokeIDs.Add(sketchPanel.InkSketch.GetInkStrokeIDBySubstroke(substroke));
            }

            if (!outputMapping.ContainsKey(outputShape.Name))
            {
                outputMapping.Add(outputShape.Name, strokeIDs);
            }
        }
예제 #22
0
        /// <summary>
        /// Uses the RecognitionInterfaces.Recognizer recognize method
        /// which recognizes and assigns the type of a shape.  This
        /// implementation allows the use of the learnFromExample
        /// method in Interface Functions.
        /// </summary>
        /// <param name="shape">The shape to recognize</param>
        /// <param name="featureSketch">The featureSketch to use</param>
        public override void recognize(Sketch.Shape shape, Featurefy.FeatureSketch featureSketch)
        {
            BitmapSymbol      unknown = new BitmapSymbol(shape.SubstrokesL);
            List <SymbolRank> results = unknown.Recognize(_templates);

            if (results.Count > 0)
            {
                // Populate the dictionary of alterateTypes with all of the ShapeTypes in results
                Dictionary <ShapeType, double> alternateTypes = new Dictionary <ShapeType, double>();

                if (debug)
                {
                    Console.WriteLine("\nRecognition results: ");
                }

                foreach (SymbolRank result in results)
                {
                    if (!alternateTypes.ContainsKey(result.SymbolType))
                    {
                        alternateTypes.Add(result.SymbolType, getProbability(result.SymbolType, results));
                    }

                    if (debug)
                    {
                        Console.WriteLine(result.SymbolType + " with template " + result.SymbolName);
                    }
                }

                ShapeType type = results[0].SymbolType;          // the most likely type

                float probability = (float)alternateTypes[type]; // grab the probability of our most likely type

                alternateTypes.Remove(type);                     // the most likely type is NOT an alternate

                shape.setRecognitionResults(
                    type,
                    probability,
                    alternateTypes,
                    results[0].BestOrientation,
                    results[0].SymbolName);
            }
        }
예제 #23
0
        private ConfusionMatrix <ShapeType> computeRecognitionConfusionMatrix()
        {
            ConfusionMatrix <ShapeType> result = new ConfusionMatrix <ShapeType>();

            foreach (Sketch.Shape correctShape in _original.Shapes)
            {
                ShapeType originalType = correctShape.Type;

                if (_toCompare.ShapesL.Exists(delegate(Sketch.Shape s) { return(s.Equals(correctShape)); }))
                {
                    Sketch.Shape resultShape = _toCompare.ShapesL.Find(delegate(Sketch.Shape s) { return(s.Equals(correctShape)); });
                    ShapeType    resultType  = resultShape.Type;

                    // Record stats
                    result.increment(originalType, resultType);
                }
            }

            return(result);
        }
예제 #24
0
        /// <summary>
        /// Once strokes are grouped, turn the stroke pairs into shapes.
        /// </summary>
        /// <param name="pairs">The list of stroke pairs that should be merged into shapes.</param>
        /// <param name="sketch">The sketch the strokes exist in; where the shapes should be created.</param>
        private void makeShapes(List <Sketch.StrokePair> pairs, Sketch.Sketch sketch)
        {
            foreach (Sketch.StrokePair pair in pairs)
            {
                Sketch.Shape shape1 = pair.Item1.ParentShape;
                Sketch.Shape shape2 = pair.Item2.ParentShape;

                // If they've already been merged, forget it.
                if (shape1 == shape2)
                {
                    continue;
                }

                // If either one is null, we have a problem!
                if (shape1 == null || shape2 == null)
                {
                    throw new Exception("Cannot merge substrokes " + pair.Item1 + " and " + pair.Item2 + "; one or both are missing a parent shape");
                }

                // Don't merge any user-specified shapes.
                if (shape1.AlreadyGrouped || shape2.AlreadyGrouped)
                {
                    continue;
                }

                sketch.mergeShapes(shape1, shape2);
            }

#if DEBUG
            Console.WriteLine("Your sketch has " + sketch.Shapes.Length + " distinct shapes.");
            int gates = 0;
            foreach (Sketch.Shape shape in sketch.Shapes)
            {
                if (shape.Classification == LogicDomain.GATE_CLASS)
                {
                    gates++;
                }
            }
            Console.WriteLine(gates + " of those shapes are gates.");
#endif
        }
        /// <summary>
        /// Draws "ghost" gate for the supplied shape
        /// </summary>
        /// <param name="gate"></param>
        /// <param name="pos"></param>
        public void DrawFeedback(Sketch.Shape shape, bool isHoverGate = false)
        {
            if (!Domain.LogicDomain.IsGate(shape.Type))
            {
                return;
            }

            GhostGate ghostGate = new GhostGate(shape, ref sketchPanel, ref gateDrawer);

            ghostGate.SubscribeEvents();
            currGhosts.Add(ghostGate);

            if (isHoverGate)
            {
                hoverGate = ghostGate;
            }

            if (shape.UserLabeled)
            {
                ghostGate.ShowDrawingAdvice();
            }
        }
예제 #26
0
        /// <summary>
        /// Determines if shape2 is contained in the boundingbox of shape1
        /// more accurately it checks that at most some fraction of the points are not contained
        /// </summary>
        /// <param name="shape2"></param>
        /// <param name="shape1"></param>
        /// <returns></returns>
        private bool contains(Sketch.Shape shape1, Sketch.Shape shape2)
        {
            RectangleF bbox1  = Featurefy.Compute.BoundingBox(shape1.Points.ToArray());
            int        badPts = 0;

            foreach (Sketch.Point pt in shape2.Points)
            {
                System.Drawing.PointF pf = pt.SysDrawPointF;
                if (!(bbox1.Contains(pf)))
                {
                    badPts++;
                }
            }
            //THIS IS A MAGIC NUMBER I PULLED OUT OF THE AIR
            double MAXIMUM_BAD_PERCENT = .2;

            if (shape2.Points.Count != 0)
            {
                return(MAXIMUM_BAD_PERCENT > badPts / shape2.Points.Count);
            }
            return(true);
        }
예제 #27
0
 public ParseError(string errorExplanation, Sketch.Shape shape)
 {
     _errorExplanation = errorExplanation;
     _userExplanation  = null;
     _shape            = shape;
 }
예제 #28
0
 /// <summary>
 /// Recognizes a shape and updates values in shape (through setRecognitionResults).
 /// Also notes which template was used for template ranking purposes.
 /// </summary>
 /// <param name="shape">The shape to recognize</param>
 /// <param name="featureSketch">The featureSketch containing the shape.
 ///     Never used in this function, but kept around because this function is overriding another.</param>
 public override void recognize(Sketch.Shape shape, Featurefy.FeatureSketch featureSketch)
 {
     base.recognize(shape, featureSketch);
     //++_templateUsage[shape.Type][base.findTemplate(shape.TemplateName)]; // increment the number of times that BitmapSymbol has been used
 }
예제 #29
0
        public Sketch.Shape align(Sketch.Shape shape)
        {
            Sketch.Shape aligned = shape.Clone();
            string       imId    = aligned.Id.ToString();

            Dictionary <Substroke, int> votes = new Dictionary <Substroke, int>();

            foreach (Substroke s in aligned.SubstrokesL)
            {
                votes.Add(s, 0);
            }

            foreach (AlignFeature af in _tf.Keys)
            {
                double    goodness = Double.PositiveInfinity;              // Best match so far
                Substroke lbest    = null;
                foreach (Substroke ss in aligned.SubstrokesL)
                {
                    double current = match(ss, aligned, af);
                    if (current < goodness)
                    {
                        lbest    = ss;
                        goodness = current;
                    }
                }
                ++votes[lbest];
            }
            int       maxvote = 0;
            Substroke best    = null;

            foreach (KeyValuePair <Substroke, int> kvp in votes)
            {
                if (kvp.Value > maxvote)
                {
                    maxvote = kvp.Value;
                    best    = kvp.Key;
                }
            }

            if (best == null)
            {
                return(shape);
            }

            // Step 1 is to uniformly scale so that the keystroke and the match stroke are the same length
            double scaleFactor = _template.SpatialLength / best.SpatialLength;

            aligned.scale(scaleFactor);

            // Next, let's find some points in the template
            Point TTop = _template.PointsL[0];
            Point TBottom;

            findFarthestPointFrom(TTop, _template, out TBottom);
            if (TBottom.Y > TTop.Y)
            {
                swapPts(ref TTop, ref TBottom);
            }

            double TMiddleX = (TTop.X + TBottom.X) / 2.0;
            double TMiddleY = (TTop.Y + TBottom.Y) / 2.0;

            double TCentroidX = _shape.Centroid[0];
            double TCentroidY = _shape.Centroid[1];

            // Now some points in the match
            Point BTop = best.PointsL[0];
            Point BBottom;

            findFarthestPointFrom(BTop, best, out BBottom);
            if (BBottom.Y > BTop.Y)
            {
                swapPts(ref BTop, ref BBottom);
            }

            double BMiddleX   = (BTop.X + BBottom.X) / 2.0;
            double BMiddleY   = (BTop.Y + BBottom.Y) / 2.0;
            double BCentroidX = aligned.Centroid[0];
            double BCentroidY = aligned.Centroid[1];

            // The first step in alignment is rotation. We want the angle between the line BMiddle-BCentroid and horizontal to
            // be the same as the angle between the line TMiddle-TCentroid and horizontal.
            double ttheta     = Math.Atan2(TCentroidY - TMiddleY, TCentroidX - TMiddleX);
            double btheta     = Math.Atan2(BCentroidY - BMiddleY, BCentroidX - BMiddleX);
            double deltaTheta = ttheta - btheta;

            aligned.rotate(deltaTheta);

            /*
             * BMiddleX = (BTop.X + BBottom.X) / 2.0;
             * BMiddleY = (BTop.Y + BBottom.Y) / 2.0;
             * BCentroidX = shape.Centroid[0];
             * BCentroidY = shape.Centroid[1];
             * btheta = Math.Atan2(BCentroidY - BMiddleY, BCentroidX - BMiddleX);
             *
             * Substroke middleToCenter = new Substroke(new Point[2] {
             *      new Point((float)BMiddleX, (float)BMiddleY), new Point((float)BCentroidX,(float)BCentroidY)
             * }, new XmlStructs.XmlShapeAttrs(true));
             * middleToCenter.XmlAttrs.Time = (ulong)DateTime.Now.Ticks;
             * aligned.AddSubstroke(middleToCenter);
             * // Finally, we want to scale along the Middle-Centroid axis such that the lengths of the Middle-Centroid lines are the same
             * scaleFactor = Math.Sqrt(Math.Pow(TCentroidX - TMiddleX, 2) + Math.Pow(TCentroidY - TMiddleY, 2)) / Math.Sqrt(Math.Pow(BCentroidX - BMiddleX, 2) + Math.Pow(BCentroidY - BMiddleY, 2));
             * aligned.rotate(-btheta);
             * SymbolRec.Image.Image image = new SymbolRec.Image.Image(64, 64, aligned);
             * image.writeToBitmap(String.Format("{0}\\output\\shape_{1}_postrotate.png", System.IO.Directory.GetCurrentDirectory(), imId));
             * aligned.transform(new MathNet.Numerics.LinearAlgebra.Matrix(new double[][] { new double[] { 1, 0, 0 }, new double[] { 0, scaleFactor, 0 }, new double[] { 0, 0, 1 } }));
             * image = new SymbolRec.Image.Image(64, 64, aligned);
             * image.writeToBitmap(String.Format("{0}\\output\\shape_{1}_postaxialscale.png", System.IO.Directory.GetCurrentDirectory(), imId));
             * aligned.rotate(ttheta);
             * image = new SymbolRec.Image.Image(64, 64, aligned);
             * image.writeToBitmap(String.Format("{0}\\output\\shape_{1}_postnextrotate.png", System.IO.Directory.GetCurrentDirectory(), imId));
             */
            return(aligned);
        }
예제 #30
0
 /// <summary>
 /// Returns the number of substrokes in a shape
 /// </summary>
 /// <param name="shape">The shape</param>
 /// <returns>The number of substrokes in the shape</returns>
 public int numSubStrokes(Sketch.Shape shape)
 {
     return(shape.Substrokes.Length);
 }