示例#1
0
        Thing MatchAreaToStoredShapes(Thing t, out float score)
        {
            score = float.MaxValue;
            Thing bestMatch  = null;
            float bestScore  = float.MaxValue;
            Thing areaParent = uks.GetOrAddThing("Area", "Shape");

            if (areaParent == null)
            {
                return(null);
            }
            foreach (Thing t1 in areaParent.Children)
            {
                if (t1.Label.IndexOf("SavedShape") == 0)
                {
                    float matchScore = GetMatchScore(t1, t);
                    if (matchScore < bestScore)
                    {
                        bestScore = matchScore;
                        bestMatch = t1;
                    }
                }
            }
            score = bestScore;
            return(bestMatch);
        }
示例#2
0
        //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 wordParent        = uks.GetOrAddThing("Word", "Audible");
            Thing attn              = uks.GetOrAddThing("ATTN", "Thing");
            Thing attnVisualTarget  = attn.GetReferenceWithAncestor(mentalModel);
            Thing attnAudibleTarget = attn.GetReferenceWithAncestor(wordParent);

            AssociateWordsWithVisuals(attnAudibleTarget);

            //if you want the dlg to update, use the following code whenever any parameter changes
            if (dlg != null && !((ModuleAssociationDlg)dlg).busy)
            {
                UpdateDialog();
            }
        }
示例#3
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]);
                    }
                }
            }
        }
        private void AddAtttention(Thing t)
        {
            Thing attn   = uks.GetOrAddThing("ATTN", "Thing");
            Thing parent = t.Parents[t.Parents.Count - 1];

            attn.RemoveReferencesWithAncestor(uks.Labeled("Visual"));
            attn.AddReference(t);
            currentAttention = t;
            UpdateDialog();
        }
示例#5
0
        //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 knownObjectParent      = uks.GetOrAddThing("KnownObject", "Visual");
            Thing currentlyVisibleParent = uks.GetOrAddThing("CurrentlyVisible", "Visual");

            //List<Thing> visibleKnownThings = new List<Thing>();
            foreach (Thing area in currentlyVisibleParent.Children)
            {
                Thing knownObject1 = null;
                foreach (Thing knownObject in knownObjectParent.Children)
                {
                    Thing knownObjectShape = knownObject.HasReferenceWithParent(uks.Labeled("Area"));
                    Thing areaShape        = area.HasReferenceWithParent(uks.Labeled("Area"));
                    Thing knownObjectColor = knownObject.HasReferenceWithParent(uks.Labeled("Color"));
                    Thing areaColor        = area.HasReferenceWithParent(uks.Labeled("Color"));
                    //if critical properties match, object is already known
                    if (knownObjectShape == areaShape && knownObjectColor == areaColor)
                    {
                        knownObject1 = knownObject;
                        break;
                    }
                }

                if (knownObject1 == null)
                {
                    //The object is unknown, add it to known objects for future reference
                    knownObject1 = area.Clone();
                    knownObject1.AddParent(knownObjectParent);
                    knownObject1.Label = "KnownShape*";
                }
                //visibleKnownThings.Add(knownObject1);
                uks.DeleteAllChilden(area);
                area.AddChild(knownObject1);
                //knownObject1.Label = area.Label;
            }

            //if you want the dlg to update, use the following code whenever any parameter changes
            // UpdateDialog();
        }
        //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();
        }
        //fill this method in with code which will execute
        //once for each cycle of the engine
        public override void Fire()
        {
            bool visualTargetChanged = false;

            Init();  //be sure to leave this here

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

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

            DeleteUnusedRelationships();

            Thing attn        = uks.GetOrAddThing("ATTN", "Thing");
            Thing mentalModel = uks.GetOrAddThing("MentalModel", "Visual");

            if (attn.References.Count == 0)
            {
                return;
            }


            Thing newVisualTarget = attn.GetReferenceWithAncestor(mentalModel);

            if (newVisualTarget != attnVisualTarget)
            {
                visualTargetChanged = true;
            }
            if (visualTargetChanged)
            {
                prevAttnTarget   = attnVisualTarget;
                attnVisualTarget = newVisualTarget;
            }

            if (prevAttnTarget != null && attnVisualTarget != null)
            {
                if (visualTargetChanged && mentalModel.Children.Count > 1)
                {
                    //add all the relationships to the uks
                    AddRelationshipsToUKS(prevAttnTarget, attnVisualTarget);
                }
            }

            UpdateDialog();
            return;
        }
        private void AddRelationshipsToUKS(Thing t1, Thing t2)
        {
            if (t1 == null || t2 == null)
            {
                return;
            }
            //DeletePreviousRelationships(t1, t2);
            var vals1 = uks.GetValues(t1);
            var vals2 = uks.GetValues(t2);

            foreach (var pair1 in vals1)
            {
                //if (!pair1.Key.Contains("Siz")) continue;
                var val2 = vals2[pair1.Key];
                //hue is special because it is an angle which wraps around so < & > are not really defined
                if (pair1.Key == "Hue+")
                {
                    Angle diff = (pair1.Value - val2) * 2 * Math.PI;
                    diff = (diff.ToDegrees() + 180) % 360 - 180;
                    diff = Angle.FromDegrees(diff);
                    if (Math.Abs(diff) < Angle.FromDegrees(10))
                    {
                        t1.AddRelationship(t2, uks.GetOrAddThing("=" + pair1.Key, "Relationship"));
                    }
                    else
                    {
                        t1.AddRelationship(t1, uks.GetOrAddThing("!" + pair1.Key, "Relationship"));
                    }
                }
                else if (pair1.Key.EndsWith("+"))
                {
                    //value comparison
                    if (Math.Abs(pair1.Value - val2) == 0) //TODO make this tolerance a parameter
                    {
                        t1.AddRelationship(t2, uks.GetOrAddThing("=" + pair1.Key, "Relationship"));
                    }
                    else if (pair1.Value > val2)
                    {
                        t1.AddRelationship(t2, uks.GetOrAddThing("<" + pair1.Key, "Relationship"));
                    }
                    else
                    {
                        t1.AddRelationship(t2, uks.GetOrAddThing(">" + pair1.Key, "Relationship"));
                    }
                }
                else
                {
                    //equality comparison
                    if (pair1.Value == val2)
                    {
                        t1.AddRelationship(t2, uks.GetOrAddThing("=" + pair1.Key.Replace("Saved", ""), "Relationship"));
                    }
                    else
                    {
                        t1.AddRelationship(t2, uks.GetOrAddThing("!" + pair1.Key.Replace("Saved", ""), "Relationship"));
                    }
                }
            }
        }
