//fill this method in with code which will execute
        //once for each cycle of the engine
        public override void Fire()
        {
            Init();  //be sure to leave this here
            ModuleView naSource = theNeuronArray.FindModuleByLabel("UKS");

            if (naSource == null)
            {
                return;
            }
            uks = (ModuleUKS)naSource.TheModule;

            Thing areaParent  = uks.GetOrAddThing("CurrentlyVisible", "Visual");
            Thing colorParent = uks.GetOrAddThing("Color", "Visual");

            foreach (Thing area in areaParent.Children)
            {
                var   values = uks.GetValues(area);
                float hue    = values["Hue+"];
                float sat    = values["Sat+"];
                float lum    = values["Lum+"];

                Thing theColor = null;
                foreach (Thing color in colorParent.Children)
                {
                    var   valuesc = uks.GetValues(color);
                    float huec    = valuesc["Hue+"];
                    float satc    = valuesc["Sat+"];
                    float lumc    = valuesc["Lum+"];

                    //TODO add better match algorithm
                    if (huec == hue && Abs(satc - sat) < 0.2f && Abs(lumc - lum) < 0.2f)
                    {
                        theColor = color;
                        break;
                    }
                }
                if (theColor == null)
                {
                    theColor = uks.AddThing("c*", colorParent);
                    uks.SetValue(theColor, hue, "Hue", 2);
                    uks.SetValue(theColor, sat, "Sat", 2);
                    uks.SetValue(theColor, lum, "Lum", 2);
                }
                area.AddReference(theColor);
            }

            //if you want the dlg to update, use the following code whenever any parameter changes
            // UpdateDialog();
        }
示例#2
0
        private void SetAreasToUKS()
        {
            Thing currentlyVisibleParent = uks.GetOrAddThing("CurrentlyVisible", "Visual");

            uks.DeleteAllChilden(currentlyVisibleParent);
            Thing valueParent = uks.GetOrAddThing("Value", "Thing");

            foreach (Area a in areas)//all the areas currently visible
            {
                Thing theArea = uks.AddThing("Area*", currentlyVisibleParent);

                uks.SetValue(theArea, a.greatestLength, "Siz", 0);
                uks.SetValue(theArea, (float)a.orientation, "Ang", 2);
                uks.SetValue(theArea, (float)a.centroid.X, "CtrX", 0);
                uks.SetValue(theArea, (float)a.centroid.Y, "CtrY", 0);
                uks.SetValue(theArea, (float)a.avgColor.hue / 360f, "Hue", 2);
                uks.SetValue(theArea, (float)a.avgColor.saturation, "Sat", 2);
                uks.SetValue(theArea, (float)a.avgColor.luminance, "Lum", 2);

                List <Thing> theCorners = new List <Thing>();
                foreach (Corner c in a.areaCorners)
                {
                    theCorners.Add(uks.AddThing("Cnr*", theArea));

                    Thing theLocation = uks.Valued(c.loc, uks.Labeled("Point").Children);
                    if (theLocation == null)
                    {
                        theLocation   = uks.AddThing("p*", "Point");
                        theLocation.V = c.loc;
                    }
                    theLocation.AddParent(theCorners.Last());
                }
                //add the reference links
                if (theCorners.Count == 2)
                {
                    theCorners[0].AddReference(theCorners[1]); //add lengths to these?
                    theCorners[1].AddReference(theCorners[0]);
                }
                else
                {
                    for (int i = 0; i < theCorners.Count; i++)
                    {
                        int j = a.areaCorners.IndexOf(a.areaCorners[i].c1);
                        int k = a.areaCorners.IndexOf(a.areaCorners[i].c2);
                        if (k == -1 || j == -1 || j == k)
                        { // the area is not valid, delete it
                            uks.DeleteAllChilden(theArea);
                            uks.DeleteThing(theArea);
                            break;
                        }
                        theCorners[i].AddReference(theCorners[j]); //add lengths to these?
                        theCorners[i].AddReference(theCorners[k]);
                    }
                }
            }
        }
