示例#1
0
        public static Diff DiffWithHash(IEnumerable <object> pastObjects, IEnumerable <object> currentObjects, DiffingConfig diffConfig = null, bool useExistingHash = false)
        {
            BH.Engine.Reflection.Compute.RecordNote("This diffing method cannot track modified objects between different revisions." +
                                                    "\nIt will simply return the objects that appear exclusively in the past set, in the following set, and in both." +
                                                    $"\nConsider using '{nameof(DiffWithCustomId)}', '{nameof(DiffWithFragmentId)}' or '{nameof(DiffRevisions)}' if this feature is needed.");

            // Set configurations if diffConfig is null. Clone it for immutability in the UI.
            DiffingConfig dc = diffConfig == null ? new DiffingConfig() : (DiffingConfig)diffConfig.DeepClone();

            // Clone objects for immutability in the UI.
            List <object> pastObjects_cloned    = BH.Engine.Base.Query.DeepClone(pastObjects).ToList();
            List <object> currentObjects_cloned = BH.Engine.Base.Query.DeepClone(currentObjects).ToList();

            if (!useExistingHash)
            {
                // Clean any existing hash fragment. This ensures the hash will be re-computed using the provided DiffingConfig.
                pastObjects_cloned.OfType <IBHoMObject>().ToList().ForEach(o => o.Fragments.Remove(typeof(HashFragment)));
                currentObjects_cloned.OfType <IBHoMObject>().ToList().ForEach(o => o.Fragments.Remove(typeof(HashFragment)));
            }

            // Compute the "Diffing" by means of a VennDiagram.
            // Hashes are computed in the DiffingHashComparer, once per each object (the hash is stored in a hashFragment).
            VennDiagram <object> vd = Engine.Data.Create.VennDiagram(pastObjects_cloned, currentObjects_cloned, new HashComparer <object>(dc.ComparisonConfig, true));

            return(new Diff(vd.OnlySet2, vd.OnlySet1, null, dc, null, vd.Intersection));
        }
示例#2
0
文件: Delta.cs 项目: BHoM/BHoM_Engine
        public static Delta Delta(List <IBHoMObject> objects, object streamId, string revisionName = null,
                                  string comment = null, DiffingConfig diffingConfig = null)
        {
            Revision revision = Create.Revision(objects, streamId, revisionName, comment, diffingConfig);

            return(Delta(revision, diffingConfig, comment));
        }
示例#3
0
        public static Diff DiffWithFragmentId(IEnumerable <IBHoMObject> pastObjects, IEnumerable <IBHoMObject> currentObjects, Type fragmentType = null, string fragmentIdProperty = null, DiffingConfig diffConfig = null)
        {
            if (fragmentType == null || string.IsNullOrWhiteSpace(fragmentIdProperty))
            {
                fragmentType       = typeof(IPersistentAdapterId);
                fragmentIdProperty = nameof(IPersistentAdapterId.PersistentId);

                BH.Engine.Reflection.Compute.RecordNote($"No `{nameof(fragmentType)}` or `{nameof(fragmentIdProperty)}` specified." +
                                                        $"\nDefaulted to `{typeof(IPersistentAdapterId).FullName}.{nameof(IPersistentAdapterId.PersistentId)}`.");
            }

            // Set configurations if diffConfig is null. Clone it for immutability in the UI.
            DiffingConfig diffConfigCopy = diffConfig == null ? new DiffingConfig() : (DiffingConfig)diffConfig.DeepClone();

            if (string.IsNullOrWhiteSpace(fragmentIdProperty))
            {
                BH.Engine.Reflection.Compute.RecordError($"The DiffingConfig must specify a valid {nameof(fragmentIdProperty)}.");
                return(null);
            }

            // Clone for immutability
            List <IBHoMObject> currentObjs = currentObjects.ToList();
            List <IBHoMObject> pastObjs    = pastObjects.ToList();

            string customDataIdKey = fragmentType.Name + "_fragmentId";

            currentObjs.ForEach(o => o.CustomData[customDataIdKey] = o.GetIdFromFragment(fragmentType, fragmentIdProperty));
            pastObjs.ForEach(o => o.CustomData[customDataIdKey]    = o.GetIdFromFragment(fragmentType, fragmentIdProperty));

            return(DiffWithCustomId(pastObjs, currentObjs, customDataIdKey, diffConfigCopy));
        }