示例#9
0
        private void AssociateWordsWithVisuals(Thing attnAudibleTarget)
        {
            if (attnAudibleTarget != null)
            {
                //IList<Thing> recentlyFiredWords = uks.Labeled("Word").DescendentsWhichFired;
                List <Thing> recentlyFiredWords = new List <Thing>();
                recentlyFiredWords.Add(attnAudibleTarget);
                IList <Thing> recentlyFiredRelationships = uks.Labeled("Relationship").DescendentsWhichFired;
                IList <Thing> recentlyFiredVisuals       = uks.Labeled("Visual").DescendentsWhichFired;


                //set the hits
                foreach (Thing word in recentlyFiredWords)
                {
                    foreach (Thing relationshipType in recentlyFiredRelationships)
                    {
                        word.AdjustReference(relationshipType);
                    }
                    foreach (Thing visual in recentlyFiredVisuals)
                    {
                        if (!visual.HasAncestor(uks.GetOrAddThing("MentalModel", "Visual")))
                        {
                            word.AdjustReference(visual);
                        }
                    }
                }

                //set the misses for relationships
                foreach (Thing relationshipType in recentlyFiredRelationships)
                {
                    foreach (Link l in relationshipType.ReferencedBy)
                    {
                        Thing word = l.T;
                        if (word.HasAncestor(uks.Labeled("Word")))
                        {
                            if (!recentlyFiredWords.Contains(word))
                            {
                                word.AdjustReference(relationshipType, -1);
                            }
                        }
                    }
                }

                //set the misses for properties
                foreach (Thing visual in recentlyFiredVisuals)
                {
                    foreach (Link l in visual.ReferencedBy)
                    {
                        Thing word = l.T;
                        if (word.HasAncestor(uks.Labeled("Word")))
                        {
                            if (!recentlyFiredWords.Contains(word))
                            {
                                word.AdjustReference(visual, -1);
                            }
                        }
                    }
                }
            }
        }
