Skip to content

Commit

Permalink
feat(civil3d): adds corridors (#302)
Browse files Browse the repository at this point in the history
* adds general and class properties extractors

* Update Speckle.Converters.Civil3dShared.projitems

* adds class properties for catchments

* adds catchment group proxies

* catchment proxy bug fix

* adds site props

* Update ClassPropertiesExtractor.cs

* Update ClassPropertiesExtractor.cs

* adds network, structure, and pipes

* registers pipe network

* adds alignment basecurves and properties

* adds profiles to alignments

* adds corridors

* fixes di and other corridor bugs

* parses corridor solid property sets

* Update CorridorHandler.cs

* Update CorridorHandler.cs

* adds body raw converter to autocad

* adds calculated info

* Update PropertySetDefinitionHandler.cs

* Update DBBodyToSpeckleRawConverter.cs
  • Loading branch information
clairekuang authored Oct 16, 2024
1 parent fa1fa35 commit 617bb5f
Show file tree
Hide file tree
Showing 16 changed files with 1,114 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\PointToHostConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\ArcToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\Solid3dToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\CircularArc2dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBArcToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBCircleToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBEllipseToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBLineToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBBodyToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBSolid3dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBCurveToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\CircleToSpeckleConverter.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;

namespace Speckle.Converters.Autocad.ToSpeckle.Raw;

public class CircularArc2dToSpeckleConverter : ITypedConverter<AG.CircularArc2d, SOG.Arc>
{
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;

public CircularArc2dToSpeckleConverter(
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_planeConverter = planeConverter;
_settingsStore = settingsStore;
}

public SOG.Arc Convert(AG.CircularArc2d target)
{
string units = _settingsStore.Current.SpeckleUnits;

// find arc plane (normal is in clockwise dir)
var center3 = new AG.Point3d(target.Center.X, target.Center.Y, 0);
AG.Plane plane = target.IsClockWise
? new AG.Plane(center3, AG.Vector3d.ZAxis.MultiplyBy(-1))
: new AG.Plane(center3, AG.Vector3d.ZAxis);

// calculate total angle. TODO: This needs to be validated across all possible arc orientations
var totalAngle = target.IsClockWise
? Math.Abs(target.EndAngle - target.StartAngle)
: Math.Abs(target.EndAngle - target.StartAngle);

double startParam = target.GetParameterOf(target.StartPoint);
double endParam = target.GetParameterOf(target.EndPoint);
AG.Point2d midPoint = target.EvaluatePoint(target.StartAngle + (target.EndAngle - target.StartAngle) / 2);

// create arc
var arc = new SOG.Arc()
{
plane = _planeConverter.Convert(plane),
radius = target.Radius,
startPoint = new()
{
x = target.StartPoint.X,
y = target.StartPoint.Y,
z = 0,
units = units
},
endPoint = new()
{
x = target.EndPoint.X,
y = target.EndPoint.Y,
z = 0,
units = units
},
midPoint = new()
{
x = midPoint.X,
y = midPoint.Y,
z = 0,
units = units
},
startAngle = target.StartAngle,
endAngle = target.EndAngle,
angleRadians = totalAngle,
domain = new SOP.Interval { start = startParam, end = endParam },
length = target.GetLength(0, 1),
units = units
};

return arc;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Sdk;
using Speckle.Sdk.Common.Exceptions;
using Speckle.Sdk.Models;

namespace Speckle.Converters.Autocad.ToSpeckle.Raw;

public class DBBodyToSpeckleRawConverter : ITypedConverter<ADB.Body, SOG.Mesh>
{
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;

public DBBodyToSpeckleRawConverter(
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_boxConverter = boxConverter;
_settingsStore = settingsStore;
}

public Base Convert(object target) => Convert((ADB.Body)target);

public SOG.Mesh Convert(ADB.Body target)
{
using ABR.Brep brep = new(target);
if (brep.IsNull)
{
throw new ConversionException("Could not retrieve brep from the body.");
}

var vertices = new List<AG.Point3d>();
var faces = new List<int>();

// create mesh from solid with mesh filter
using ABR.Mesh2dControl control = new();
control.MaxSubdivisions = 10000; // POC: these settings may need adjusting
using ABR.Mesh2dFilter filter = new();
filter.Insert(brep, control);
using ABR.Mesh2d m = new(filter);
foreach (ABR.Element2d e in m.Element2ds)
{
// get vertices
List<int> faceIndices = new();
foreach (ABR.Node n in e.Nodes)
{
faceIndices.Add(vertices.Count);
vertices.Add(n.Point);
n.Dispose();
}

// get faces
List<int> faceList = new() { e.Nodes.Count() };
for (int i = 0; i < e.Nodes.Count(); i++)
{
faceList.Add(faceIndices[i]);
}

faces.AddRange(faceList);

e.Dispose();
}

// mesh props
var convertedVertices = vertices.SelectMany(o => _pointConverter.Convert(o).ToList()).ToList();
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);

// create speckle mesh
SOG.Mesh mesh =
new()
{
vertices = convertedVertices,
faces = faces,
units = _settingsStore.Current.SpeckleUnits,
bbox = bbox
};

try
{
mesh.area = brep.GetSurfaceArea();
}
catch (Exception e) when (!e.IsFatal()) { }
try
{
mesh.volume = brep.GetVolume();
}
catch (Exception e) when (!e.IsFatal()) { }

return mesh;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,21 @@ public Base Convert(object target)

// get general properties
Dictionary<string, object?>? generalProperties = _generalPropertiesExtractor.GetGeneralProperties(entity);
if (generalProperties is not null)
if (generalProperties is not null && generalProperties.Count > 0)
{
properties.Add("Properties", generalProperties);
}

// get part data
Dictionary<string, object?>? partData = _partDataExtractor.GetPartData(entity);
if (partData is not null)
if (partData is not null && partData.Count > 0)
{
properties.Add("Part Data", partData);
}

// get property set data
Dictionary<string, object?>? propertySets = _propertySetExtractor.GetPropertySets(entity);
if (propertySets is not null)
if (propertySets is not null && propertySets.Count > 0)
{
properties.Add("Property Sets", propertySets);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Microsoft.Extensions.Logging;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Objects;

namespace Speckle.Converters.Civil3dShared.Helpers;

Expand All @@ -10,46 +9,103 @@ public sealed class BaseCurveExtractor
private readonly ILogger<DisplayValueExtractor> _logger;
private readonly IConverterSettingsStore<Civil3dConversionSettings> _converterSettings;
private readonly ITypedConverter<AG.LineSegment3d, SOG.Line> _lineConverter;

//private readonly ITypedConverter<AG.CircularArc2d, SOG.Arc> _arcConverter;
private readonly ITypedConverter<AG.CircularArc2d, SOG.Arc> _arcConverter;
private readonly ITypedConverter<CDB.AlignmentSubEntityLine, SOG.Line> _alignmentLineConverter;
private readonly ITypedConverter<CDB.AlignmentSubEntityArc, SOG.Arc> _alignmentArcConverter;
private readonly ITypedConverter<
(CDB.AlignmentSubEntitySpiral, CDB.Alignment),
SOG.Polyline
> _alignmentSpiralConverter;
private readonly ITypedConverter<ADB.Curve, Objects.ICurve> _curveConverter;

public BaseCurveExtractor(
ITypedConverter<AG.LineSegment3d, SOG.Line> lineConverter,
//ITypedConverter<AG.CircularArc2d, SOG.Arc> arcConverter,
ITypedConverter<AG.CircularArc2d, SOG.Arc> arcConverter,
ITypedConverter<CDB.AlignmentSubEntityLine, SOG.Line> alignmentLineConverter,
ITypedConverter<CDB.AlignmentSubEntityArc, SOG.Arc> alignmentArcConverter,
ITypedConverter<(CDB.AlignmentSubEntitySpiral, CDB.Alignment), SOG.Polyline> alignmentSpiralConverter,
ITypedConverter<ADB.Curve, Objects.ICurve> curveConverter,
ILogger<DisplayValueExtractor> logger,
IConverterSettingsStore<Civil3dConversionSettings> converterSettings
)
{
_lineConverter = lineConverter;
//_arcConverter = arcConverter;
_arcConverter = arcConverter;
_alignmentLineConverter = alignmentLineConverter;
_alignmentArcConverter = alignmentArcConverter;
_alignmentSpiralConverter = alignmentSpiralConverter;
_curveConverter = curveConverter;
_logger = logger;
_converterSettings = converterSettings;
}

public List<Speckle.Objects.ICurve>? GetBaseCurve(CDB.Entity entity)
public List<Speckle.Objects.ICurve>? GetBaseCurves(CDB.Entity entity)
{
switch (entity)
{
// rant: if this is a pipe, the BaseCurve prop is fake news && will return a DB.line with start and endpoints set to [0,0,0] & [0,0,1]
// do not use basecurve for pipes 😡
// currently not handling arc pipes due to lack of CircularArc2D converter, and also way to properly retrieve 2d arc curve
case CDB.Pipe pipe:
ICurve pipeCurve =
//pipe.SubEntityType == PipeSubEntityType.Straight ?
_lineConverter.Convert(new AG.LineSegment3d(pipe.StartPoint, pipe.EndPoint));
//: _arcConverter.Convert(pipe.Curve2d);
return new() { pipeCurve };
return GetPipeBaseCurves(pipe);

case CDB.Alignment:
ICurve baseCurve = _curveConverter.Convert(entity.BaseCurve);
return new() { baseCurve };
case CDB.Alignment alignment:
return GetAlignmentBaseCurves(alignment);

// for any entities that don't use their basecurve prop
default:
return null;
}
}

private List<Speckle.Objects.ICurve> GetPipeBaseCurves(CDB.Pipe pipe)
{
switch (pipe.SubEntityType)
{
case CDB.PipeSubEntityType.Curved:
return new() { _arcConverter.Convert(pipe.Curve2d) };

// POC: don't know how to properly handle segmented and flex pipes for now, sending them as lines
case CDB.PipeSubEntityType.Straight:
default:
return new() { _lineConverter.Convert(new AG.LineSegment3d(pipe.StartPoint, pipe.EndPoint)) };
}
}

private List<Speckle.Objects.ICurve> GetAlignmentBaseCurves(CDB.Alignment alignment)
{
// get the alignment subentity curves
List<Speckle.Objects.ICurve> curves = new();
for (int i = 0; i < alignment.Entities.Count; i++)
{
CDB.AlignmentEntity entity = alignment.Entities.GetEntityByOrder(i);
for (int j = 0; j < entity.SubEntityCount; j++)
{
CDB.AlignmentSubEntity subEntity = entity[j];
switch (subEntity.SubEntityType)
{
case CDB.AlignmentSubEntityType.Arc:
if (subEntity is CDB.AlignmentSubEntityArc arc)
{
curves.Add(_alignmentArcConverter.Convert(arc));
}
break;
case CDB.AlignmentSubEntityType.Line:
if (subEntity is CDB.AlignmentSubEntityLine line)
{
curves.Add(_alignmentLineConverter.Convert(line));
}
break;
case CDB.AlignmentSubEntityType.Spiral:
if (subEntity is CDB.AlignmentSubEntitySpiral spiral)
{
curves.Add(_alignmentSpiralConverter.Convert((spiral, alignment)));
}
break;
}
}
}

return curves;
}
}
Loading

0 comments on commit 617bb5f

Please sign in to comment.