示例#4
0
文件: Delta.cs 项目: BHoM/BHoM_Engine
        public static Delta Delta(Revision revision, DiffingConfig diffingConfig = null, string comment = null)
        {
            if (revision == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot create a Delta from a null revision.");
                return(null);
            }

            Diff diff = Compute.DiffRevisions(null, revision, diffingConfig);

            return(new Delta(revision.StreamId, diff, revision.RevisionId, new Guid(), DateTime.UtcNow.Ticks, m_Author, comment));
        }
示例#5
0
        public static Diff DiffOneByOne(IEnumerable <object> pastObjects, IEnumerable <object> currentObjects, DiffingConfig diffConfig = null)
        {
            if (pastObjects.Count() != currentObjects.Count())
            {
                BH.Engine.Reflection.Compute.RecordWarning($"Input collections must be of the same length for '{nameof(DiffOneByOne)}' to work.");
                return(null);
            }

            BH.Engine.Reflection.Compute.RecordNote($"This diffing method is equivalent to calling '{nameof(Query.DifferentProperties)}' on the input lists. " +
                                                    $"\nThis will only identify 'modified' or 'unchanged' objects. For 'modified' objects, the property differences are also returned." +
                                                    $"\nIt will work correctly only if the objects in the lists are in the same order and at most they have been modified (i.e. no new object has been added, no object has been deleted).");

            // Set configurations if diffConfig is null. Clone it for immutability in the UI.
            DiffingConfig diffConfigCopy = diffConfig == null ? new DiffingConfig() : (DiffingConfig)diffConfig.DeepClone();

            diffConfigCopy.EnablePropertyDiffing = true; // must be forced on for this Diffing method to make sense.

            // Clone objects for immutability in the UI.
            List <object> pastObjects_cloned    = BH.Engine.Base.Query.DeepClone(pastObjects).ToList();
            List <object> currentObjects_cloned = BH.Engine.Base.Query.DeepClone(currentObjects).ToList();

            List <object> modifiedObjects  = new List <object>();
            List <object> unchangedObjects = new List <object>();

            bool anyChangeDetected = false;

            var allModifiedProps = new Dictionary <string, Dictionary <string, Tuple <object, object> > >();

            for (int i = 0; i < pastObjects_cloned.Count(); i++)
            {
                var modifiedProps = Query.DifferentProperties(currentObjects_cloned[i], pastObjects_cloned[i], diffConfigCopy);

                if (modifiedProps != null && modifiedProps.Any())
                {
                    modifiedObjects.Add(currentObjects_cloned[i]);
                    anyChangeDetected = true;
                }
                else if (diffConfig.IncludeUnchangedObjects)
                {
                    unchangedObjects.Add(currentObjects_cloned[i]);
                }

                allModifiedProps[$"Object #{i}"] = modifiedProps ?? new Dictionary <string, Tuple <object, object> >();
            }

            if (!anyChangeDetected)
            {
                allModifiedProps = null;
            }

            return(new Diff(new List <object>(), new List <object>(), modifiedObjects, diffConfigCopy, allModifiedProps, unchangedObjects));
        }
示例#6
0
        public static List <T> SetRevisionFragment <T>(this IEnumerable <T> objs, DiffingConfig diffingConfig = null) where T : IBHoMObject
        {
            // Clone the current objects to preserve immutability
            List <T> objs_cloned = new List <T>();

            // Set configurations if DiffingConfig is null
            diffingConfig = diffingConfig == null ? new DiffingConfig() : diffingConfig;

            // Calculate and set the object hashes
            foreach (var obj in objs)
            {
                objs_cloned.Add(SetRevisionFragment(obj, diffingConfig));
            }

            return(objs_cloned);
        }
示例#7
0
        public static T SetRevisionFragment <T>(this T obj, DiffingConfig diffingConfig = null) where T : IBHoMObject
        {
            // Clone the current object to preserve immutability
            T obj_cloned = BH.Engine.Base.Query.DeepClone(obj);

            // Set configurations if DiffingConfig is null
            diffingConfig = diffingConfig == null ? new DiffingConfig() : diffingConfig;

            // Calculate and set the object hashes
            string hash = obj_cloned.Hash(diffingConfig.ComparisonConfig);

            RevisionFragment existingFragm = obj_cloned.RevisionFragment();

            obj_cloned.Fragments.AddOrReplace(new RevisionFragment(hash, existingFragm?.Hash));

            return(obj_cloned);
        }