示例#10
0
        //fill this method in with code which will execute once
        //when the module is added, when "initialize" is selected from the context menu,
        //or when the engine restart button is pressed
        public override void Initialize()
        {
            ModuleView naSource = theNeuronArray.FindModuleByLabel("UKS");

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

            uks.GetOrAddThing("Area", "Shape");
        }
        private void InnerMonologue()
        {
            Thing attn    = uks.GetOrAddThing("ATTN", "Thing");
            Thing curAttn = attn.GetReferenceWithAncestor(uks.Labeled("Visual"));

            if (prevAttn == curAttn)
            {
                return;
            }
            if (curAttn == null)
            {
                return;
            }
            string newDescriptionString = "";

            ModuleView na = theNeuronArray.FindModuleByLabel("Association");

            if (na == null)
            {
                return;
            }
            ModuleAssociation ma = (ModuleAssociation)na.TheModule;

            foreach (Link l in curAttn.References)
            {
                Thing word = ma.GetBestAssociation(l.T);
                if (word != null)
                {
                    newDescriptionString += word.Label + " ";
                }
            }
            newDescriptionString += "\r";

            if (prevAttn != null)
            {
                var relationShips = prevAttn.GetRelationshipsByTarget(curAttn);
                foreach (Thing relationshipType in relationShips)
                {
                    Thing word = ma.GetBestAssociation(relationshipType);
                    if (word != null)
                    {
                        newDescriptionString += word.Label + " ";
                    }
                }
            }

            if (newDescriptionString != "" && newDescriptionString != descriptionString)
            {
                descriptionString = newDescriptionString;
            }
            prevAttn = curAttn;
        }
示例#12
0
        //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
            //return;

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

            if (naSource == null)
            {
                return;
            }
            uks = (ModuleUKS)naSource.TheModule;
            Thing x = uks.Labeled("CurrentlyVisible");
            Thing currentlyVisibleParent = uks.GetOrAddThing("CurrentlyVisible", "Visual");

            foreach (Thing t in currentlyVisibleParent.Children)
            {
                Thing tempShape = CreateTempShapeFromArea(t);
                if (tempShape == null)
                {
                    continue;
                }
                Thing bestMatch = MatchAreaToStoredShapes(tempShape, out float score);
                if (bestMatch != null && score < 0.5)
                {
                    t.AddReference(bestMatch);
                    DeleteTempShape(tempShape);
                }
                else
                {
                    AddShapeFromArea(tempShape);
                    tempShape.Label = "SavedShape'*";
                    t.AddReference(tempShape);
                }
            }


            //if you want the dlg to update, use the following code whenever any parameter changes
            // UpdateDialog();
        }
示例#13
0
        public override bool Draw(bool checkDrawTimer)
        {
            if (busy)
            {
                return(false);
            }
            //the datagridview is so slow, always wait for the timer
            if (!base.Draw(checkDrawTimer))
            {
                return(false);
            }

            if (mouseInWindow)
            {
                return(true);
            }

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

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

            Thing mentalModel = uks.GetOrAddThing("MentalModel", "Visual");

            if (mentalModel == null || mentalModel.Children.Count == 0)
            {
                return(false);
            }

            Thing attn = uks.Labeled("ATTN");

            if (attn == null || attn.References.Count == 0)
            {
                return(false);
            }

            busy = true;
            Thing attnTarget = attn.GetReferenceWithAncestor(uks.Labeled("Visual"));


            DataTable dt = new DataTable();

            dt.Columns.Add("*", typeof(string));

            IList <Thing> words = uks.Labeled("Word").Children;

            foreach (Thing child in words)
            {
                dt.Columns.Add(child.Label, typeof(string));
            }

            List <Thing> properties = uks.Labeled("Color").Children.ToList();

            properties.AddRange(uks.Labeled("Area").Children.ToList());
            //properties = properties.OrderBy(x => x.Label).ToList();
            IList <Thing> relationships = uks.Labeled("Relationship").Children;

            //relationships = relationships.OrderBy(x => x.Label.Substring(1)).ToList();


            //collect all the values in a single spot
            float[,] values = ((ModuleAssociation)base.ParentModule).GetAssociations();


            int row = 0;

            foreach (Thing property in properties)
            {
                DataRow dr = dt.NewRow();
                dr[0] = property.Label;
                List <Link> refs = property.GetReferencedByWithAncestor(uks.Labeled("Word"));
                for (int i = 0; i < words.Count; i++)
                {
                    Link l = words[i].HasReference(property);
                    if (l != null)
                    {
                        if (cbRawValues.IsChecked == true)
                        {
                            dr[i + 1] = l.hits + "/" + l.misses;
                        }
                        else
                        {
                            dr[i + 1] = l.Value1.ToString("f2");
                        }
                    }
                }
                dt.Rows.Add(dr);
                row++;
            }

            foreach (Thing relationship in relationships)
            {
                DataRow dr = dt.NewRow();
                dr[0] = relationship.Label;
                List <Link> refs = relationship.GetReferencedByWithAncestor(uks.Labeled("Word"));
                for (int i = 0; i < words.Count; i++)
                {
                    Link l = words[i].HasReference(relationship);
                    if (l != null)
                    {
                        if (cbRawValues.IsChecked == true)
                        {
                            dr[i + 1] = l.hits + "/" + l.misses;
                        }
                        else
                        {
                            dr[i + 1] = l.Value1.ToString("f2");
                        }
                    }
                }
                dt.Rows.Add(dr);
                row++;
            }


            theGrid.ItemsSource   = dt.DefaultView;
            theGrid.SelectionUnit = DataGridSelectionUnit.Cell;

            float[] maxInRow = new float[values.GetLength(0)];
            float[] maxInCol = new float[values.GetLength(1)];
            for (int i = 0; i < values.GetLength(0); i++)
            {
                for (int j = 0; j < values.GetLength(1); j++)
                {
                    if (values[i, j] > maxInRow[i])
                    {
                        maxInRow[i] = values[i, j];
                    }
                }
            }
            for (int j = 0; j < values.GetLength(1); j++)
            {
                for (int i = 0; i < values.GetLength(0); i++)
                {
                    if (values[i, j] > maxInCol[j])
                    {
                        maxInCol[j] = values[i, j];
                    }
                }
            }

            //set the background colors of the significant elements
            for (int j = 0; j < values.GetLength(1); j++)
            {
                for (int i = 0; i < values.GetLength(0); i++)
                {
                    if (values[i, j] == maxInRow[i] && values[i, j] == maxInCol[j])
                    {
                        SetCellBackground(i, j + 1, Colors.LightGreen);
                    }
                    else if (values[i, j] == maxInRow[i])
                    {
                        SetCellBackground(i, j + 1, Colors.LightGoldenrodYellow);
                    }
                    else if (values[i, j] == maxInCol[j])
                    {
                        SetCellBackground(i, j + 1, Colors.Yellow);
                    }
                    else
                    {
                        SetCellBackground(i, j + 1, Colors.White);
                    }
                }
            }

            theGrid.FrozenColumnCount = 1;
            busy = false;
            return(true);
        }
