Skip to content

Commit

Permalink
bjorn/cnx-880-add-sections-and-materials-as-proxies (#499)
Browse files Browse the repository at this point in the history
* HostAppVersion

v21 and v22 following SDK updates

* Working POC for material and section proxies

* Refactoring section unpacking

Refactoring in accordance with PropertiesExtractor example

* Material unpackers

* Notes and documentation

* More explanations

* materialId

- Interim solution for viewer filtering is appending the materialId to assignments for each object
- For FRAME this was easy
- For SHELL not so easy. No GetMaterial method avaiable given a AreaObj sectionName. Implemented lightweight materialCache based on cDatabaseTable. Marked as temporary based on previous discussions

* Explicit dictionary entries

* Repeated property strings as consts

- Fair point for repeated strings in the CsiMaterialPropertyExtractor.cs
- Even more reason to include this across all repeated strings. Categories of properties screaming out for this. Added additionally

* PR review comments

- Dictionary lookups for material and section proxies
- Only create proxies for assigned sections and materials (not pretty)

* refactor(etabs): adds singleton converter cache for material and section relationships (#514)

* This is a workaround for Revit's order of operations when initializing (#511)

* This is a workaround for Revit's order of operations when initializing

* Fix event listening

* adds a singleton cache for material and section relationships to csishared

* updating extraction results and simplifying classes

* Only allow methods on classes as opposed to anonymous lambdas for Event Subscription (#512)

* This is a workaround for Revit's order of operations when initializing

* Fix event listening

* Only allow methods on classes as opposed to anonymous lambdas

* formatting

* fix tests

* weakreference found should remove subscription

* doument model store fix (#516)

* testing commit

---------

Co-authored-by: Adam Hathcock <[email protected]>
Co-authored-by: Björn <[email protected]>

* resolving conflicts, testing and small tweaks

- merged dev into branch
- added "type" parameter to group proxies for sections in order to distinguish between frame sections and shell sections

---------

Co-authored-by: Claire Kuang <[email protected]>
Co-authored-by: Adam Hathcock <[email protected]>
  • Loading branch information
3 people authored Jan 22, 2025
1 parent e52df07 commit 7eb1de4
Show file tree
Hide file tree
Showing 36 changed files with 1,406 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Speckle.Connectors.CSiShared.Utils;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Converters.CSiShared.Utils;

namespace Speckle.Connectors.CSiShared.Bindings;

Expand All @@ -25,18 +26,6 @@ public CsiSharedSelectionBinding(IBrowserBridge parent, ICsiApplicationService c
/// </remarks>
public SelectionInfo GetSelection()
{
// TODO: Since this is standard across CSi Suite - better stored in an enum?
var objectTypeMap = new Dictionary<int, string>
{
{ 1, "Point" },
{ 2, "Frame" },
{ 3, "Cable" },
{ 4, "Tendon" },
{ 5, "Area" },
{ 6, "Solid" },
{ 7, "Link" }
};

int numberItems = 0;
int[] objectType = Array.Empty<int>();
string[] objectName = Array.Empty<string>();
Expand All @@ -48,10 +37,10 @@ public SelectionInfo GetSelection()

for (int i = 0; i < numberItems; i++)
{
var typeKey = objectType[i];
var typeName = objectTypeMap.TryGetValue(typeKey, out var name) ? name : $"Unknown ({typeKey})";
var typeKey = (ModelObjectType)objectType[i];
var typeName = typeKey.ToString();

encodedIds.Add(ObjectIdentifier.Encode(typeKey, objectName[i]));
encodedIds.Add(ObjectIdentifier.Encode(objectType[i], objectName[i]));
typeCounts[typeName] = (typeCounts.TryGetValue(typeName, out var count) ? count : 0) + 1; // NOTE: Cross-framework compatibility (net 48 and net8)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using Speckle.Converters.Common;
using Speckle.Converters.CSiShared;
using Speckle.Converters.CSiShared.Utils;

namespace Speckle.Connectors.CSiShared.HostApp.Helpers;

/// <summary>
/// Base frame section property extractor for CSi products.
/// </summary>
/// <remarks>
/// Handles common Csi API calls for frame section properties
/// Provides foundation for application-specific extractors.
/// </remarks>
public class CsiFrameSectionPropertyExtractor : IFrameSectionPropertyExtractor
{
private readonly IConverterSettingsStore<CsiConversionSettings> _settingsStore;

public CsiFrameSectionPropertyExtractor(IConverterSettingsStore<CsiConversionSettings> settingsStore)
{
_settingsStore = settingsStore;
}

public void ExtractProperties(string sectionName, Dictionary<string, object?> properties)
{
GetMaterialName(sectionName, properties);
GetSectionProperties(sectionName, properties);
GetPropertyModifiers(sectionName, properties);
}

private void GetMaterialName(string sectionName, Dictionary<string, object?> properties)
{
// get material name
string materialName = string.Empty;
_settingsStore.Current.SapModel.PropFrame.GetMaterial(sectionName, ref materialName);

// append to General Data of properties dictionary
Dictionary<string, object?> generalData = DictionaryUtils.EnsureNestedDictionary(
properties,
SectionPropertyCategory.GENERAL_DATA
);
generalData["material"] = materialName;
}

private void GetSectionProperties(string sectionName, Dictionary<string, object?> properties)
{
double crossSectionalArea = 0,
shearAreaInMajorAxisDirection = 0,
shearAreaInMinorAxisDirection = 0,
torsionalConstant = 0,
momentOfInertiaAboutMajorAxis = 0,
momentOfInertiaAboutMinorAxis = 0,
sectionModulusAboutMajorAxis = 0,
sectionModulusAboutMinorAxis = 0,
plasticModulusAboutMajorAxis = 0,
plasticModulusAboutMinorAxis = 0,
radiusOfGyrationAboutMajorAxis = 0,
radiusOfGyrationAboutMinorAxis = 0;

_settingsStore.Current.SapModel.PropFrame.GetSectProps(
sectionName,
ref crossSectionalArea,
ref shearAreaInMajorAxisDirection,
ref shearAreaInMinorAxisDirection,
ref torsionalConstant,
ref momentOfInertiaAboutMajorAxis,
ref momentOfInertiaAboutMinorAxis,
ref sectionModulusAboutMajorAxis,
ref sectionModulusAboutMinorAxis,
ref plasticModulusAboutMajorAxis,
ref plasticModulusAboutMinorAxis,
ref radiusOfGyrationAboutMajorAxis,
ref radiusOfGyrationAboutMinorAxis
);

Dictionary<string, object?> mechanicalProperties = DictionaryUtils.EnsureNestedDictionary(
properties,
SectionPropertyCategory.SECTION_PROPERTIES
);
mechanicalProperties["area"] = crossSectionalArea;
mechanicalProperties["As2"] = shearAreaInMajorAxisDirection;
mechanicalProperties["As3"] = shearAreaInMinorAxisDirection;
mechanicalProperties["torsion"] = torsionalConstant;
mechanicalProperties["I22"] = momentOfInertiaAboutMajorAxis;
mechanicalProperties["I33"] = momentOfInertiaAboutMinorAxis;
mechanicalProperties["S22"] = sectionModulusAboutMajorAxis;
mechanicalProperties["S33"] = sectionModulusAboutMinorAxis;
mechanicalProperties["Z22"] = plasticModulusAboutMajorAxis;
mechanicalProperties["Z33"] = plasticModulusAboutMinorAxis;
mechanicalProperties["R22"] = radiusOfGyrationAboutMajorAxis;
mechanicalProperties["R33"] = radiusOfGyrationAboutMinorAxis;
}

private void GetPropertyModifiers(string sectionName, Dictionary<string, object?> properties)
{
double[] stiffnessModifiersArray = [];
_settingsStore.Current.SapModel.PropFrame.GetModifiers(sectionName, ref stiffnessModifiersArray);

Dictionary<string, object?> modifiers =
new()
{
["crossSectionalAreaModifier"] = stiffnessModifiersArray[0],
["shearAreaInLocal2DirectionModifier"] = stiffnessModifiersArray[1],
["shearAreaInLocal3DirectionModifier"] = stiffnessModifiersArray[2],
["torsionalConstantModifier"] = stiffnessModifiersArray[3],
["momentOfInertiaAboutLocal2AxisModifier"] = stiffnessModifiersArray[4],
["momentOfInertiaAboutLocal3AxisModifier"] = stiffnessModifiersArray[5],
["mass"] = stiffnessModifiersArray[6],
["weight"] = stiffnessModifiersArray[7],
};

Dictionary<string, object?> generalData = DictionaryUtils.EnsureNestedDictionary(
properties,
SectionPropertyCategory.GENERAL_DATA
);
generalData["modifiers"] = modifiers;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
using Speckle.Converters.Common;
using Speckle.Converters.CSiShared;
using Speckle.Converters.CSiShared.Utils;

namespace Speckle.Connectors.CSiShared.HostApp.Helpers;

/// <summary>
/// Base material property extractor for CSi products.
/// </summary>
/// <remarks>
/// Currently, all material property extraction can happen on a CsiShared level which simplifies things a lot.
/// Properties depend on the directional symmetry of the material, hence the switch statements.
/// </remarks>
public class CsiMaterialPropertyExtractor
{
/// <summary>
/// Property strings for all mechanical properties, used by numerous methods.
/// </summary>
private static class MechanicalPropertyNames
{
public const string MODULUS_OF_ELASTICITY = "modulusOfElasticity";
public const string MODULUS_OF_ELASTICITY_ARRAY = "modulusOfElasticityArray";
public const string POISSON_RATIO = "poissonRatio";
public const string POISSON_RATIO_ARRAY = "poissonRatioArray";
public const string THERMAL_COEFFICIENT = "thermalCoefficient";
public const string THERMAL_COEFFICIENT_ARRAY = "thermalCoefficientArray";
public const string SHEAR_MODULUS = "shearModulus";
public const string SHEAR_MODULUS_ARRAY = "shearModulusArray";
}

private readonly IConverterSettingsStore<CsiConversionSettings> _settingsStore;

public CsiMaterialPropertyExtractor(IConverterSettingsStore<CsiConversionSettings> settingsStore)
{
_settingsStore = settingsStore;
}

public void ExtractProperties(string materialName, Dictionary<string, object?> properties)
{
GetGeneralProperties(materialName, properties);
GetWeightAndMassProperties(materialName, properties);
GetMechanicalProperties(materialName, properties);
}

private void GetGeneralProperties(string materialName, Dictionary<string, object?> properties)
{
{
eMatType materialType = default;
int materialColor = 0;
string materialNotes = string.Empty;
string materialGuid = string.Empty;

_settingsStore.Current.SapModel.PropMaterial.GetMaterial(
materialName,
ref materialType,
ref materialColor,
ref materialNotes,
ref materialGuid
);

var generalData = DictionaryUtils.EnsureNestedDictionary(properties, SectionPropertyCategory.GENERAL_DATA);
generalData["name"] = materialName;
generalData["type"] = materialType.ToString();
generalData["notes"] = materialNotes;
}
}

private void GetWeightAndMassProperties(string materialName, Dictionary<string, object?> properties)
{
double weightPerUnitVolume = double.NaN;
double massPerUnitVolume = double.NaN;

_settingsStore.Current.SapModel.PropMaterial.GetWeightAndMass(
materialName,
ref weightPerUnitVolume,
ref massPerUnitVolume
);

var weightAndMass = DictionaryUtils.EnsureNestedDictionary(properties, "Weight and Mass");
weightAndMass["w"] = weightPerUnitVolume;
weightAndMass["m"] = massPerUnitVolume;
}

private void GetMechanicalProperties(string materialName, Dictionary<string, object?> properties)
{
int materialDirectionalSymmetryKey = 0;
eMatType materialType = default;

_settingsStore.Current.SapModel.PropMaterial.GetTypeOAPI(
materialName,
ref materialType,
ref materialDirectionalSymmetryKey
);

var materialDirectionalSymmetryValue = materialDirectionalSymmetryKey switch
{
0 => DirectionalSymmetryType.ISOTROPIC,
1 => DirectionalSymmetryType.ORTHOTROPIC,
2 => DirectionalSymmetryType.ANISOTROPIC,
3 => DirectionalSymmetryType.UNIAXIAL,
_ => throw new ArgumentException($"Unknown symmetry type: {materialDirectionalSymmetryKey}")
};

var mechanicalProperties = DictionaryUtils.EnsureNestedDictionary(properties, "Mechanical Properties");
mechanicalProperties["directionalSymmetryType"] = materialDirectionalSymmetryValue.ToString();

GetMechanicalPropertiesByType(materialName, materialDirectionalSymmetryValue, mechanicalProperties);
}

private void GetMechanicalPropertiesByType(
string materialName,
DirectionalSymmetryType directionalSymmetryType,
Dictionary<string, object?> mechanicalProperties
)
{
switch (directionalSymmetryType)
{
case DirectionalSymmetryType.ISOTROPIC:
ExtractIsotropicProperties(materialName, mechanicalProperties);
break;
case DirectionalSymmetryType.ORTHOTROPIC:
ExtractOrthotropicProperties(materialName, mechanicalProperties);
break;
case DirectionalSymmetryType.ANISOTROPIC:
ExtractAnisotropicProperties(materialName, mechanicalProperties);
break;
case DirectionalSymmetryType.UNIAXIAL:
ExtractUniaxialProperties(materialName, mechanicalProperties);
break;
default:
throw new ArgumentException($"Unknown directional symmetry type: {directionalSymmetryType}");
}
}

private void ExtractIsotropicProperties(string materialName, Dictionary<string, object?> mechanicalProperties)
{
double modulusOfElasticity = double.NaN;
double poissonRatio = double.NaN;
double thermalCoefficient = double.NaN;
double shearModulus = double.NaN;

_settingsStore.Current.SapModel.PropMaterial.GetMPIsotropic(
materialName,
ref modulusOfElasticity,
ref poissonRatio,
ref thermalCoefficient,
ref shearModulus
);

mechanicalProperties[MechanicalPropertyNames.MODULUS_OF_ELASTICITY] = modulusOfElasticity;
mechanicalProperties[MechanicalPropertyNames.POISSON_RATIO] = poissonRatio;
mechanicalProperties[MechanicalPropertyNames.THERMAL_COEFFICIENT] = thermalCoefficient;
mechanicalProperties[MechanicalPropertyNames.SHEAR_MODULUS] = shearModulus;
}

private void ExtractOrthotropicProperties(string materialName, Dictionary<string, object?> mechanicalProperties)
{
double[] modulusOfElasticityArray = [];
double[] poissonRatioArray = [];
double[] thermalCoefficientArray = [];
double[] shearModulusArray = [];

_settingsStore.Current.SapModel.PropMaterial.GetMPOrthotropic(
materialName,
ref modulusOfElasticityArray,
ref poissonRatioArray,
ref thermalCoefficientArray,
ref shearModulusArray
);

mechanicalProperties[MechanicalPropertyNames.MODULUS_OF_ELASTICITY_ARRAY] = modulusOfElasticityArray;
mechanicalProperties[MechanicalPropertyNames.POISSON_RATIO_ARRAY] = poissonRatioArray;
mechanicalProperties[MechanicalPropertyNames.THERMAL_COEFFICIENT_ARRAY] = thermalCoefficientArray;
mechanicalProperties[MechanicalPropertyNames.SHEAR_MODULUS_ARRAY] = shearModulusArray;
}

private void ExtractAnisotropicProperties(string materialName, Dictionary<string, object?> mechanicalProperties)
{
double[] modulusOfElasticityArray = [];
double[] poissonRatioArray = [];
double[] thermalCoefficientArray = [];
double[] shearModulusArray = [];

_settingsStore.Current.SapModel.PropMaterial.GetMPAnisotropic(
materialName,
ref modulusOfElasticityArray,
ref poissonRatioArray,
ref thermalCoefficientArray,
ref shearModulusArray
);

mechanicalProperties[MechanicalPropertyNames.MODULUS_OF_ELASTICITY_ARRAY] = modulusOfElasticityArray;
mechanicalProperties[MechanicalPropertyNames.POISSON_RATIO_ARRAY] = poissonRatioArray;
mechanicalProperties[MechanicalPropertyNames.THERMAL_COEFFICIENT_ARRAY] = thermalCoefficientArray;
mechanicalProperties[MechanicalPropertyNames.SHEAR_MODULUS_ARRAY] = shearModulusArray;
}

private void ExtractUniaxialProperties(string materialName, Dictionary<string, object?> mechanicalProperties)
{
double modulusOfElasticity = double.NaN;
double thermalCoefficient = double.NaN;

_settingsStore.Current.SapModel.PropMaterial.GetMPUniaxial(
materialName,
ref modulusOfElasticity,
ref thermalCoefficient
);

mechanicalProperties[MechanicalPropertyNames.MODULUS_OF_ELASTICITY] = modulusOfElasticity;
mechanicalProperties[MechanicalPropertyNames.THERMAL_COEFFICIENT] = thermalCoefficient;
}
}
Loading

0 comments on commit 7eb1de4

Please sign in to comment.