示例#8
0
文件: Delta.cs 项目: BHoM/BHoM_Engine
        public static Delta Delta(Revision pastRevision, Revision currentRevision, DiffingConfig diffingConfig = null, string comment = null)
        {
            if (pastRevision == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot create a Delta from a null past revision.");
                return(null);
            }

            if (currentRevision == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot create a Delta from a null current revision.");
                return(null);
            }

            Diff diff = Compute.DiffRevisions(pastRevision, currentRevision, diffingConfig);

            return(new Delta(pastRevision.StreamId, diff, pastRevision.RevisionId, currentRevision.RevisionId, DateTime.UtcNow.Ticks, m_Author, comment));
        }
示例#9
0
        public static bool HasMergeablePropertiesWith(Space element, Space other)
        {
            DiffingConfig config = new DiffingConfig()
            {
                ComparisonConfig = new ComparisonConfig()
                {
                    PropertyExceptions = new List <string>
                    {
                        "Location",
                        "Type",
                        "BHoM_Guid",
                        "CustomData",
                    },
                    NumericTolerance = BH.oM.Geometry.Tolerance.Distance,
                }
            };

            return(Diffing.Query.DifferentProperties(element, other, config) == null);
        }
示例#10
0
        public static bool HasMergeablePropertiesWith(Opening element, Opening other)
        {
            DiffingConfig config = new DiffingConfig()
            {
                ComparisonConfig = new ComparisonConfig()
                {
                    PropertyExceptions = new List <string>
                    {
                        "Edges",
                        "FrameFactorValue",
                        "InnerEdges",
                        "Type",
                        "BHoM_Guid",
                        "CustomData",
                    },
                    NumericTolerance = BH.oM.Geometry.Tolerance.Distance
                }
            };

            return(Diffing.Query.DifferentProperties(element, other, config) == null);
        }
示例#11
0
        public static bool HasMergeablePropertiesWith(Panel element, Panel other)
        {
            DiffingConfig config = new DiffingConfig()
            {
                ComparisonConfig = new ComparisonConfig()
                {
                    PropertyExceptions = new List <string>
                    {
                        "ExternalEdges",
                        "Openings",
                        "ConnectedSpaces",
                        "Type",
                        "BHoM_Guid",
                        "CustomData",
                    },
                    NumericTolerance = BH.oM.Geometry.Tolerance.Distance
                }
            };

            return(Diffing.Query.DifferentProperties(element, other, config) == null);
        }
示例#12
0
        // Computes the diffing for IEnumerable<object>.
        // For BHoMObjects, it assumes that they all have a HashFragment assigned (like when they have been passed through a Revision).
        // For non-BHoMObjects, it performs the VennDiagram comparision with a HashComparer.
        // Results for BHoMObjects and non are concatenated.
        private static Diff DiffRevisionObjects(IEnumerable <object> pastRevisionObjs, IEnumerable <object> followingRevisionObjs, DiffingConfig diffingConfig = null)
        {
            // Set configurations if DiffingConfig is null. Clone it for immutability in the UI.
            DiffingConfig diffConfigCopy = diffingConfig == null ? new DiffingConfig() : diffingConfig.DeepClone() as DiffingConfig;

            // Dispatch the objects in BHoMObjects and generic objects.
            IEnumerable <IBHoMObject> prevObjs_BHoM    = pastRevisionObjs.OfType <IBHoMObject>();
            IEnumerable <IBHoMObject> currObjs_BHoM    = followingRevisionObjs.OfType <IBHoMObject>();
            IEnumerable <object>      prevObjs_nonBHoM = pastRevisionObjs.Where(o => !(o is IBHoMObject));
            IEnumerable <object>      currObjs_nonBHoM = followingRevisionObjs.Where(o => !(o is IBHoMObject));

            // Compute the specific Diffing for the BHoMObjects.
            Diff diff = Compute.DiffRevisionObjects(prevObjs_BHoM, currObjs_BHoM, diffConfigCopy);

            // If all objects are BHoMObjects, we are done.
            if (pastRevisionObjs.Count() != 0 && pastRevisionObjs.Count() == prevObjs_BHoM.Count() && followingRevisionObjs.Count() == currObjs_BHoM.Count())
            {
                return(diff);
            }

            // Compute the generic Diffing for the other objects.
            // This is left to the VennDiagram with a HashComparer.
            VennDiagram <object> vd = Engine.Data.Create.VennDiagram(prevObjs_nonBHoM, currObjs_nonBHoM, new HashComparer <object>(diffingConfig.ComparisonConfig));

            // Concatenate the results of the two diffing operations.
            List <object> allPrevObjs      = new List <object>();
            List <object> allCurrObjs      = new List <object>();
            List <object> allUnchangedObjs = new List <object>();

            allCurrObjs.AddRange(diff.AddedObjects);
            allCurrObjs.AddRange(vd.OnlySet1);

            allPrevObjs.AddRange(diff.RemovedObjects);
            allPrevObjs.AddRange(vd.OnlySet2);

            // Create the final, actual diff.
            Diff finalDiff = new Diff(allCurrObjs, allPrevObjs, diff.ModifiedObjects, diffConfigCopy, diff.ModifiedPropsPerObject, diff.UnchangedObjects);

            return(finalDiff);
        }
