From 28132225b873f2d265b2b7b3b627a7809a7c454f Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 10 Sep 2024 18:32:02 +0100 Subject: [PATCH 01/17] Add Read Method for pulling IRequests --- Etabs_Adapter/CRUD/Read/_Read.cs | 12 ++ Etabs_Adapter/Convert/Execute.cs | 233 +++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 Etabs_Adapter/Convert/Execute.cs diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index 1f706111..7f4c4b1a 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -101,6 +101,18 @@ protected override IEnumerable IRead(Type type, IList ids, ActionCo /***************************************************/ + protected virtual IEnumerable Read(IRequest request, ActionConfig actionConfig = null) + { + // The implementation must: + // 1. extract all the needed info from the IRequest + // 2. return a call to the Basic Method Read() with the extracted info. + + BH.Engine.Base.Compute.RecordError($"Read for {request.GetType().Name} is not implemented in {(this as dynamic).GetType().Name}."); + return new List(); + } + + /***************************************************/ + public IEnumerable Read(SelectionRequest request, ActionConfig actionConfig = null) { List results = new List(); diff --git a/Etabs_Adapter/Convert/Execute.cs b/Etabs_Adapter/Convert/Execute.cs new file mode 100644 index 00000000..bad17880 --- /dev/null +++ b/Etabs_Adapter/Convert/Execute.cs @@ -0,0 +1,233 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2024, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System.Collections.Generic; +using System.Linq; +using BH.Engine.Adapter; +using BH.oM.Adapters.ETABS; +using BH.oM.Adapter; +using BH.oM.Base; +using BH.oM.Adapter.Commands; +using BH.oM.Structure.Loads; + +#if Debug16 || Release16 +using ETABS2016; +#elif Debug17 || Release17 +using ETABSv17; +#else +using CSiAPIv1; +#endif + + +namespace BH.Adapter.ETABS +{ +#if Debug16 || Release16 + public partial class ETABS2016Adapter +#elif Debug17 || Release17 + public partial class ETABS17Adapter +#else + public partial class ETABSAdapter +#endif + { + /***************************************************/ + /**** IAdapter Interface ****/ + /***************************************************/ + + public override Output, bool> Execute(IExecuteCommand command, ActionConfig actionConfig = null) + { + var output = new Output, bool>() { Item1 = null, Item2 = false }; + + output.Item2 = RunCommand(command as dynamic); + + return output; + } + + /***************************************************/ + /**** Commands ****/ + /***************************************************/ + + public bool RunCommand(NewModel command) + { + bool success = m_model.InitializeNewModel(eUnits.N_m_C) == 0; + success &= m_model.File.NewBlank() == 0; + return success; + } + + /***************************************************/ + + public bool RunCommand(Save command) + { + return m_model.File.Save() == 0; + } + + /***************************************************/ + + public bool RunCommand(SaveAs command) + { + return m_model.File.Save(command.FileName) == 0; + } + + /***************************************************/ + + public bool RunCommand(Open command) + { + if (System.IO.File.Exists(command.FileName)) + { + bool success = m_model.File.OpenFile(command.FileName) == 0; + success &= m_model.SetPresentUnits(eUnits.N_m_C) == 0; + return success; + } + else + { + Engine.Base.Compute.RecordError("File does not exist"); + return false; + } + } + + /***************************************************/ + + public bool RunCommand(Analyse command) + { + return Analyse(); + } + + /***************************************************/ + + public bool RunCommand(AnalyseLoadCases command) + { + if(command.LoadCases == null || command.LoadCases.Count() == 0) + Engine.Base.Compute.RecordNote("No cases provided, all cases will be run"); + + return Analyse(command.LoadCases); + } + + /***************************************************/ + + public bool RunCommand(ClearResults command) + { + if (m_model.Analyze.DeleteResults("", true) == 0) + { + return m_model.SetModelIsLocked(false) == 0; + } + else + { + return false; + } + } + + /***************************************************/ + + public bool RunCommand(Exit command) + { + if (command.SaveBeforeClose) + { + if (m_app.SapModel.GetModelFilepath() == "(Untitled)") + { + Engine.Base.Compute.RecordError($"Application not exited. File does not have a name. Please manually save the file or use the {nameof(SaveAs)} command before trying to Exit the application. If you want to close the application anyway, please toggle {nameof(Exit.SaveBeforeClose)} to false."); + return false; + } + } + + bool success = m_app.ApplicationExit(command.SaveBeforeClose) == 0; + m_app = null; + m_model = null; + return success; + } + + /***************************************************/ + + public bool RunCommand(IExecuteCommand command) + { + Engine.Base.Compute.RecordWarning($"The command {command.GetType().Name} is not supported by this Adapter."); + return false; + } + + /***************************************************/ + /**** Private helper methods ****/ + /***************************************************/ + + private bool Analyse(IEnumerable cases = null) + { + bool success; + + //Check if the model has been saved + if (m_model.GetModelFilename(true) == "(Untitled)") + { + Engine.Base.Compute.RecordWarning("ETABS requires the model to be saved before being analysed. Please save the model and try running again."); + return false; + } + + if (cases == null || cases.Count() == 0) + { + success = m_model.Analyze.SetRunCaseFlag("", true, true) == 0; + + if (!success) + { + Engine.Base.Compute.RecordWarning("Failed to set up cases to run. Model has not been analysed"); + return false; + } + } + else + { + //Unselect all cases + success = m_model.Analyze.SetRunCaseFlag("", false, true) == 0; + + //Select provided cases + foreach (object item in cases) + { + string name; + if (item == null) + continue; + if (item is string) + name = item as string; + else if (item is ICase) + name = (item as ICase).Name; + else + { + Engine.Base.Compute.RecordWarning("Can not set up cases for running of type " + item.GetType().Name + ". Item " + item.ToString() + " will be ignored. Please provide case names or BHoM cases to be run"); + continue; + } + + bool caseSuccess = m_model.Analyze.SetRunCaseFlag(name, true, false) == 0; + success &= caseSuccess; + + if (!caseSuccess) + { + Engine.Base.Compute.RecordWarning("Failed to set case " + name + "for running. Please check that the case exists in the model"); + } + } + + } + + success &= m_model.Analyze.RunAnalysis() == 0; + return success; + } + + /***************************************************/ + } +} + + + + + + From 5c7f07b19625216c20577fbb7383e700d9168fae Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Wed, 11 Sep 2024 14:45:34 +0100 Subject: [PATCH 02/17] Add Read Method for both FilterRequests and ILogicalRequests --- Etabs_Adapter/CRUD/Read/_Read.cs | 59 +++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index 7f4c4b1a..760bc6dd 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -101,16 +101,73 @@ protected override IEnumerable IRead(Type type, IList ids, ActionCo /***************************************************/ - protected virtual IEnumerable Read(IRequest request, ActionConfig actionConfig = null) + public IEnumerable Read (T request, ActionConfig actionConfig = null) where T : ILogicalRequest { // The implementation must: // 1. extract all the needed info from the IRequest // 2. return a call to the Basic Method Read() with the extracted info. + HashSet < IBHoMObject > bhomObjects= new HashSet(); + + if (request is LogicalAndRequest) + { + List requests = (request as LogicalAndRequest).Requests; + + IRequest req = requests[0]; + if (req.GetType() is FilterRequest) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType() is SelectionRequest) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType() is ILogicalRequest) Read((ILogicalRequest)req, actionConfig); + + for (int i = 1; i((ILogicalRequest)req, actionConfig); + } + + return bhomObjects; + + } + + else if (request is LogicalOrRequest) + + { + List requests = (request as LogicalOrRequest).Requests; + requests.ForEach(req => { if (req.GetType()==typeof(FilterRequest)) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((ILogicalRequest)req, actionConfig);}); + return bhomObjects; + } + + //else if (request is LogicalNotRequest) + //{ + + //} + + else + { + BH.Engine.Base.Compute.RecordError($"Requests of type {request?.GetType()} are not supported by the Excel adapter."); + return new List(); + } + BH.Engine.Base.Compute.RecordError($"Read for {request.GetType().Name} is not implemented in {(this as dynamic).GetType().Name}."); return new List(); } + + public IEnumerable 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 Read(SelectionRequest request, ActionConfig actionConfig = null) From 03069930b3bfb3e8898d405e37c94a2856185e27 Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Wed, 11 Sep 2024 21:02:02 +0100 Subject: [PATCH 03/17] Add Reflection-based Dynamic Comparer class to allow to intersect Hashsets of IBHoMObjects --- Etabs_Adapter/CRUD/Read/_Read.cs | 52 +++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index 760bc6dd..4c5c00a3 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -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; @@ -112,17 +113,20 @@ public IEnumerable Read (T request, ActionConfig actionConfig = if (request is LogicalAndRequest) { List requests = (request as LogicalAndRequest).Requests; - + + DynamicComparer iBHoMETABSComparer = new DynamicComparer(); + + IRequest req = requests[0]; - if (req.GetType() is FilterRequest) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); - if (req.GetType() is SelectionRequest) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); - if (req.GetType() is ILogicalRequest) Read((ILogicalRequest)req, actionConfig); + if (req.GetType() == typeof(FilterRequest)) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType() == typeof(ILogicalRequest)) Read((ILogicalRequest)req, actionConfig); for (int i = 1; i((ILogicalRequest)req, actionConfig); + if (requests[i].GetType() == typeof(FilterRequest)) bhomObjects=bhomObjects.Intersect(Read((FilterRequest)req, actionConfig), iBHoMETABSComparer).ToHashSet(); + if (requests[i].GetType() == typeof(SelectionRequest)) bhomObjects = bhomObjects.Intersect(Read((FilterRequest)req, actionConfig), iBHoMETABSComparer).ToHashSet(); + if (requests[i].GetType() == typeof(ILogicalRequest)) Read((ILogicalRequest)req, actionConfig); } return bhomObjects; @@ -257,6 +261,40 @@ private static List FilterIds(IEnumerable ids, IEnumerable + { + public bool Equals(IBHoMObject obj1, IBHoMObject obj2) + { + if (obj1 == null || obj2 == null) return false; + if (obj1.GetType() != obj2.GetType()) return false; + + return getEtabsId(obj1).Id==getEtabsId(obj2).Id; + + } + + public int GetHashCode(IBHoMObject obj) + { + throw new NotImplementedException(); + } + + private ETABSId getEtabsId(IBHoMObject obj) + { + // 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; + } + + + } + + } } From 1a75a9a899c4273935df58cdd4f41007d92f28ad Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Wed, 11 Sep 2024 21:11:21 +0100 Subject: [PATCH 04/17] Fix bug --- Etabs_Adapter/CRUD/Read/_Read.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index 4c5c00a3..ad003420 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -124,9 +124,9 @@ public IEnumerable Read (T request, ActionConfig actionConfig = for (int i = 1; i((ILogicalRequest)req, actionConfig); + if (requests[i].GetType() == typeof(FilterRequest)) bhomObjects=bhomObjects.Intersect(Read((FilterRequest)requests[i], actionConfig), iBHoMETABSComparer).ToHashSet(); + if (requests[i].GetType() == typeof(SelectionRequest)) bhomObjects = bhomObjects.Intersect(Read((SelectionRequest)requests[i], actionConfig), iBHoMETABSComparer).ToHashSet(); + if (requests[i].GetType() == typeof(ILogicalRequest)) Read((ILogicalRequest)requests[i], actionConfig); } return bhomObjects; From 3460fdf7b717982b12e9f0914b280a77e856e9b9 Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Wed, 11 Sep 2024 21:32:28 +0100 Subject: [PATCH 05/17] Turn HashSet into List to allow for use of .Equals method from Dynamic Comparer --- Etabs_Adapter/CRUD/Read/_Read.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index ad003420..2508679f 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -124,8 +124,8 @@ public IEnumerable Read (T request, ActionConfig actionConfig = for (int i = 1; i((ILogicalRequest)requests[i], actionConfig); } From afebaa6798e387efff0cc1a7537aab7234f94fc2 Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Wed, 11 Sep 2024 21:44:56 +0100 Subject: [PATCH 06/17] Fix minor issues --- Etabs_Adapter/CRUD/Read/_Read.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index 2508679f..e2f87c5c 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -124,8 +124,8 @@ public IEnumerable Read (T request, ActionConfig actionConfig = for (int i = 1; i((ILogicalRequest)requests[i], actionConfig); } @@ -274,7 +274,7 @@ public bool Equals(IBHoMObject obj1, IBHoMObject obj2) public int GetHashCode(IBHoMObject obj) { - throw new NotImplementedException(); + return obj.GetHashCode(); } private ETABSId getEtabsId(IBHoMObject obj) From 8674e6418ea511ef51d798d0221fbc2edb4102d8 Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 17 Sep 2024 12:56:41 +0100 Subject: [PATCH 07/17] Add code to read from LogicalNotRequests --- Etabs_Adapter/CRUD/Read/_Read.cs | 56 +++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index e2f87c5c..b16376d8 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -122,11 +122,11 @@ public IEnumerable Read (T request, ActionConfig actionConfig = if (req.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); if (req.GetType() == typeof(ILogicalRequest)) Read((ILogicalRequest)req, actionConfig); - for (int i = 1; i((ILogicalRequest)requests[i], actionConfig); + if (requests[i].GetType() == typeof(ILogicalRequest)) bhomObjects = (bhomObjects.ToList().Intersect(Read((ILogicalRequest)requests[i], actionConfig))).ToHashSet(); } return bhomObjects; @@ -137,16 +137,38 @@ public IEnumerable Read (T request, ActionConfig actionConfig = { List requests = (request as LogicalOrRequest).Requests; - requests.ForEach(req => { if (req.GetType()==typeof(FilterRequest)) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); - if (req.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); - if (req.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((ILogicalRequest)req, actionConfig);}); + requests.ForEach(req => { if (req.GetType() == typeof(FilterRequest)) Read((FilterRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)req, actionConfig).ToList().ForEach(bhomObj => bhomObjects.Add(bhomObj)); + if (req.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((ILogicalRequest)req, actionConfig); }); return bhomObjects; } - //else if (request is LogicalNotRequest) - //{ + else if (request is LogicalNotRequest) + { + IRequest iRequest = (request as LogicalNotRequest).Request; + + HashSet notBhomObjects = new HashSet(); + List allBhomObjects = new List(); + + if (iRequest.GetType() == typeof(FilterRequest)) Read((FilterRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj)); + if (iRequest.GetType() == typeof(SelectionRequest)) Read((SelectionRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj)); + if (iRequest.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((ILogicalRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj)); + + 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) + .ToList(); + + return allBhomObjects.Except(notBhomObjects,new DynamicComparer()); + } - //} else { @@ -193,7 +215,7 @@ public Dictionary> SelectedElements() int numItems = 0; int[] objectTypes = new int[0]; string[] objectIds = new string[0]; - + m_model.SelectObj.GetSelected(ref numItems, ref objectTypes, ref objectIds); // Replace Panels' type numbers with Openings' type numbers @@ -268,13 +290,13 @@ public bool Equals(IBHoMObject obj1, IBHoMObject obj2) if (obj1 == null || obj2 == null) return false; if (obj1.GetType() != obj2.GetType()) return false; - return getEtabsId(obj1).Id==getEtabsId(obj2).Id; + return getEtabsId(obj1).Label.ToString()==getEtabsId(obj2).Label.ToString(); } public int GetHashCode(IBHoMObject obj) { - return obj.GetHashCode(); + return getEtabsId(obj).PersistentId.GetHashCode(); } private ETABSId getEtabsId(IBHoMObject obj) @@ -295,6 +317,16 @@ private ETABSId getEtabsId(IBHoMObject obj) } + /***************************************************/ + + public static List GetClassesInNamespace(Assembly assembly, string nameSpace) + { + return assembly.GetTypes() + .Where(t => t.IsClass && t.Namespace == nameSpace) + .ToList(); + } + + } } From c3fad843b48979be60577c9cf07e831ab4a641f2 Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 17 Sep 2024 14:55:14 +0100 Subject: [PATCH 08/17] Add comments highlighting use of GENERIC TYPES, HASH TABLES, STREAMS, RECURSION AND REFLECTION --- Etabs_Adapter/CRUD/Read/_Read.cs | 54 +++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index b16376d8..f923964f 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -102,58 +102,83 @@ protected override IEnumerable IRead(Type type, IList ids, ActionCo /***************************************************/ - public IEnumerable Read (T request, ActionConfig actionConfig = null) where T : ILogicalRequest + public IEnumerable Read (T request, ActionConfig actionConfig = null) where T : ILogicalRequest //- **GENERIC TYPES** { - // The implementation must: - // 1. extract all the needed info from the IRequest - // 2. return a call to the Basic Method Read() with the extracted info. + // 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(); + /* 1. Handle the LogicalANDRequest */ if (request is LogicalAndRequest) { + // 1.1 Initialize List of Requests to be extracted from LogicalRequest List 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.GetType() == typeof(ILogicalRequest)) Read((ILogicalRequest)req, actionConfig); + + // 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].GetType() == typeof(ILogicalRequest)) bhomObjects = (bhomObjects.ToList().Intersect(Read((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 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.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((ILogicalRequest)req, actionConfig); }); + + // 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 notBhomObjects = new HashSet(); List allBhomObjects = new List(); + // 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.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((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)}; @@ -163,13 +188,14 @@ public IEnumerable Read (T request, ActionConfig actionConfig = fr.Type = bhomType; return fr;}) .Select(filtReq => Read(filtReq)) - .SelectMany(x=>x) + .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()); } - else { BH.Engine.Base.Compute.RecordError($"Requests of type {request?.GetType()} are not supported by the Excel adapter."); @@ -285,6 +311,10 @@ private static List FilterIds(IEnumerable ids, IEnumerable { + + // Use of STREAMS and REFLECTIONS + + // 1. Equality based on ETABS obj Label public bool Equals(IBHoMObject obj1, IBHoMObject obj2) { if (obj1 == null || obj2 == null) return false; @@ -294,11 +324,13 @@ public bool Equals(IBHoMObject obj1, IBHoMObject obj2) } + // 2. HashCode based on Hash function of ETABS obj PersistentId public int GetHashCode(IBHoMObject obj) { return getEtabsId(obj).PersistentId.GetHashCode(); } + // 3. Get ETABS Id using REFLECTION - **REFLECTION** private ETABSId getEtabsId(IBHoMObject obj) { // 1. Get the object Type From 06eee2bf4cdcfc45664b78e9a608f64951ad896f Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 17 Sep 2024 15:23:56 +0100 Subject: [PATCH 09/17] Remove outstanding lines of code --- Etabs_Adapter/CRUD/Read/_Read.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index f923964f..c78b8ad3 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -196,12 +196,6 @@ public IEnumerable Read (T request, ActionConfig actionConfig = return allBhomObjects.Except(notBhomObjects,new DynamicComparer()); } - else - { - BH.Engine.Base.Compute.RecordError($"Requests of type {request?.GetType()} are not supported by the Excel adapter."); - return new List(); - } - BH.Engine.Base.Compute.RecordError($"Read for {request.GetType().Name} is not implemented in {(this as dynamic).GetType().Name}."); return new List(); } From 15a93c56d986f3b2e6f7c4d56ada3fb16a7299bf Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 17 Sep 2024 16:16:49 +0100 Subject: [PATCH 10/17] Improve Hash function for the DynamicCompararer --- Etabs_Adapter/CRUD/Read/_Read.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index c78b8ad3..20e7ff51 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -321,7 +321,7 @@ public bool Equals(IBHoMObject obj1, IBHoMObject obj2) // 2. HashCode based on Hash function of ETABS obj PersistentId public int GetHashCode(IBHoMObject obj) { - return getEtabsId(obj).PersistentId.GetHashCode(); + return (getEtabsId(obj).Id.ToString() + getEtabsId(obj).Label.ToString()).GetHashCode(); } // 3. Get ETABS Id using REFLECTION - **REFLECTION** From a0a0911cee843614e9bb1679c9207763acb18833 Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 17 Sep 2024 19:19:22 +0100 Subject: [PATCH 11/17] Improve the Dynamic Comparer methods .Equals() and .GetHashCode() and adjust recursion calls --- Etabs_Adapter/CRUD/Read/_Read.cs | 33 ++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index 20e7ff51..5b33fa24 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -40,6 +40,7 @@ using BH.oM.Adapter; using System.ComponentModel; using BH.oM.Data.Requests; +using BH.oM.Spatial.SettingOut; namespace BH.Adapter.ETABS { @@ -125,7 +126,7 @@ public IEnumerable Read (T request, ActionConfig actionConfig = // ...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.GetType() == typeof(ILogicalRequest)) Read((ILogicalRequest)req, actionConfig); + if (req is ILogicalRequest) bhomObjects=Read((ILogicalRequest)req, actionConfig).ToHashSet(); // 1.4 Add to bhomObjects List all objects abiding by ALL THE OTHER requests in the list... - **STREAMS** @@ -136,7 +137,7 @@ public IEnumerable Read (T request, ActionConfig actionConfig = // ...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].GetType() == typeof(ILogicalRequest)) bhomObjects = (bhomObjects.ToList().Intersect(Read((ILogicalRequest)requests[i], actionConfig))).ToHashSet(); + if (requests[i] is ILogicalRequest) bhomObjects = (bhomObjects.ToList().Intersect(Read((ILogicalRequest)requests[i], actionConfig))).ToHashSet(); } // 1.5 Return list of bhomObjects @@ -155,7 +156,7 @@ public IEnumerable Read (T request, ActionConfig actionConfig = // ...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.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((ILogicalRequest)req, actionConfig); }); + if (req is ILogicalRequest) bhomObjects=Read((ILogicalRequest)req, actionConfig).ToHashSet(); }); // 2.3 Return list of bhomObjects return bhomObjects; @@ -175,7 +176,7 @@ public IEnumerable Read (T request, ActionConfig actionConfig = // ...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.GetType().IsSubclassOf(typeof(ILogicalRequest))) Read((ILogicalRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj)); + if (iRequest is ILogicalRequest) Read((ILogicalRequest)iRequest, actionConfig).ToList().ForEach(bhomObj => notBhomObjects.Add(bhomObj)); // 3.3 Get all bhomObjects of ANY kind from ETABS Model... - **STREAMS** @@ -314,14 +315,34 @@ public bool Equals(IBHoMObject obj1, IBHoMObject obj2) if (obj1 == null || obj2 == null) return false; if (obj1.GetType() != obj2.GetType()) return false; - return getEtabsId(obj1).Label.ToString()==getEtabsId(obj2).Label.ToString(); + Type objType = obj1.GetType(); + + 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(); + 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 PersistentId public int GetHashCode(IBHoMObject obj) { - return (getEtabsId(obj).Id.ToString() + getEtabsId(obj).Label.ToString()).GetHashCode(); + Type objType = obj.GetType(); + + 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(); + 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** From 2ee2250e5380af43bfa1f9126b554bab10bda24e Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 17 Sep 2024 19:22:57 +0100 Subject: [PATCH 12/17] Add comments --- Etabs_Adapter/CRUD/Read/_Read.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index 5b33fa24..a5e7fa65 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -309,7 +309,7 @@ private class DynamicComparer : IEqualityComparer // Use of STREAMS and REFLECTIONS - // 1. Equality based on ETABS obj Label + // 1. Equality based on ETABS obj Id or Name public bool Equals(IBHoMObject obj1, IBHoMObject obj2) { if (obj1 == null || obj2 == null) return false; @@ -318,8 +318,10 @@ public bool Equals(IBHoMObject obj1, IBHoMObject obj2) 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)) @@ -329,13 +331,15 @@ public bool Equals(IBHoMObject obj1, IBHoMObject obj2) } - // 2. HashCode based on Hash function of ETABS obj PersistentId + // 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)) From 53c41c947849ff35b80d6fbff779f73f587ac359 Mon Sep 17 00:00:00 2001 From: Giorgio Date: Mon, 14 Oct 2024 12:47:43 +0100 Subject: [PATCH 13/17] Update _Read.cs Turned the getEtabsId() method name (from the DynamicComparer private class) into GetEtabsId(), based on BHoM method's naming convention. --- Etabs_Adapter/CRUD/Read/_Read.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index a5e7fa65..db5df637 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -350,7 +350,7 @@ public int GetHashCode(IBHoMObject obj) } // 3. Get ETABS Id using REFLECTION - **REFLECTION** - private ETABSId getEtabsId(IBHoMObject obj) + private ETABSId GetEtabsId(IBHoMObject obj) { // 1. Get the object Type Type objsType = obj.GetType(); From 7174aee94b129a3126c9d479b1cfa103b468d0e8 Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Mon, 14 Oct 2024 13:00:41 +0100 Subject: [PATCH 14/17] Turn DynamicComparer private class into public class in Types namespace --- Etabs_Adapter/CRUD/Read/_Read.cs | 66 +-------------------- Etabs_Adapter/Etabs_Adapter.csproj | 1 + Etabs_Adapter/Types/DynamicComparer.cs | 81 ++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 65 deletions(-) create mode 100644 Etabs_Adapter/Types/DynamicComparer.cs diff --git a/Etabs_Adapter/CRUD/Read/_Read.cs b/Etabs_Adapter/CRUD/Read/_Read.cs index db5df637..769049f0 100644 --- a/Etabs_Adapter/CRUD/Read/_Read.cs +++ b/Etabs_Adapter/CRUD/Read/_Read.cs @@ -41,6 +41,7 @@ using System.ComponentModel; using BH.oM.Data.Requests; using BH.oM.Spatial.SettingOut; +using BH.Adapter.ETABS.Types; namespace BH.Adapter.ETABS { @@ -302,71 +303,6 @@ private static List FilterIds(IEnumerable ids, IEnumerable - { - - // 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) - { - // 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; - } - - - } - /***************************************************/ diff --git a/Etabs_Adapter/Etabs_Adapter.csproj b/Etabs_Adapter/Etabs_Adapter.csproj index ce6419c3..383486bb 100644 --- a/Etabs_Adapter/Etabs_Adapter.csproj +++ b/Etabs_Adapter/Etabs_Adapter.csproj @@ -381,6 +381,7 @@ + diff --git a/Etabs_Adapter/Types/DynamicComparer.cs b/Etabs_Adapter/Types/DynamicComparer.cs new file mode 100644 index 00000000..e1bf37d5 --- /dev/null +++ b/Etabs_Adapter/Types/DynamicComparer.cs @@ -0,0 +1,81 @@ +using BH.oM.Adapters.ETABS; +using BH.oM.Base; +using BH.oM.Spatial.SettingOut; +using BH.oM.Structure.Constraints; +using BH.oM.Structure.Elements; +using BH.oM.Structure.Loads; +using BH.oM.Structure.MaterialFragments; +using BH.oM.Structure.SectionProperties; +using BH.oM.Structure.SurfaceProperties; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace BH.Adapter.ETABS.Types +{ + public class DynamicComparer : IEqualityComparer + { + + // 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) + { + // 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; + } + + + } +} From 31623c096ff4315793383401356a950c47814d2c Mon Sep 17 00:00:00 2001 From: Giorgio Date: Thu, 24 Oct 2024 11:27:44 +0100 Subject: [PATCH 15/17] Add copyright header to DynamicComparer class --- Etabs_Adapter/Types/DynamicComparer.cs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Etabs_Adapter/Types/DynamicComparer.cs b/Etabs_Adapter/Types/DynamicComparer.cs index e1bf37d5..f2bfd26d 100644 --- a/Etabs_Adapter/Types/DynamicComparer.cs +++ b/Etabs_Adapter/Types/DynamicComparer.cs @@ -1,4 +1,27 @@ -using BH.oM.Adapters.ETABS; +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2021, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + + +using BH.oM.Adapters.ETABS; using BH.oM.Base; using BH.oM.Spatial.SettingOut; using BH.oM.Structure.Constraints; From ee7d8ae201c9e67e9a33d2e4b71a1a44f80f241a Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Mon, 28 Oct 2024 14:40:33 +0000 Subject: [PATCH 16/17] Repaste Copyright header in DynamicComparer --- Etabs_Adapter/Types/DynamicComparer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Etabs_Adapter/Types/DynamicComparer.cs b/Etabs_Adapter/Types/DynamicComparer.cs index f2bfd26d..cf348d6d 100644 --- a/Etabs_Adapter/Types/DynamicComparer.cs +++ b/Etabs_Adapter/Types/DynamicComparer.cs @@ -20,7 +20,6 @@ * along with this code. If not, see . */ - using BH.oM.Adapters.ETABS; using BH.oM.Base; using BH.oM.Spatial.SettingOut; From e482ce6afbb7d7a8aaae3b9eab4f3afece5556ba Mon Sep 17 00:00:00 2001 From: GCRA101 Date: Tue, 5 Nov 2024 15:41:12 +0000 Subject: [PATCH 17/17] Revert Execute.cs to original --- Etabs_Adapter/Convert/Execute.cs | 233 ------------------------------- 1 file changed, 233 deletions(-) delete mode 100644 Etabs_Adapter/Convert/Execute.cs diff --git a/Etabs_Adapter/Convert/Execute.cs b/Etabs_Adapter/Convert/Execute.cs deleted file mode 100644 index bad17880..00000000 --- a/Etabs_Adapter/Convert/Execute.cs +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2024, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using System.Collections.Generic; -using System.Linq; -using BH.Engine.Adapter; -using BH.oM.Adapters.ETABS; -using BH.oM.Adapter; -using BH.oM.Base; -using BH.oM.Adapter.Commands; -using BH.oM.Structure.Loads; - -#if Debug16 || Release16 -using ETABS2016; -#elif Debug17 || Release17 -using ETABSv17; -#else -using CSiAPIv1; -#endif - - -namespace BH.Adapter.ETABS -{ -#if Debug16 || Release16 - public partial class ETABS2016Adapter -#elif Debug17 || Release17 - public partial class ETABS17Adapter -#else - public partial class ETABSAdapter -#endif - { - /***************************************************/ - /**** IAdapter Interface ****/ - /***************************************************/ - - public override Output, bool> Execute(IExecuteCommand command, ActionConfig actionConfig = null) - { - var output = new Output, bool>() { Item1 = null, Item2 = false }; - - output.Item2 = RunCommand(command as dynamic); - - return output; - } - - /***************************************************/ - /**** Commands ****/ - /***************************************************/ - - public bool RunCommand(NewModel command) - { - bool success = m_model.InitializeNewModel(eUnits.N_m_C) == 0; - success &= m_model.File.NewBlank() == 0; - return success; - } - - /***************************************************/ - - public bool RunCommand(Save command) - { - return m_model.File.Save() == 0; - } - - /***************************************************/ - - public bool RunCommand(SaveAs command) - { - return m_model.File.Save(command.FileName) == 0; - } - - /***************************************************/ - - public bool RunCommand(Open command) - { - if (System.IO.File.Exists(command.FileName)) - { - bool success = m_model.File.OpenFile(command.FileName) == 0; - success &= m_model.SetPresentUnits(eUnits.N_m_C) == 0; - return success; - } - else - { - Engine.Base.Compute.RecordError("File does not exist"); - return false; - } - } - - /***************************************************/ - - public bool RunCommand(Analyse command) - { - return Analyse(); - } - - /***************************************************/ - - public bool RunCommand(AnalyseLoadCases command) - { - if(command.LoadCases == null || command.LoadCases.Count() == 0) - Engine.Base.Compute.RecordNote("No cases provided, all cases will be run"); - - return Analyse(command.LoadCases); - } - - /***************************************************/ - - public bool RunCommand(ClearResults command) - { - if (m_model.Analyze.DeleteResults("", true) == 0) - { - return m_model.SetModelIsLocked(false) == 0; - } - else - { - return false; - } - } - - /***************************************************/ - - public bool RunCommand(Exit command) - { - if (command.SaveBeforeClose) - { - if (m_app.SapModel.GetModelFilepath() == "(Untitled)") - { - Engine.Base.Compute.RecordError($"Application not exited. File does not have a name. Please manually save the file or use the {nameof(SaveAs)} command before trying to Exit the application. If you want to close the application anyway, please toggle {nameof(Exit.SaveBeforeClose)} to false."); - return false; - } - } - - bool success = m_app.ApplicationExit(command.SaveBeforeClose) == 0; - m_app = null; - m_model = null; - return success; - } - - /***************************************************/ - - public bool RunCommand(IExecuteCommand command) - { - Engine.Base.Compute.RecordWarning($"The command {command.GetType().Name} is not supported by this Adapter."); - return false; - } - - /***************************************************/ - /**** Private helper methods ****/ - /***************************************************/ - - private bool Analyse(IEnumerable cases = null) - { - bool success; - - //Check if the model has been saved - if (m_model.GetModelFilename(true) == "(Untitled)") - { - Engine.Base.Compute.RecordWarning("ETABS requires the model to be saved before being analysed. Please save the model and try running again."); - return false; - } - - if (cases == null || cases.Count() == 0) - { - success = m_model.Analyze.SetRunCaseFlag("", true, true) == 0; - - if (!success) - { - Engine.Base.Compute.RecordWarning("Failed to set up cases to run. Model has not been analysed"); - return false; - } - } - else - { - //Unselect all cases - success = m_model.Analyze.SetRunCaseFlag("", false, true) == 0; - - //Select provided cases - foreach (object item in cases) - { - string name; - if (item == null) - continue; - if (item is string) - name = item as string; - else if (item is ICase) - name = (item as ICase).Name; - else - { - Engine.Base.Compute.RecordWarning("Can not set up cases for running of type " + item.GetType().Name + ". Item " + item.ToString() + " will be ignored. Please provide case names or BHoM cases to be run"); - continue; - } - - bool caseSuccess = m_model.Analyze.SetRunCaseFlag(name, true, false) == 0; - success &= caseSuccess; - - if (!caseSuccess) - { - Engine.Base.Compute.RecordWarning("Failed to set case " + name + "for running. Please check that the case exists in the model"); - } - } - - } - - success &= m_model.Analyze.RunAnalysis() == 0; - return success; - } - - /***************************************************/ - } -} - - - - - -