Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Multiple Logic Requests #474

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 191 additions & 1 deletion Etabs_Adapter/CRUD/Read/_Read.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using BH.oM.Base;
Expand All @@ -39,6 +40,7 @@
using BH.oM.Adapter;
using System.ComponentModel;
using BH.oM.Data.Requests;
using BH.oM.Spatial.SettingOut;

namespace BH.Adapter.ETABS
{
Expand Down Expand Up @@ -97,6 +99,120 @@
return new List<IBHoMObject>();//<--- returning null will throw error in replace method of BHOM_Adapter line 34: can't do typeof(null) - returning null does seem the most sensible to return though
}

/***************************************************/

public IEnumerable<IBHoMObject> Read <T>(T request, ActionConfig actionConfig = null) where T : ILogicalRequest //- **GENERIC TYPES**
{

// Use of GENERIC TYPES, HASH TABLES, STREAMS and RECURSION

/* Use a HashSet data structure to make sure no collected elements are duplicate and to make access/search as fast as possible - **HASH TABLES ** */
HashSet < IBHoMObject > bhomObjects= new HashSet<IBHoMObject >();

/* 1. Handle the LogicalANDRequest */
if (request is LogicalAndRequest)
{
// 1.1 Initialize List of Requests to be extracted from LogicalRequest
List<IRequest> requests = (request as LogicalAndRequest).Requests;
// 1.2 Initialize DynamicComparer class instance allowing to check equality between IBHoMObject class instances
DynamicComparer iBHoMETABSComparer = new DynamicComparer();

// 1.3 Add to bhomObjects List all objects abiding by the FIRST request in the list... - **STREAMS**
IRequest req = requests[0];
// ...when it's a FilterRequest...
if (req.GetType() == typeof(FilterRequest)) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj));
// ...when it's a SelectionRequest...
if (req.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj));
// ...when it's a LogicalRequest...call the method recursively! - **RECURSION**
if (req is ILogicalRequest) bhomObjects=Read<ILogicalRequest>((ILogicalRequest)req, actionConfig).ToHashSet();


// 1.4 Add to bhomObjects List all objects abiding by ALL THE OTHER requests in the list... - **STREAMS**
for (int i = 1; i < requests.Count; i++)
{
// ...when they are FilterRequests...
if (requests[i].GetType() == typeof(FilterRequest)) bhomObjects = (bhomObjects.ToList().Intersect(Read((FilterRequest)requests[i], actionConfig).ToList(), iBHoMETABSComparer)).ToHashSet();
// ...when they are SelectionRequests...
if (requests[i].GetType() == typeof(SelectionRequest)) bhomObjects = (bhomObjects.ToList().Intersect(Read((SelectionRequest)requests[i], actionConfig).ToList(), iBHoMETABSComparer)).ToHashSet();
// ...when they are LogicalRequests...call the method recursively! - **RECURSION**
if (requests[i] is ILogicalRequest) bhomObjects = (bhomObjects.ToList().Intersect(Read<ILogicalRequest>((ILogicalRequest)requests[i], actionConfig))).ToHashSet();
}

// 1.5 Return list of bhomObjects
return bhomObjects;
}

/* 2. Handle the LogicalORRequest */
else if (request is LogicalOrRequest)
{
// 2.1 Initialize List of Requests to be extracted from LogicalRequest
List<IRequest> requests = (request as LogicalOrRequest).Requests;

// 2.2 Add to bhomObjects List all objects abiding by ALL requests in the list... - **STREAMS**
// ...when they are FilterRequests...
requests.ForEach(req => { if (req.GetType() == typeof(FilterRequest)) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj));
// ...when they are SelectionRequests...
if (req.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj));
// ...when they are LogicalRequests...call the method recursively! - **RECURSION**
if (req is ILogicalRequest) bhomObjects=Read<ILogicalRequest>((ILogicalRequest)req, actionConfig).ToHashSet(); });

// 2.3 Return list of bhomObjects
return bhomObjects;
}

/* 3. Handle the LogicalNOTRequest */
else if (request is LogicalNotRequest)
{
// 3.1 Initialize Lists and Hashsets for collecting all bhomObjects - **HASH TABLES **
IRequest iRequest = (request as LogicalNotRequest).Request;
HashSet<IBHoMObject> notBhomObjects = new HashSet<IBHoMObject>();
List<IBHoMObject> allBhomObjects = new List<IBHoMObject>();

// 3.2 Add to NOTbhomObjects HashSet all unique objects abiding by the Request input in the LogicalNOTRequest... - **STREAMS**
// ...when it's a FilterRequest...
if (iRequest.GetType() == typeof(FilterRequest)) Read((FilterRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj));
// ...when it's a SelectionRequest...
if (iRequest.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj));
// ...when it's a LogicalRequest...call the method recursively! - **RECURSION**
if (iRequest is ILogicalRequest) Read<ILogicalRequest>((ILogicalRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj));


// 3.3 Get all bhomObjects of ANY kind from ETABS Model... - **STREAMS**
Type[] bhomTypes = {typeof(Node),typeof(Bar),typeof(ISectionProperty), typeof(IMaterialFragment), typeof(Panel),
typeof(ISurfaceProperty), typeof(LoadCombination), typeof(Loadcase), typeof(ILoad), typeof(RigidLink),
typeof(LinkConstraint),typeof(oM.Spatial.SettingOut.Level),typeof(oM.Spatial.SettingOut.Grid),typeof(FEMesh)};