示例#13
0
        // Computes the Diffing for BHoMObjects that all have a HashFragment assigned (like when they have been passed through a Revision).
        private static Diff DiffRevisionObjects(IEnumerable <IBHoMObject> pastObjects, IEnumerable <IBHoMObject> currentObjects, DiffingConfig diffingConfig = null)
        {
            // Set configurations if DiffingConfig is null. Clone it for immutability in the UI.
            DiffingConfig dc = diffingConfig == null ? new DiffingConfig() : diffingConfig.DeepClone() as DiffingConfig;

            // Take the Revision's objects
            List <IBHoMObject> currentObjs = currentObjects.ToList();
            List <IBHoMObject> readObjs    = pastObjects.ToList();

            // Make dictionary with object hashes to speed up the next lookups
            Dictionary <string, IBHoMObject> readObjs_dict = readObjs.ToDictionary(obj => obj.RevisionFragment().Hash, obj => obj);

            // Dispatch the objects: new, modified or old
            List <IBHoMObject> newObjs      = new List <IBHoMObject>();
            List <IBHoMObject> modifiedObjs = new List <IBHoMObject>();
            List <IBHoMObject> oldObjs      = new List <IBHoMObject>();
            List <IBHoMObject> unChanged    = new List <IBHoMObject>();

            var objModifiedProps = new Dictionary <string, Dictionary <string, Tuple <object, object> > >();

            foreach (IBHoMObject bhomObj in currentObjs)
            {
                RevisionFragment revisionFragm = bhomObj.RevisionFragment();

                if (revisionFragm?.PreviousHash == null)
                {
                    newObjs.Add(bhomObj); // It's a new object
                }

                else if (revisionFragm.PreviousHash == revisionFragm.Hash)
                {
                    // It's NOT been modified
                    if (dc.IncludeUnchangedObjects)
                    {
                        unChanged.Add(bhomObj);
                    }
                }

                else if (revisionFragm.PreviousHash != revisionFragm.Hash)
                {
                    modifiedObjs.Add(bhomObj); // It's been modified

                    if (dc.EnablePropertyDiffing)
                    {
                        // Determine changed properties
                        IBHoMObject oldBhomObj = null;
                        readObjs_dict.TryGetValue(revisionFragm.PreviousHash, out oldBhomObj);

                        if (oldBhomObj == null)
                        {
                            continue;
                        }

                        // To compute differentProps in a Revision-Diffing, make sure we remove the RevisionFragment. We don't want to consider that.
                        var differentProps = Query.DifferentProperties(bhomObj.RemoveFragment(typeof(RevisionFragment)), oldBhomObj.RemoveFragment(typeof(RevisionFragment)), dc);

                        if (differentProps != null)
                        {
                            objModifiedProps.Add(revisionFragm.Hash, differentProps);
                        }
                    }
                }
                else
                {
                    throw new Exception("Could not find hash information to perform Diffing on some objects.");
                }
            }

            // If no modified property was found, set the field to null (otherwise will get empty list)
            objModifiedProps = objModifiedProps.Count == 0 ? null : objModifiedProps;

            // All ReadObjs that cannot be found by hash in the previousHash of the CurrentObjs are toBeDeleted
            Dictionary <string, IBHoMObject> CurrentObjs_withPreviousHash_dict = currentObjs
                                                                                 .Where(obj => obj.RevisionFragment().PreviousHash != null)
                                                                                 .ToDictionary(obj => obj.RevisionFragment().PreviousHash, obj => obj);

            oldObjs = readObjs_dict.Keys.Except(CurrentObjs_withPreviousHash_dict.Keys)
                      .Where(k => readObjs_dict.ContainsKey(k)).Select(k => readObjs_dict[k]).ToList();

            return(new Diff(newObjs, oldObjs, modifiedObjs, diffingConfig, objModifiedProps, unChanged));
        }
