public static List<IRelation> ToRelation(this IBHoMObject obj) { if(obj == null) { BH.Engine.Reflection.Compute.RecordError("Cannot convert a null BHoM object to a relation."); return new List<IRelation>(); } List<IRelation> relations = new List<IRelation>(); List<IFragment> dependencyFragments = obj.GetAllFragments(typeof(IDependencyFragment)); foreach (IDependencyFragment dependency in dependencyFragments) relations.AddRange(dependency.IToRelation(obj.BHoM_Guid)); return relations; }
private static ConditionResult VerifyCondition(List <object> objects, FragmentCondition fragmentCondition) { ConditionResult result = new ConditionResult() { Condition = fragmentCondition }; foreach (var obj in objects) { IBHoMObject bhomObj = obj as IBHoMObject; if (bhomObj != null && !IsAnyConditionNull(fragmentCondition.Condition, nameof(FragmentCondition) + "." + nameof(FragmentCondition.Condition))) { // If there is only one fragment of the specified type, no problem, the check will be done on it. // If the specified type is a parent type, all fragments of that type will be retrieved: // the condition will have to be satisfied for all fragments (forced AND). // To have an OR condition on the child fragments, // multiple conditions that target the individual fragment child type combined with a logical OR condition is needed. List <IFragment> fragments = bhomObj.GetAllFragments(fragmentCondition.FragmentType); ConditionResult subConditionResult = new ConditionResult(); subConditionResult = IVerifyCondition(fragments.OfType <object>().ToList(), fragmentCondition.Condition); // Forced AND on all child fragments. See comment above. if (subConditionResult.Pattern.TrueForAll(v => v == true)) { result.PassedObjects.Add(obj); result.Pattern.Add(true); } else { result.FailedObjects.Add(obj); result.Pattern.Add(false); } } else { // If the object is not a BHoMObject, the condition can't apply to it. result.FailedObjects.Add(obj); result.Pattern.Add(false); } } return(result); }
public static string Hash(this IObject iObj, ComparisonConfig comparisonConfig = null, bool hashFromFragment = false) { if (iObj == null) { BH.Engine.Reflection.Compute.RecordError("Cannot query the hash of a null object."); return(""); } if (hashFromFragment && iObj is IBHoMObject) { // Instead of computing the Hash, first tryGet the hash in HashFragment string hash = (iObj as IBHoMObject).FindFragment <HashFragment>()?.Hash; if (!string.IsNullOrWhiteSpace(hash)) { return(hash); } } // ------ SET UP OF CONFIGURATION ------ // Make sure we always have a config object. Clone for immutability. ComparisonConfig cc = comparisonConfig == null ? new ComparisonConfig() : comparisonConfig.DeepClone(); // Make sure that "BHoM_Guid" is added to the PropertyExceptions of the config. cc.PropertyExceptions = cc.PropertyExceptions ?? new List <string>(); if (!cc.PropertyExceptions.Contains(nameof(BHoMObject.BHoM_Guid))) { cc.PropertyExceptions.Add(nameof(BHoMObject.BHoM_Guid)); } // Process the "PropertiesToInclude" property. if (cc.PropertiesToConsider?.Any() ?? false) { // The hash computation can only consider "exceptions". // We need to retrieve all the object properties, intersect them with PropertiesToInclude, and treat all those remaining as "exceptions". // Works only for top-level properties. IEnumerable <string> exceptions = BH.Engine.Reflection.Query.PropertyNames(iObj).Except(cc.PropertiesToConsider); cc.PropertyExceptions.AddRange(exceptions); } // Make sure that the single Property exceptions are either: // - explicitly referring to a property in its "property path": e.g. Bar.StartNode.Point.X // - OR if it's only a property name e.g. BHoM_Guid make sure that we prepend the wildcard so we can match the single property inside any property path: e.g. *BHoM_Guid //cc.PropertyExceptions = cc.PropertyExceptions.Select(pe => pe = pe.Contains('.') ? pe : "*" + pe).ToList(); // Convert from the Numeric Tolerance to fractionalDigits (required for the hash). int fractionalDigits = Math.Abs(Convert.ToInt32(Math.Log10(cc.NumericTolerance))); // ----- SET UP OF INPUT OBJECT ----- // Copy the object for immutability IObject iObj_copy = iObj.ShallowClone(); // Any HashFragment present on the object must not be considered when computing the Hash. Remove if present. IBHoMObject bhomobj = iObj_copy as IBHoMObject; if (bhomobj != null) { List <IHashFragment> hashFragments = bhomobj.GetAllFragments(typeof(IHashFragment)).OfType <IHashFragment>().ToList(); hashFragments.ForEach(f => bhomobj.Fragments.Remove(f.GetType())); iObj_copy = bhomobj; } // ----- HASH ----- // Compute the defining string. string hashString = DefiningString(iObj_copy, cc, fractionalDigits, 0); if (string.IsNullOrWhiteSpace(hashString)) { // This means that: // - all properties of the input object were disregarded due to the settings specified in the ComparisonConfig, or // - all properties of the input object that were not disregarded were null or empty, // Since a hash has to be always returned, for this scenario we are forced to build a defining string out of the type full name. hashString = iObj_copy.GetType().FullName; } // Return the SHA256 hash of the defining string. return(SHA256Hash(hashString)); }