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

CNX-619 Revit Analytical Panel #3645

Merged
merged 10 commits into from
Jan 9, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ public void AreaToNative(Element2D area, ApplicationObject appObj)
throw new ConversionException($"There is already a frame object named {area.name} in the model");
}

var propName = CreateOrGetProp(area.property, out bool isExactMatch);
if (!isExactMatch)
var propName = CreateOrGetProp(area.property, out bool isPropertyHandled);
if (!isPropertyHandled)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isPropertyHandled is a more appropriate name than isExactMatch

{
appObj.Update(
logItem: $"Area section for object could not be created and was replaced with section named \"{propName}\""
Expand Down Expand Up @@ -299,7 +299,7 @@ private string CreateAreaFromPoints(IEnumerable<Point> points, string propName)
return name;
}

private string? CreateOrGetProp(Property2D property, out bool isExactMatch)
private string? CreateOrGetProp(Property2D property, out bool isPropertyHandled)
{
int numberNames = 0;
string[] propNames = Array.Empty<string>();
Expand All @@ -310,30 +310,45 @@ private string CreateAreaFromPoints(IEnumerable<Point> points, string propName)
throw new ConversionException("Failed to retrieve the names of all defined area properties");
}

isExactMatch = true;
isPropertyHandled = true;

// Use the property if it already exists in the analytical model
if (propNames.Contains(property?.name))
{
return property.name;
}

if (property is CSIProperty2D prop2D)
// Create detailed property if it is of type CSI and doesn't exist in the analytical model
if (property is CSIProperty2D csiProp2D)
{
try
{
return Property2DToNative(prop2D);
return Property2DToNative(csiProp2D);
}
catch (Exception ex) when (!ex.IsFatal())
{
SpeckleLog.Logger.Error(ex, "Unable to create property2d");
// something failed... replace the type
isPropertyHandled = false;
}
}

isExactMatch = false;
if (propNames.Any())
/* Create the property with information we can use if it is a Property2D (i.e. thickness)
* Furthermore, a property can only be created if it has a name (hence the two conditionals).
* Name is inherited from the physical association in Revit (i.e. it comes from the type name of the family) */
if (property is Property2D structuralProp2D && !string.IsNullOrEmpty(structuralProp2D.name))
{
try
{
return Property2DToNative(structuralProp2D);
}
catch (Exception ex) when (!ex.IsFatal())
{
SpeckleLog.Logger.Error(ex, "Unable to create property2d");
}
}
isPropertyHandled = false;
if (propNames.Length > 0)
{
// TODO: support creating of Property2D
return propNames.First();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using CSiAPIv1;
using Objects.Structural.CSI.Analysis;
using Objects.Structural.CSI.Properties;
using Objects.Structural.Properties;

namespace Objects.Converter.CSI;

Expand All @@ -14,6 +15,20 @@ void setProperties(CSIProperty2D property2D, string matProp, double thickeness,
return;
}

private string Property2DToNative(Property2D property2D)
{
// Walls are typically shells (axially loaded)
if (property2D.type == Structural.PropertyType2D.Wall || property2D.type == Structural.PropertyType2D.Shell)
{
return WallPropertyToNative(property2D);
}
// Floors are typically plates (loaded in bending and shear)
else
{
return FloorPropertyToNative(property2D);
}
}

private string Property2DToNative(CSIProperty2D property2D)
{
if (property2D.type2D == CSIPropertyType2D.Wall)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using CSiAPIv1;
using Objects.Structural.CSI.Properties;
using Objects.Structural.Properties;
using Speckle.Core.Kits;

namespace Objects.Converter.CSI;
Expand Down Expand Up @@ -118,6 +119,24 @@ private string FloorSlabPropertyToNative(CSIProperty2D property2D)
return property2D.name;
}

// A Property2D can be created with the basic information we have i.e. thickness and material. No need to default to "Slab1"
public string FloorPropertyToNative(Property2D property2D)
{
var materialName = MaterialToNative(property2D.material);
int success = Model.PropArea.SetSlab(
property2D.name,
eSlabType.Slab,
eShellType.ShellThin,
materialName,
ScaleToNative(property2D.thickness, property2D.units)
);
if (success != 0)
{
throw new ConversionException("Failed to set slab property");
}
return property2D.name;
}

public string FloorPropertyToNative(CSIProperty2D property2D)
{
if (property2D.deckType != Structural.CSI.Analysis.DeckType.Null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
using CSiAPIv1;
using Objects.Structural.CSI.Properties;
using Objects.Structural.Properties;
using Speckle.Core.Kits;

namespace Objects.Converter.CSI;

public partial class ConverterCSI
{
public string WallPropertyToNative(CSIProperty2D Wall)
public string WallPropertyToNative(Property2D property2D)
{
throw new ConversionNotSupportedException("Wall properties are not currently supported on receive");
var materialName = MaterialToNative(property2D.material);
int success = Model.PropArea.SetWall(
property2D.name,
eWallPropType.Specified,
eShellType.ShellThin, // Lateral stability analysis typically has walls as thin shells
materialName,
ScaleToNative(property2D.thickness, property2D.units)
);
if (success != 0)
{
throw new ConversionException("Failed to set wall property");
}
return property2D.name;
}

public CSIProperty2D WallPropertyToSpeckle(string property)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<Compile Include="$(MSBuildThisFileDirectory)PartialClasses\ConvertCombinableElement.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PartialClasses\ConvertRevitElement.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PartialClasses\ConvertArea.cs" />
<Compile Include="$(MSBuildThisFileDirectory)partialclasses\ConvertStructuralMaterial.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PartialClasses\ConvertToposolid.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PartialClasses\ConvertView.Schedule.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PartialClasses\ConvertSpace.cs" />
Expand Down
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConvertAnalyticalSurface was using a method of GetStructuralMaterial which is inside ConvertAnalyticalStick (?). ConvertStructuralMaterial includes material related functions and these were moved out of ConvertAnalyticalStick.cs

Original file line number Diff line number Diff line change
Expand Up @@ -629,158 +629,4 @@ private void SetStructuralSectionProps(StructuralSection revitSection, SectionPr
//speckleSection["webToeOfFillet"] = u.WebToeOfFillet * scaleFactor; // this is in inches (or mm?) so it needs a different scaleFactor
}
}

private StructuralMaterial GetStructuralMaterial(Material material)
{
if (material == null)
{
return null;
}

StructuralAsset materialAsset = null;
string name = null;
if (material.StructuralAssetId != ElementId.InvalidElementId)
{
materialAsset = (
(PropertySetElement)material.Document.GetElement(material.StructuralAssetId)
).GetStructuralAsset();

name = material.Document.GetElement(material.StructuralAssetId)?.Name;
}
var materialName = material.MaterialClass;
var materialType = GetMaterialType(materialName);

var speckleMaterial = GetStructuralMaterial(materialType, materialAsset, name);
speckleMaterial.applicationId = material.UniqueId;

return speckleMaterial;
}

private StructuralMaterial GetStructuralMaterial(
StructuralMaterialType materialType,
StructuralAsset materialAsset,
string name
)
{
Structural.Materials.StructuralMaterial speckleMaterial = null;

if (materialType == StructuralMaterialType.Undefined && materialAsset != null)
{
materialType = GetMaterialType(materialAsset);
}

name ??= materialType.ToString();
switch (materialType)
{
case StructuralMaterialType.Concrete:
var concreteMaterial = new Concrete { name = name, materialType = Structural.MaterialType.Concrete, };

if (materialAsset != null)
{
concreteMaterial.compressiveStrength = materialAsset.ConcreteCompression; // Newtons per foot meter
concreteMaterial.lightweight = materialAsset.Lightweight;
}

speckleMaterial = concreteMaterial;
break;
case StructuralMaterialType.Steel:
var steelMaterial = new Steel
{
name = name,
materialType = Structural.MaterialType.Steel,
designCode = null,
codeYear = null,
maxStrain = 0,
dampingRatio = 0,
};

if (materialAsset != null)
{
steelMaterial.grade = materialAsset.Name;
steelMaterial.yieldStrength = materialAsset.MinimumYieldStress; // Newtons per foot meter
steelMaterial.ultimateStrength = materialAsset.MinimumTensileStrength; // Newtons per foot meter
}

speckleMaterial = steelMaterial;
break;
case StructuralMaterialType.Wood:
var timberMaterial = new Timber
{
name = name,
materialType = Structural.MaterialType.Timber,
designCode = null,
codeYear = null,
dampingRatio = 0
};

if (materialAsset != null)
{
timberMaterial.grade = materialAsset.WoodGrade;
timberMaterial.species = materialAsset.WoodSpecies;
timberMaterial["bendingStrength"] = materialAsset.WoodBendingStrength;
timberMaterial["parallelCompressionStrength"] = materialAsset.WoodParallelCompressionStrength;
timberMaterial["parallelShearStrength"] = materialAsset.WoodParallelShearStrength;
timberMaterial["perpendicularCompressionStrength"] = materialAsset.WoodPerpendicularCompressionStrength;
timberMaterial["perpendicularShearStrength"] = materialAsset.WoodPerpendicularShearStrength;
}

speckleMaterial = timberMaterial;
break;
default:
var defaultMaterial = new Objects.Structural.Materials.StructuralMaterial { name = name, };
speckleMaterial = defaultMaterial;
break;
}

// TODO: support non-isotropic materials
if (materialAsset != null)
{
// some of these are actually the dumbest units I've ever heard of
speckleMaterial.elasticModulus = materialAsset.YoungModulus.X; // Newtons per foot meter
speckleMaterial.poissonsRatio = materialAsset.PoissonRatio.X; // Unitless
speckleMaterial.shearModulus = materialAsset.ShearModulus.X; // Newtons per foot meter
speckleMaterial.density = materialAsset.Density; // kilograms per cubed feet
speckleMaterial.thermalExpansivity = materialAsset.ThermalExpansionCoefficient.X; // inverse Kelvin
}

return speckleMaterial;
}

private StructuralMaterialType GetMaterialType(string materialName)
{
StructuralMaterialType materialType = StructuralMaterialType.Undefined;
switch (materialName.ToLower())
{
case "concrete":
materialType = StructuralMaterialType.Concrete;
break;
case "steel":
materialType = StructuralMaterialType.Steel;
break;
case "wood":
materialType = StructuralMaterialType.Wood;
break;
}

return materialType;
}

private StructuralMaterialType GetMaterialType(StructuralAsset materialAsset)
{
StructuralMaterialType materialType = StructuralMaterialType.Undefined;
switch (materialAsset?.StructuralAssetClass)
{
case StructuralAssetClass.Metal:
materialType = StructuralMaterialType.Steel;
break;
case StructuralAssetClass.Concrete:
materialType = StructuralMaterialType.Concrete;
break;
case StructuralAssetClass.Wood:
materialType = StructuralMaterialType.Wood;
break;
}

return materialType;
}
}
Loading