示例#14
0
文件: Delta.cs 项目: BHoM/BHoM_Engine
 public static Delta Delta(Diff diff, object streamId, Guid revision_from, string comment = null, DiffingConfig diffingConfig = null)
 {
     return(new Delta(ProcessStreamId(streamId), diff, revision_from, new Guid(), DateTime.UtcNow.Ticks, m_Author, comment));
 }
示例#15
0
        public static Dictionary <string, Tuple <object, object> > DifferentProperties(this object obj1, object obj2, DiffingConfig diffingConfig = null)
        {
            // Set configurations if DiffingConfig is null. Clone it for immutability in the UI.
            DiffingConfig dc = diffingConfig == null ? new DiffingConfig() : diffingConfig.DeepClone() as DiffingConfig;

            object obj1Copy = obj1.DeepClone();
            object obj2Copy = obj2.DeepClone();

            var dict = new Dictionary <string, Tuple <object, object> >();

            CompareLogic comparer = new CompareLogic();

            // General configurations.
            comparer.Config.MaxDifferences  = dc.MaxPropertyDifferences;
            comparer.Config.DoublePrecision = dc.ComparisonConfig.NumericTolerance;

            // Set the properties to be ignored.
            if (!dc.ComparisonConfig.PropertyExceptions?.Contains("BHoM_Guid") ?? true)
            {
                dc.ComparisonConfig.PropertyExceptions.Add("BHoM_Guid");
            }
            // the above should be replaced by BH.Engine.Reflection.Compute.RecordWarning($"`BHoM_Guid` should generally be ignored when computing the diffing. Consider adding it to the {nameof(DiffingConfig.PropertiesToIgnore)}.");
            // when the bug in the auto Create() method ("auto-property initialisers for ByRef values like lists do not populate default values") is resolved.

            comparer.Config.MembersToIgnore = dc.ComparisonConfig.PropertyExceptions;

            // Removes the CustomData to be ignored.
            var bhomobj1 = (obj1Copy as IBHoMObject);
            var bhomobj2 = (obj2Copy as IBHoMObject);

            if (bhomobj1 != null)
            {
                dc.ComparisonConfig.CustomdataKeysExceptions.ForEach(k => bhomobj1.CustomData.Remove(k));
                obj1Copy = bhomobj1;
            }

            if (bhomobj2 != null)
            {
                dc.ComparisonConfig.CustomdataKeysExceptions.ForEach(k => bhomobj2.CustomData.Remove(k));
                obj2Copy = bhomobj2;
            }

            // Never include the changes in HashFragment.
            comparer.Config.TypesToIgnore.Add(typeof(HashFragment));
            comparer.Config.TypesToIgnore.Add(typeof(RevisionFragment));

            // Perform the comparison.
            ComparisonResult result = comparer.Compare(obj1Copy, obj2Copy);

            // Parse and store the differnces as appropriate.
            foreach (var difference in result.Differences)
            {
                string propertyName = difference.PropertyName;

                //workaround for Revit's parameters in Fragments
                if (propertyName.Contains("Fragments") && propertyName.Contains("Parameter") && propertyName.Contains("Value"))
                {
                    propertyName = BH.Engine.Reflection.Query.PropertyValue(difference.ParentObject2, "Name").ToString();
                }

                if (propertyName.Contains("CustomData") && propertyName.Contains("Value"))
                {
                    var splittedName = difference.PropertyName.Split('.');

                    int idx = 0;
                    Int32.TryParse(string.Join(null, System.Text.RegularExpressions.Regex.Split(splittedName.ElementAtOrDefault(1), "[^\\d]")), out idx);

                    string keyName = (obj2Copy as IBHoMObject)?.CustomData.ElementAtOrDefault(idx - 1).Key; // this seems buggy ATM.

                    propertyName = splittedName.FirstOrDefault() + $"['{keyName}']." + splittedName.Last();
                }

                if (dc.ComparisonConfig.PropertyExceptions.Any() && !dc.ComparisonConfig.PropertyExceptions.Contains(difference.PropertyName))
                {
                    dict[propertyName] = new Tuple <object, object>(difference.Object1, difference.Object2);
                }
            }

            if (dict.Count == 0)
            {
                return(null);
            }

            return(dict); // this Dictionary may be exploded in the UI by using the method "ListDifferentProperties".
        }