示例#3
0
        //Areas have absolute coordinates, Shapes are completely relative
        Thing CreateTempShapeFromArea(Thing theArea)
        {
            foreach (Thing t in theArea.Children)
            {
                if (t.Children.Count == 0)
                {
                    return(null);
                }
            }
            if (!theArea.Label.Contains("Area"))
            {
                return(null);
            }
            //this abstracts a shape from a specific area
            Thing theShape = uks.AddThing("TempShape", new Thing[] { }); //the resultant shape

            //Areas are randomly ordered. We want the Shape to be in sequence around the shape because that's easier to search

            //first find the top/left corner
            Thing topLeft = null;

            float greatestLength = uks.GetValues(theArea)["Siz+"];
            Angle ang            = uks.GetValues(theArea)["Ang+"];

            uks.SetValue(theShape, ang, "PrefAng", 2);

            for (int i = 0; i < theArea.Children.Count; i++)
            {
                Thing corner = theArea.Children[i];
                if (topLeft == null)
                {
                    topLeft = corner;
                }
                Point p1 = (Point)corner.References[0].T.Children[0].V;

                if (p1.Y < ((Point)topLeft.Children[0].V).Y ||
                    (p1.Y == ((Point)topLeft.Children[0].V).Y && p1.X < ((Point)topLeft.Children[0].V).X))
                {
                    topLeft = theArea.Children[i];
                }
            }


            //these both are for the area
            Thing nextAreaCorner = topLeft.References[0].T;
            Thing prevAreaCorner = topLeft;

            //these are for the shape
            Thing newShapeCorner   = uks.AddThing("Cnr*", theShape);
            Thing firstShapeCorner = newShapeCorner;

            while (nextAreaCorner != topLeft)
            {
                //which area reference points to the next corner (not the previous)
                int refIndex = 0;
                if (nextAreaCorner.References.Count > 1 && nextAreaCorner.References[0].T == prevAreaCorner)
                {
                    refIndex = 1;
                }
                Thing nextShapeCorner = AddAngleandRelationship(greatestLength, nextAreaCorner, newShapeCorner, refIndex, theShape);

                newShapeCorner = nextShapeCorner;

                prevAreaCorner = nextAreaCorner;
                nextAreaCorner = nextAreaCorner.References[refIndex].T; //which way do we go?
            }

            int refIndex1 = 0;

            if (nextAreaCorner.References.Count > 1 && nextAreaCorner.References[0].T == prevAreaCorner)
            {
                refIndex1 = 1;
            }
            AddAngleandRelationship(greatestLength, nextAreaCorner, newShapeCorner, refIndex1, theShape, firstShapeCorner);

            return(theShape);
        }
        //fill this method in with code which will execute
        //once for each cycle of the engine
        public override void Fire()
        {
            Init();  //be sure to leave this here

            ModuleView naSource = theNeuronArray.FindModuleByLabel("UKS");

            if (naSource == null)
            {
                return;
            }
            uks = (ModuleUKS)naSource.TheModule;

            Thing mentalModel            = uks.GetOrAddThing("MentalModel", "Visual");
            Thing currentlyVisibleParent = uks.GetOrAddThing("CurrentlyVisible", "Visual");
            Thing motionParent           = uks.GetOrAddThing("Motion", "Visual");



            //Things which disappeared in the last cycle need special treatment to remove from mental model & relationships but not the known object
            foreach (Thing t in motionParent.Children)
            {
                if (t.Label.Contains("Disappeared"))
                {
                    Thing thingToRemove = t.Children[0];
                    for (int i = thingToRemove.Children.Count - 1; i >= 0; i--)
                    {
                        Thing child = thingToRemove.Children[i];
                        thingToRemove.RemoveChild(child);
                    }
                    uks.DeleteThing(thingToRemove);
                }
            }

            uks.DeleteAllChilden(motionParent);

            //build little lists of things which moved or appeared so we can also be left with things which things which disappeared
            List <Thing> matchedThings  = new List <Thing>();
            List <Thing> movedThings    = new List <Thing>();
            List <Thing> movedThingsNew = new List <Thing>();
            List <Thing> newThings      = new List <Thing>();

            foreach (Thing visibleArea in currentlyVisibleParent.Children)
            {
                Thing matchedThing = null;
                foreach (Thing storedArea in mentalModel.Children)
                {
                    Debug.Assert(visibleArea.Children.Count == 1);
                    if (storedArea.Children.Count != 1)
                    {
                        continue;
                    }
                    if (storedArea.Children[0] == visibleArea.Children[0]) //are these instances of the same object type?
                    {
                        var   values     = uks.GetValues(visibleArea);
                        var   prevValues = uks.GetValues(storedArea);
                        Point c1         = new Point(uks.GetValue(visibleArea, "CtrX+"), uks.GetValue(visibleArea, "CtrY+"));
                        Point c2         = new Point(uks.GetValue(storedArea, "CtrX+"), uks.GetValue(storedArea, "CtrY+"));
                        float dist       = (float)(c1 - c2).Length;
                        if (dist < (uks.GetValue(visibleArea, "Siz+") + uks.GetValue(storedArea, "Siz+")) / 2)
                        {
                            //these are probably the same object...is motion detected?
                            var changes = uks.GetChangedValues(visibleArea, storedArea);
                            if (changes.ContainsKey("Siz+") ||
                                changes.ContainsKey("CtrX+") ||
                                changes.ContainsKey("CtrY+") ||
                                changes.ContainsKey("Ang+"))
                            {
                                Thing t1 = uks.AddThing("Moved", motionParent);
                                t1.AddChild(storedArea);
                                foreach (var change in changes)
                                {
                                    uks.SetValue(t1, change.Value, change.Key, 0);
                                }
                                movedThings.Add(storedArea);
                                movedThingsNew.Add(visibleArea);
                            }
                            matchedThing = storedArea;
                            goto objectMatch;
                        }
                    }
                }
                //there is no matching object, this just appeared!
                newThings.Add(visibleArea);
                Thing m = uks.AddThing("Appeared*", motionParent);
                m.AddChild(visibleArea);
                continue;

                objectMatch :;
                if (matchedThing != null)
                {
                    matchedThings.Add(matchedThing);
                }
            }


            for (int i = mentalModel.Children.Count - 1; i >= 0; i--)
            {
                Thing t = mentalModel.Children[i];
                if (!matchedThings.Contains(t))
                {
                    Thing m = uks.AddThing("Disappeared*", motionParent);
                    m.AddChild(t);
                    mentalModel.RemoveChild(t);
                    Thing attn = uks.Labeled("ATTN");
                    if (attn != null)
                    {
                        attn.RemoveReference(t);
                    }
                }
            }

            if (motionParent.Children.Count > 1)
            {
                //analyze motion
                //if only a few objects moved, they moved
                //if all objects moved in same direction, it's becaue POV turned
                //if all objects moved in directions radiating to or from a point, POV is moving toward or away from that point.
                //TODO if all objects moved in same direction but varying magnitudes, POV has moved sideways...further objects move less

                //calculate the motion vector for all associated objects
                List <Segment> motions = new List <Segment>();
                foreach (Thing t in motionParent.Children)
                {
                    if (t.Label.StartsWith("Moved")) //ignore appeared/disappeared
                    {
                        var       values = uks.GetValues(t);
                        PointPlus p      = new PointPlus(0, (float)0);
                        if (values.ContainsKey("CtrX++"))
                        {
                            p.X = values["CtrX++"];
                        }
                        if (values.ContainsKey("CtrY++"))
                        {
                            p.Y = values["CtrY++"];
                        }
                        Segment s = new Segment();
                        s.P1   = p; //This is a relative motion value
                        values = uks.GetValues(t.Children[0]);
                        p      = new PointPlus(0, (float)0);
                        if (values.ContainsKey("CtrX+"))
                        {
                            p.X = values["CtrX+"];
                        }
                        if (values.ContainsKey("CtrY+"))
                        {
                            p.Y = values["CtrY+"];
                        }
                        s.P2 = p; //This is an absolute position
                        motions.Add(s);
                    }
                }

                if (motions.Count > 1)
                {
                    //do most move the same?  ANGULAR POV MOTION
                    //TODO: use clustering to get most likely motions
                    PointPlus pMotion = new PointPlus(motions[0].P1);

                    int count = 0;
                    foreach (Segment s in motions)
                    {
                        if (s.P1.Near(pMotion, .1f))
                        {
                            count++;
                        }
                    }
                    if (count > motions.Count - 2) //only two objects can be exceptions
                    {
                        for (int i = 0; i < motions.Count; i++)
                        {
                            if (motions[i].P1.Near(pMotion, .1f))
                            {
                                motions.RemoveAt(i);
                                Thing t = motionParent.Children[i];
                                uks.DeleteAllChilden(t);
                                uks.DeleteThing(t);
                                i--;
                            }
                            else
                            {
                                //an object has its own motion too...subtract off the POV motion
                                Thing t = motionParent.Children[i];
                                float x = uks.GetValue(t, "CtrX+");
                                float y = uks.GetValue(t, "CtrY+");
                                x -= motions[i].P1.X;
                                y -= motions[i].P1.Y;
                                uks.SetValue(t, x, "CtrX", 3);
                                uks.SetValue(t, y, "CtrY", 3);
                            }
                        }
                        Thing POVMotion = uks.AddThing("POVMotion*", "Motion");
                        uks.SetValue(POVMotion, pMotion.X, "CtrX", 3);
                        uks.SetValue(POVMotion, pMotion.Y, "CtrY", 3);
                    }
                    else
                    { //this is not a rotation...is it a motion toward/away?
                      //TODO there are no exceptions allowed
                        foreach (var m in motions)
                        {
                            m.P1 += m.P2;
                        }
                        List <PointPlus> intersections = new List <PointPlus>();
                        for (int i = 0; i < motions.Count; i++)
                        {
                            for (int j = i + 1; j < motions.Count; j++)
                            {
                                Utils.FindIntersection(motions[i].P1, motions[i].P2, motions[j].P1, motions[j].P2, out Point intersection);
                                intersections.Add(intersection);
                            }
                        }

                        //testing clustering...
                        //TODO try all this with points of interest rather than centers
                        double[][] rawData = new double[intersections.Count][];
                        for (int i = 0; i < intersections.Count; i++)
                        {
                            rawData[i] = new double[2] {
                                intersections[i].X, intersections[i].Y
                            }
                        }
                        ;
                        int[] clusters = KMeansClustering.Cluster(rawData, 2);
                        //now ask if there is a single cluster with most of the data

                        PointPlus aveIntersection = new PointPlus();
                        for (int i = 0; i < intersections.Count; i++)
                        {
                            aveIntersection.X += intersections[i].X;
                            aveIntersection.Y += intersections[i].Y;
                        }
                        aveIntersection.X /= intersections.Count;
                        aveIntersection.Y /= intersections.Count;
                        float dist = 0;
                        float dir  = 0;
                        for (int i = 0; i < intersections.Count; i++)
                        {
                            dist += (intersections[i] - aveIntersection).R;
                            //moving toward or away?
                            dir += (motions[i].P1 - intersections[i]).R - (motions[i].P2 - intersections[i]).R;
                        }
                        dist /= intersections.Count;
                        dir  /= intersections.Count;
                        if (dist < 10) // ???
                        {
                            uks.DeleteAllChilden(motionParent);
                            Thing POVMotion = uks.AddThing("POVMotion*", "Motion");
                            uks.SetValue(POVMotion, aveIntersection.X, "CtrX", 3);
                            uks.SetValue(POVMotion, aveIntersection.Y, "CtrY", 3);
                            uks.SetValue(POVMotion, dir, "CtrZ", 3);
                        }
                    }
                }
            }

            //transfer currently visible objects to previously visible
            Debug.Assert(movedThings.Count == movedThingsNew.Count);
            for (int i = 0; i < movedThings.Count; i++)
            {
                uks.SetValue(movedThings[i], uks.GetValue(movedThingsNew[i], "CtrX+"), "CtrX", 0);
                uks.SetValue(movedThings[i], uks.GetValue(movedThingsNew[i], "CtrY+"), "CtrY", 0);
                uks.SetValue(movedThings[i], uks.GetValue(movedThingsNew[i], "Siz+"), "Siz", 0);
                uks.SetValue(movedThings[i], uks.GetValue(movedThingsNew[i], "Ang+"), "Ang", 0);
            }

            foreach (var t in newThings)
            {
                t.AddParent(mentalModel); //TODO, this may leave multiple things in the mental model with the same label
            }

            //This hack puts predictable labels on things in the mental model so we can select them more easily in the description
            //Area0-n from top->bottom, left->right
            List <sortable> vals = new List <sortable>();

            foreach (Thing storedArea in mentalModel.Children)
            {
                var values = uks.GetValues(storedArea);
                vals.Add(new sortable {
                    t = storedArea, x = values["CtrX+"], y = values["CtrY+"],
                });
            }
            vals = vals.OrderBy(w => w.y * 1000 + w.x).ToList();
            for (int i = 0; i < vals.Count; i++)
            {
                vals[i].t.Label = "Area" + i;
            }

            //for debugging:
            //if there is a new image, cancel the existing relationships
            ModuleImageFile mif = (ModuleImageFile)FindModule("ImageFile");

            if (mif == null)
            {
                return;
            }
            string curPath = mif.GetFilePath();

            if (curPath != prevPath)
            {
                foreach (Thing t in mentalModel.Children)
                {
                    var refs = t.GetRelationshipsByType(null, null);
                    foreach (Link ref1 in refs)
                    {
                        t.RemoveReference(ref1.T);
                    }
                }
                prevPath = curPath;
            }

            //if you want the dlg to update, use the following code whenever any parameter changes
            // UpdateDialog();
        }