示例#14
0
        //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");

            if (mentalModel.Children.Count == 0)
            {
                return;
            }


            if (autoAttention > 0)
            {
                autoAttention--;
                return;
            }
            if (autoAttention < 0)
            {
                return;
            }

            //if an object moved, it gets attention
            Thing currentMotionParent = uks.GetOrAddThing("Motion", "Visual");
            Thing newAttention        = null;

            foreach (Thing t in currentMotionParent.Children)
            {
                if (t.Label.StartsWith("Moved"))
                {
                    newAttention = t.Children[0];
                    break;
                }
            }


            if (newAttention != null)
            {
                currentAttention = newAttention;
            }
            else
            {
                currentAttention = mentalModel.Children[rand.Next(mentalModel.Children.Count)];
                currentAttention.useCount++;
            }

            AddAtttention(currentAttention);

            foreach (Link l in currentAttention.References)
            {
                if (l is Relationship r)
                {
                }
                // r.relationshipType.SetFired();
                else
                {
                    l.T.SetFired();
                }
            }
        }
        //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;

            ModuleView attnSource = theNeuronArray.FindModuleByLabel("Attention");

            if (attnSource == null)
            {
                return;
            }
            ModuleAttention m = (ModuleAttention)attnSource.TheModule;


            Thing mentalModelParent = uks.GetOrAddThing("MentalModel", "Visual");
            Thing wordParent        = uks.GetOrAddThing("Word", "Audible");
            Thing attn = uks.GetOrAddThing("ATTN", "Thing");

            if (words.Count > 0)
            {
                if (currentWord != "")
                {
                    attn.RemoveReferencesWithAncestor(wordParent);
                }
                currentWord = words[0];
                //is this a reference to a visible object? does it contain a digit?
                if (words[0].IndexOfAny(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }) != -1)
                {
                    Thing t = uks.Labeled(words[0], mentalModelParent.Children);
                    if (t != null)
                    {
                        if (naSource != null)
                        {
                            m.SetAttention(t, -1);
                        }
                    }
                }
                else
                {
                    //process a single word & add it to the current phrase
                    currentWord = char.ToUpper(currentWord[0]) + currentWord.Substring(1);
                    Thing theWord = uks.GetOrAddThing("w" + currentWord, wordParent);
                    attn.AddReference(theWord);
                }
                //delete the word from the top of the list
                words.RemoveAt(0);
            }
            else
            {
                if (attn.HasReferenceWithParent(wordParent) != null)
                {
                    attn.RemoveReferencesWithAncestor(wordParent);
                    m.SetAttention(null, 0);
                }
            }



            InnerMonologue();

            //if you want the dlg to update, use the following code whenever any parameter changes
            UpdateDialog();
        }
        public override bool Draw(bool checkDrawTimer)
        {
            if (!base.Draw(checkDrawTimer))
            {
                return(false);
            }
            //this has a timer so that no matter how often you might call draw, the dialog
            //only updates 10x per second

            ModuleAttention parent = (ModuleAttention)base.ParentModule;

            theCanvas.Children.Clear();
            Point windowSize = new Point(theCanvas.ActualWidth, theCanvas.ActualHeight);

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

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

            Thing mentalModel = uks.GetOrAddThing("MentalModel", "Visual");

            if (mentalModel == null || mentalModel.Children.Count == 0)
            {
                return(false);
            }

            Thing attn = uks.Labeled("ATTN");

            if (attn == null || attn.References.Count == 0)
            {
                return(false);
            }

            Thing    attnTarget = attn.GetReferenceWithAncestor(uks.Labeled("Visual"));
            var      values     = uks.GetValues(attnTarget);
            HSLColor c1         = new HSLColor(values["Hue+"], values["Sat+"], values["Lum+"]);
            Color    fillColor  = c1.ToColor();

            try
            {
                double largest = 0;
                foreach (Thing area in mentalModel.Children)
                {
                    var       areaValues  = uks.GetValues(area);
                    Thing     theShape    = area.Children[0];
                    var       shapeValues = uks.GetValues(theShape);
                    PointPlus pOffset     = new PointPlus(areaValues["CtrX+"] - shapeValues["CtrX+"], areaValues["CtrY+"] - shapeValues["CtrY+"]);
                    foreach (Thing corner in theShape.Children)
                    {
                        Point p = (Point)corner.Children[0].V;
                        p       = p + pOffset;
                        largest = Math.Max(largest, p.X);
                        largest = Math.Max(largest, p.Y);
                    }
                }

                largest += 10; //a little margin

                float scale = (float)Math.Min(windowSize.X, windowSize.Y) / (float)largest;
                if (scale == 0)
                {
                    return(false);
                }

                theCanvas.Children.Clear();
                foreach (Thing area in mentalModel.Children)
                {
                    PointCollection pts         = new PointCollection();
                    var             areaValues  = uks.GetValues(area);
                    Thing           theShape    = area.Children[0];
                    var             shapeValues = uks.GetValues(theShape);

                    //These corrections are needed because known objects are stored at the location and size when they were first seen
                    //now the viewed object will have a different size and location
                    PointPlus pAreaCtr   = new PointPlus(areaValues["CtrX+"], areaValues["CtrY+"]);
                    PointPlus pShapeCtr  = new PointPlus(shapeValues["CtrX+"], shapeValues["CtrY+"]);
                    float     areaSize   = areaValues["Siz+"];
                    float     shapeSize  = shapeValues["Siz+"];
                    Angle     areaAngle  = areaValues["Ang+"];
                    Angle     shapeAngle = shapeValues["Ang+"];
                    Angle     rotation   = areaAngle - shapeAngle;

                    foreach (Thing corner in theShape.Children)
                    {
                        PointPlus p = new PointPlus((Point)corner.Children[0].V);
                        p        = p - pShapeCtr;
                        p.Theta += rotation;
                        float ratio = areaSize / shapeSize;
                        p.X *= ratio;
                        p.Y *= ratio;
                        p    = p + pAreaCtr;

                        p.X *= scale;
                        p.Y *= scale;
                        pts.Add(p);
                    }
                    Polygon poly = new Polygon {
                        Points = pts, Stroke = new SolidColorBrush(Colors.AliceBlue)
                    };
                    poly.ToolTip = area.Label;
                    poly.Fill    = this.Background;
                    if (attnTarget == area)
                    {
                        poly.Fill         = new SolidColorBrush(fillColor);
                        poly.Stroke       = new SolidColorBrush(fillColor);
                        poly.Fill.Opacity = 1;
                    }
                    poly.MouseDown += Poly_MouseDown;
                    poly.SetValue(AttentionObjectProperty, area);
                    theCanvas.Children.Add(poly);
                }
            }
#pragma warning disable 168
            catch (Exception e) //sometimes useful for debugging
#pragma warning restore 168
            { }
            return(true);
        }
        //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();
        }