示例#16
0
        public static Diff DiffWithCustomId(IEnumerable <IBHoMObject> pastObjects, IEnumerable <IBHoMObject> currentObjects, string customdataIdKey, DiffingConfig diffConfig = null)
        {
            // Set configurations if diffConfig is null. Clone it for immutability in the UI.
            DiffingConfig diffConfigCopy = diffConfig == null ? new DiffingConfig() : (DiffingConfig)diffConfig.DeepClone();

            HashSet <string> currentObjectsIds = new HashSet <string>();
            HashSet <string> pastObjectsIds    = new HashSet <string>();

            // Verifies inputs and populates the id lists.
            ProcessObjectsForDiffing(pastObjects, currentObjects, customdataIdKey, out currentObjectsIds, out pastObjectsIds);

            // Actual diffing
            // Clone for immutability in the UI
            List <IBHoMObject> currentObjs = currentObjects.ToList();
            List <IBHoMObject> pastObjs    = pastObjects.ToList();

            // Make dictionary with object ids to speed up the next lookups
            Dictionary <string, IBHoMObject> currObjs_dict = currentObjectsIds.Zip(currentObjs, (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v);
            Dictionary <string, IBHoMObject> pastObjs_dict = pastObjectsIds.Zip(pastObjs, (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v);

            // Dispatch the objects: new, modified or deleted
            List <IBHoMObject> newObjs      = new List <IBHoMObject>();
            List <IBHoMObject> modifiedObjs = new List <IBHoMObject>();
            List <IBHoMObject> deletedObjs  = new List <IBHoMObject>();
            List <IBHoMObject> unChanged    = new List <IBHoMObject>();

            var objModifiedProps = new Dictionary <string, Dictionary <string, Tuple <object, object> > >();

            foreach (var kv_curr in currObjs_dict)
            {
                IBHoMObject currentObj   = kv_curr.Value;
                string      currentObjID = kv_curr.Key;

                // Try to find an object between the pastObjs that has the same ID of the current one.
                IBHoMObject correspondingObj = null;
                pastObjs_dict.TryGetValue(kv_curr.Key, out correspondingObj);

                // If none is found, the current object is new.
                if (correspondingObj == null)
                {
                    newObjs.Add(kv_curr.Value);
                    continue;
                }

                // Otherwise, the current object existed in the past set.

                if (diffConfig.EnablePropertyDiffing)
                {
                    // Determine changed properties
                    var differentProps = Query.DifferentProperties(currentObj, correspondingObj, diffConfigCopy);

                    if (differentProps != null && differentProps.Count > 0)
                    {
                        // It's been modified
                        modifiedObjs.Add(currentObj);
                        objModifiedProps.Add(currentObjID, differentProps);
                    }
                    else
                    {
                        // It's NOT been modified
                        if (diffConfigCopy.IncludeUnchangedObjects)
                        {
                            unChanged.Add(currentObj);
                        }
                    }
                }
            }

            // If no modified property was found, set the field to null (otherwise will get empty list)
            objModifiedProps = objModifiedProps.Count == 0 ? null : objModifiedProps;

            // All PastObjects that cannot be found by id in the CurrentObjs are old.
            deletedObjs = pastObjs_dict.Keys.Except(currObjs_dict.Keys)
                          .Select(k => pastObjs_dict[k]).ToList();

            if (!newObjs.Any() && !deletedObjs.Any() && !modifiedObjs.Any())
            {
                BH.Engine.Reflection.Compute.RecordWarning($"No difference could be found." +
                                                           $"\nThe provided Id of the objects were completely different between {nameof(pastObjects)} and {nameof(currentObjects)}." +
                                                           $"\nPlease make sure that:" +
                                                           $"\n\t * The input objects constitute the entirety of the model that changed between revisions;" +
                                                           $"\n\t * the input objects come from models that were not completely re-created between revisions.");
            }
            else if (!diffConfig.EnablePropertyDiffing)
            {
                BH.Engine.Reflection.Compute.RecordWarning($"For this Diffing method to detect modified/unchanged objects, you need to set '{nameof(DiffingConfig.EnablePropertyDiffing)}' to true in the DiffingConfig.");
            }

            return(new Diff(newObjs, deletedObjs, modifiedObjs, diffConfigCopy, objModifiedProps, unChanged));
        }
示例#17
0
        public static Revision Revision(IEnumerable <IBHoMObject> objects, object streamId, string revisionName = null, string comment = null, DiffingConfig diffConfig = null)
        {
            if (objects == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot create a revision from a null collection of objects.");
                return(null);
            }

            if (streamId == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot create a revision from a null stream ID.");
                return(null);
            }

            return(new Revision(Modify.PrepareForRevision(objects, diffConfig), ProcessStreamId(streamId), diffConfig, revisionName, comment));
        }
示例#18
0
        public static IEnumerable <T> PrepareForRevision <T>(this IEnumerable <T> objects, DiffingConfig diffConfig = null) where T : IBHoMObject
        {
            // Clone the current objects to preserve immutability; calculate and set the hash fragment
            IEnumerable <T> objs_cloned = Modify.SetRevisionFragment(objects, diffConfig);

            // Remove duplicates by hash
            objs_cloned = Modify.RemoveDuplicatesByHash(objs_cloned);

            if (objs_cloned.Count() != objects.Count())
            {
                Reflection.Compute.RecordWarning("Some Objects were duplicates (same hash) and therefore have been discarded.");
            }

            return(objs_cloned);
        }
示例#19
0
        public static Diff IDiffing(IEnumerable <object> pastObjs, IEnumerable <object> followingObjs, DiffingType diffingType = DiffingType.Automatic, DiffingConfig diffConfig = null)
        {
            if (!pastObjs.Any() || !followingObjs.Any())
            {
                BH.Engine.Reflection.Compute.RecordWarning("No input objects provided.");
                return(null);
            }

            // Set configurations if diffConfig is null. Clone it for immutability in the UI.
            DiffingConfig dc = diffConfig == null ? new DiffingConfig() : diffConfig.DeepClone();

            // If requested, compute the Diffing comparing each object one by one, in the same order.
            if (diffingType == DiffingType.OneByOne)
            {
                // If objects do not have any persistentId, `AllowOneByOneDiffing` is enabled and the collections have the same length,
                // compare objects from the two collections one by one.

                BH.Engine.Reflection.Compute.RecordNote($"Calling the diffing method '{nameof(DiffOneByOne)}'" +
                                                        $"\nThis will only identify 'modified' or 'unchanged' objects. It will work correctly only if the input objects are in the same order.");

                return(DiffOneByOne(pastObjs, followingObjs, dc));
            }

            // Check if the inputs specified are Revisions. In that case, use the Diffing-Revision workflow.
            if (diffingType == DiffingType.Automatic || diffingType == DiffingType.Revision)
            {
                if (pastObjs.Count() == 1 && followingObjs.Count() == 1)
                {
                    Revision pastRev = pastObjs.First() as Revision;
                    Revision follRev = followingObjs.First() as Revision;

                    if (pastRev != null && follRev != null)
                    {
                        BH.Engine.Reflection.Compute.RecordNote($"Calling the diffing method '{nameof(DiffRevisions)}'.");

                        if (!string.IsNullOrWhiteSpace(dc.CustomDataKey))
                        {
                            BH.Engine.Reflection.Compute.RecordWarning($"The `{nameof(DiffingConfig)}.{nameof(dc.CustomDataKey)}` is not considered when the input objects are both of type {nameof(Revision)}.");
                        }

                        return(DiffRevisions(pastRev, follRev, dc));
                    }
                }

                if (diffingType == DiffingType.Revision)
                {
                    return(DiffingError(diffingType));
                }
            }

            IEnumerable <IBHoMObject> bHoMObjects_past      = pastObjs.OfType <IBHoMObject>();
            IEnumerable <IBHoMObject> bHoMObjects_following = followingObjs.OfType <IBHoMObject>();

            // Check if the BHoMObjects all have a RevisionFragment assigned.
            // If so, we may attempt the Revision diffing.
            if (bHoMObjects_past.AllHaveRevisionFragment() && bHoMObjects_following.AllHaveRevisionFragment())
            {
                BH.Engine.Reflection.Compute.RecordNote($"Calling the diffing method '{nameof(DiffRevisionObjects)}'.");
                return(DiffRevisionObjects(bHoMObjects_past, bHoMObjects_following, dc));
            }

            // If a customDataKey was specified, use the Id found under that key in customdata to perform the Diffing.
            if (diffingType == DiffingType.Automatic || diffingType == DiffingType.CustomDataId)
            {
                if (diffingType == DiffingType.CustomDataId && !string.IsNullOrWhiteSpace(dc.CustomDataKey))
                {
                    return(DiffingError(diffingType));
                }

                if (!string.IsNullOrWhiteSpace(dc.CustomDataKey) && bHoMObjects_past.Count() == pastObjs.Count() && bHoMObjects_following.Count() == followingObjs.Count())
                {
                    BH.Engine.Reflection.Compute.RecordNote($"Calling the diffing method '{nameof(DiffWithCustomId)}'.");
                    return(DiffWithCustomId(bHoMObjects_past, bHoMObjects_following, dc.CustomDataKey, dc));
                }
                else
                {
                    BH.Engine.Reflection.Compute.RecordWarning($"To perform the diffing based on an Id stored in the Custom Data, the inputs must be collections of IBHoMObjects.");
                }
            }

            // Check if the bhomObjects have a persistentId assigned.
            List <object>      reminder_past;
            List <object>      reminder_following;
            List <IBHoMObject> bHoMObjects_past_persistId      = bHoMObjects_past.WithNonNullPersistentAdapterId(out reminder_past);
            List <IBHoMObject> bHoMObjects_following_persistId = bHoMObjects_following.WithNonNullPersistentAdapterId(out reminder_following);
            Diff fragmentDiff = null;

            // For the BHoMObjects we can compute the Diff with the persistentId.
            if (diffingType == DiffingType.Automatic || diffingType == DiffingType.PersistentId)
            {
                if (bHoMObjects_past_persistId.Count != 0 && bHoMObjects_following_persistId.Count != 0)
                {
                    BH.Engine.Reflection.Compute.RecordNote($"Calling the diffing method '{nameof(DiffWithFragmentId)}'.");
                }
                fragmentDiff = DiffWithFragmentId(bHoMObjects_past_persistId, bHoMObjects_following_persistId, typeof(IPersistentAdapterId), nameof(IPersistentAdapterId.PersistentId), dc);
            }

            // For the remaining objects (= all objects that are not BHoMObjects, and all BHoMObjects not having a PersistentId) we can Diff using the Hash.
            BH.Engine.Reflection.Compute.RecordNote($"Calling the most generic Diffing method, '{nameof(DiffWithHash)}'.");

            Diff diffGeneric = DiffWithHash(pastObjs as dynamic, followingObjs as dynamic, dc);

            if (fragmentDiff == null)
            {
                return(diffGeneric);
            }

            return(fragmentDiff.CombineDiffs(diffGeneric));
        }
示例#20
0
        public static Diff DiffRevisions(Revision pastRevision, Revision followingRevision, DiffingConfig diffingConfig = null)
        {
            if (pastRevision == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot compute the diff between revisions when the past revision is null.");
                return(null);
            }

            if (followingRevision == null)
            {
                BH.Engine.Reflection.Compute.RecordError("Cannot compute the diff between revisions when the following revision is null.");
                return(null);
            }

            return(DiffRevisionObjects(pastRevision.Objects, followingRevision.Objects, diffingConfig));
        }