allBhomObjects = bhomTypes.ToList()
.Select(bhomType =>{ FilterRequest fr = new FilterRequest();
fr.Type = bhomType;
return fr;})
.Select(filtReq => Read(filtReq))
.SelectMany(x=>x) // Streams function allowing to flatten multidimensional lists!
.ToList();

// 3.4 Return the difference between ALL Objects and the ones NOT to be taken - **STREAMS**
// - .Except() Streams function returns the difference between two lists/data structures based on a specified EqualityComparer class)
return allBhomObjects.Except(notBhomObjects,new DynamicComparer());
}

BH.Engine.Base.Compute.RecordError($"Read for {request.GetType().Name} is not implemented in {(this as dynamic).GetType().Name}.");
return new List<IBHoMObject>();
}


public IEnumerable<IBHoMObject> Read(FilterRequest filterRequest, ActionConfig actionConfig = null)
{
// Extract the Ids from the FilterRequest
IList objectIds = null;
object idObject;
if (filterRequest.Equalities.TryGetValue("ObjectIds", out idObject) && idObject is IList)
objectIds = idObject as IList;

return IRead(filterRequest.Type, objectIds, actionConfig);
}



/***************************************************/

public IEnumerable<IBHoMObject> Read(SelectionRequest request, ActionConfig actionConfig = null)
Expand All @@ -118,7 +234,7 @@
int numItems = 0;
int[] objectTypes = new int[0];
string[] objectIds = new string[0];

m_model.SelectObj.GetSelected(ref numItems, ref objectTypes, ref objectIds);

Dictionary<int, List<string>> dict = objectTypes.Distinct().ToDictionary(x => x, x => new List<string>());
Expand Down Expand Up @@ -172,6 +288,80 @@

/***************************************************/

private class DynamicComparer : IEqualityComparer<IBHoMObject>

Check failure on line 291 in Etabs_Adapter/CRUD/Read/_Read.cs

View check run for this annotation

BHoMBot-CI / code-compliance

Etabs_Adapter/CRUD/Read/_Read.cs#L291

Files cannot contain more than one class - For more information see https://bhom.xyz/documentation/DevOps/Code%20Compliance%20and%20CI/Compliance%20Checks/HasSingleClass
{

// Use of STREAMS and REFLECTIONS

// 1. Equality based on ETABS obj Id or Name
public bool Equals(IBHoMObject obj1, IBHoMObject obj2)
{
if (obj1 == null || obj2 == null) return false;
if (obj1.GetType() != obj2.GetType()) return false;


Type objType = obj1.GetType();

// For physical objects, use Id as it is never null
if (objType == typeof(Node) || objType == typeof(Bar) || objType == typeof(Panel) || objType == typeof(RigidLink) || objType == typeof(FEMesh))
return getEtabsId(obj1).Id.ToString() == getEtabsId(obj2).Id.ToString();
// For all other items, use Name as it is never null
if (objType == typeof(ISectionProperty) || objType == typeof(IMaterialFragment) || objType == typeof(ISurfaceProperty) ||
objType == typeof(Loadcase) || objType == typeof(LoadCombination) || objType == typeof(ILoad) || objType == typeof(LinkConstraint) ||
objType == typeof(Level) || objType == typeof(Grid))
return obj1.Name.ToString() == obj2.Name.ToString();

return false;

}

// 2. HashCode based on Hash function of ETABS obj Id+Label or Type+Name
public int GetHashCode(IBHoMObject obj)
{
Type objType = obj.GetType();

// For physical objects, use Id and Label as they are never null
if (objType == typeof(Node) || objType == typeof(Bar) || objType == typeof(Panel) || objType == typeof(RigidLink) || objType == typeof(FEMesh))
return (getEtabsId(obj).Id.ToString() + getEtabsId(obj).Label.ToString()).GetHashCode();
// For all other items, use Name as Id/Label can be null
else if (objType == typeof(ISectionProperty) || objType == typeof(IMaterialFragment) || objType == typeof(ISurfaceProperty) ||
objType == typeof(Loadcase) || objType == typeof(LoadCombination) || objType == typeof(ILoad) || objType == typeof(LinkConstraint) ||
objType == typeof(Level) || objType == typeof(Grid))
return (obj.GetType().ToString() + obj.Name.ToString()).GetHashCode();

return 0;

}

// 3. Get ETABS Id using REFLECTION - **REFLECTION**
private ETABSId getEtabsId(IBHoMObject obj)

Check failure on line 337 in Etabs_Adapter/CRUD/Read/_Read.cs

View check run for this annotation

BHoMBot-CI / code-compliance

Etabs_Adapter/CRUD/Read/_Read.cs#L337

Method name should start with an uppercase letter - For more information see https://bhom.xyz/documentation/DevOps/Code%20Compliance%20and%20CI/Compliance%20Checks/MethodNameStartsUpper
{
// 1. Get the object Type
Type objsType = obj.GetType();
// 2. Get the Property Fragments - via REFLECTION
PropertyInfo fragmentsProperty = objsType.GetProperty("Fragments");
// 3. Downcast the Fragments Property to FragmentSet Class - via REFLECTION
FragmentSet fragments = (FragmentSet)fragmentsProperty.GetValue(obj);
// 4. Get the ETABSId object contained in the FragmentSet - via STREAMS
ETABSId etabsId = (ETABSId)(fragments.ToList().Find(frag => frag.GetType() == typeof(ETABSId)));
// 5. Return the Etabs Id of the object
return etabsId;
}


}


/***************************************************/

public static List<Type> GetClassesInNamespace(Assembly assembly, string nameSpace)
{
return assembly.GetTypes()
.Where(t => t.IsClass && t.Namespace == nameSpace)
.ToList();
}


}
}

Expand Down
Loading