Example #1
0
        public SketchModification chooseAction(List <SketchModification> availableActions, Sketch.Sketch sketch)
        {
            SketchModification result = null;

            double max = 0;

            foreach (SketchModification action in availableActions)
            {
                double change = action.benefit();
                if (change > max)
                {
                    result = action;
                    max    = change;
                }
            }

            return(result);
        }
Example #2
0
        public List <SketchModification> SketchModifications(Featurefy.FeatureSketch featureSketch)
        {
            Sketch.Sketch sketch = featureSketch.Sketch;

            if (debug)
            {
                Console.WriteLine("Sketch Modifications:");
            }

            // Used to assemble the list of results
            List <SketchModification> results = new List <SketchModification>();

            // Precompute closest contexts for each shape
            Dictionary <Shape, Tuple <double, ConnectionContext> > closestContexts = new Dictionary <Shape, Tuple <double, ConnectionContext> >();

            foreach (Shape shape in sketch.Shapes)
            {
                closestContexts.Add(shape, _domain.ClosestContext(shape));
            }

            // ==========================================================================================================

            /*
             * Operation zero: running the connector is ALWAYS an option.
             */

            //results.Add(new SketchModification(sketch, new RunConnectorOperation(featureSketch, _connector), computeEnergy));

            // ==========================================================================================================

            /*
             * First things first: missing connections
             * This takes care of obvious connector problems. If there is a wire with a dangling endpoint and a
             * shape that would be better off connected to a wire, we make that connection. The benefit is:
             *    benefit = 1 / distance
             * where "distance" is the minimum distance from the dangling endpoint to the shape. This will favor
             * close connections over distant ones.
             */

            List <EndPoint> wiresMissingConnections        = findWireEndpointsMissingConnections(sketch);
            List <Shape>    nonWiresMissingWireConnections = findNonWiresMissingConnections(sketch, closestContexts);

            foreach (EndPoint wireEndpoint in wiresMissingConnections)
            {
                foreach (Shape shape in nonWiresMissingWireConnections)
                {
                    Shape wire = wireEndpoint.ParentShape;
                    if (debug)
                    {
                        Console.WriteLine("ACTION (connect wire endpoint): " + sketch + ", " + wire + ", " + wireEndpoint + ", " + shape);
                    }
                    var op           = new ConnectEndpointOperation(sketch, wireEndpoint, shape);
                    var modification = new SketchModification(featureSketch, op, computeEnergy);
                    results.Add(modification);
                }
            }

            // ==========================================================================================================

            /*
             * Second: relabeling
             * Now we go through every shape and see if its context would be better matched as a different shape.
             * If so, we can change the shape. The benefit is the % improvement in context score plus the %
             * improvement in recognition quality.
             */

            foreach (Shape shape in sketch.Shapes)
            {
                if (shape.AlreadyLabeled)
                {
                    continue;
                }

                Tuple <double, ConnectionContext> currentContext = closestContexts[shape];
                List <ShapeType> allTypes = LogicDomain.Types;

                foreach (ShapeType otherType in AlternateTypes(shape.Type))
                {
                    if (debug)
                    {
                        Console.WriteLine("ACTION (relabel shape): " + shape + ", " + otherType);
                    }
                    var op           = new RelabelShapeOperation(sketch, shape, RecognizeAsType(shape, otherType, featureSketch));
                    var modification = new SketchModification(featureSketch, op, computeEnergy);
                    results.Add(modification);
                }
            }

            // ==========================================================================================================

            /*
             * Third: stroke steal
             * This works as follows:
             *
             * For every shape, get the set of closeSubstrokes (within a certain threshold).
             *     For every substroke in closeSubstrokes
             *         generate a steal modification (substroke --> shape)
             *
             * The steal modifications should have their benefit based on
             *    (1) connection contexts
             *    (2) recognition quality
             */

            foreach (Shape thief in sketch.Shapes)
            {
                if (thief.AlreadyLabeled)
                {
                    continue;
                }

                List <Substroke> closeSubstrokes = findSubstrokesCloseTo(thief, sketch, STROKE_STEAL_THRESHOLD);

                foreach (Substroke gem in closeSubstrokes) // thiefs steal gems
                {
                    Shape victim = gem.ParentShape;        // thiefs steal from victims

                    if (victim.AlreadyLabeled)
                    {
                        continue;
                    }

                    // find the thief's new type
                    var newThiefSubstrokes = new List <Substroke>(thief.SubstrokesL);
                    newThiefSubstrokes.Add(gem);
                    RecognitionResult newThiefRecognition = Identify(newThiefSubstrokes, featureSketch);

                    if (debug)
                    {
                        Console.WriteLine("ACTION (steal stroke): " + thief + ", " + victim + ", " + gem);
                    }
                    var stealOp        = new StrokeStealOperation(sketch, thief, gem);
                    var relabelThiefOp = new RelabelShapeOperation(sketch, thief, newThiefRecognition);
                    var runConnectorOp = new RunConnectorOperation(featureSketch, _connector);
                    ISketchOperation op;

                    // if the victim will still be around after the steal
                    if (victim.Substrokes.Length > 1)
                    {
                        var newVictimSubstrokes = new List <Substroke>(victim.SubstrokesL);
                        newVictimSubstrokes.Remove(gem);
                        RecognitionResult newVictimRecognition = Identify(newVictimSubstrokes, featureSketch);

                        var relabelVictimOp = new RelabelShapeOperation(sketch, victim, newVictimRecognition);

                        op = new CompoundSketchOperation(stealOp, relabelThiefOp, relabelVictimOp, runConnectorOp);
                    }
                    else
                    {
                        op = new CompoundSketchOperation(stealOp, relabelThiefOp, runConnectorOp);
                    }
                    var modification = new SketchModification(featureSketch, op, computeEnergy);
                    results.Add(modification);
                }
            }

            if (debug && results.Count == 0)
            {
                Console.WriteLine("(none)");
            }

            // Keep only the ones greater than the cutoff
            results = results.FindAll(r => { return(r.benefit() > BENEFIT_CUTOFF); });

            return(results);
        }