feat(autocad/civil): add reference point behavior (#1126)

* adds reference point transform to publish

* only send reference point if not identity

* first pass at adding reference point transform to publish

* fixes transform matrix

* fixes autocad to system matrix conversion

* fixes text transforms

* removes bboxs

* removes to internal reference point (send only for now)

* fix nullability

* adds instance handling

* adds converter settings to civil

* refactors instance unpacker and polyline to speckle conversion

* fixes blocks and some polyline receive conversions

* removes transform on root

* feat(autocad): adds event tracking for change of ucs/wcs settings (#1164)

* feat: track ucs changes and invalidate cache

* chore: redundant qualifier

* fixes polyline conversions

time to cry

* fix(autocad): fixes polyline2d conversion with non-standard normals (#1169)

* fix: polyline2d like polyline

* refactor: coordinate system extension

* refactor: extension for pt3d to ocs

* renames reference point  methods

* moves logic to reference point converter

* Update AutocadPolycurveToHostConverter.cs (#1175)

---------

Co-authored-by: Björn Steinhagen <88777268+bjoernsteinhagen@users.noreply.github.com>
Co-authored-by: Oğuzhan Koral <45078678+oguzhankoral@users.noreply.github.com>
Co-authored-by: bimgeek <mucahitbgoker@gmail.com>
Co-authored-by: Mucahit Bilal GOKER <51519350+bimgeek@users.noreply.github.com>
This commit is contained in:
Claire Kuang
2026-02-10 13:16:27 +00:00
committed by GitHub
parent 9b9c383128
commit cd30370654
52 changed files with 866 additions and 378 deletions
@@ -1,6 +1,7 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Speckle.Connectors.Autocad.HostApp.Extensions;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
@@ -40,6 +41,9 @@ public abstract class AutocadSendBaseBinding : ISendBinding
/// </summary>
private ConcurrentBag<string> ChangedObjectIds { get; set; } = new();
private readonly List<string> _docSubsTracker = new();
private readonly Dictionary<string, Matrix3d> _docUcsTracker = new();
protected AutocadSendBaseBinding(
DocumentModelStore store,
IBrowserBridge parent,
@@ -71,6 +75,10 @@ public abstract class AutocadSendBaseBinding : ISendBinding
// catches the case when autocad just opens up with a blank new doc
SubscribeToObjectChanges(Application.DocumentManager.CurrentDocument);
}
Application.SystemVariableChanged += (_, e) =>
_topLevelExceptionHandler.CatchUnhandled(() => OnSystemVariableChanged(e));
// Since ids of the objects generates from same seed, we should clear the cache always whenever doc swapped.
_store.DocumentChanged += (_, _) =>
{
@@ -78,8 +86,6 @@ public abstract class AutocadSendBaseBinding : ISendBinding
};
}
private readonly List<string> _docSubsTracker = new();
private void SubscribeToObjectChanges(Document doc)
{
if (doc == null || doc.Database == null || _docSubsTracker.Contains(doc.Name))
@@ -88,11 +94,58 @@ public abstract class AutocadSendBaseBinding : ISendBinding
}
_docSubsTracker.Add(doc.Name);
_docUcsTracker[doc.Name] = doc.Editor.CurrentUserCoordinateSystem;
doc.Database.ObjectAppended += (_, e) => OnObjectChanged(e.DBObject);
doc.Database.ObjectErased += (_, e) => OnObjectChanged(e.DBObject);
doc.Database.ObjectModified += (_, e) => OnObjectChanged(e.DBObject);
}
/// <summary>
/// Handles system variable changes to detect UCS modifications.
/// When UCS changes, clears the conversion cache and expires all sender model cards.
/// </summary>
private void OnSystemVariableChanged(Autodesk.AutoCAD.ApplicationServices.SystemVariableChangedEventArgs e)
{
// check if this is a UCS-defining system variable
string varName = e.Name.ToUpperInvariant();
bool isUcsChange = varName == "UCSNAME" || varName == "UCSORG" || varName == "UCSXDIR" || varName == "UCSYDIR";
if (!isUcsChange)
{
return;
}
// get the currently active document
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null)
{
return;
}
var currentUcs = doc.Editor.CurrentUserCoordinateSystem;
// first time tracking this document's UCS
if (!_docUcsTracker.TryGetValue(doc.Name, out Matrix3d storedUcs))
{
_docUcsTracker[doc.Name] = currentUcs;
return;
}
// ucs hasn't actually changed (multiple variables fire for single UCS change)
if (currentUcs.IsEqualTo(storedUcs))
{
return;
}
// ucs has changed - all cached conversions invalid
_sendConversionCache.ClearCache();
_docUcsTracker[doc.Name] = currentUcs;
// expire all sender model cards
_idleManager.SubscribeToIdle(nameof(ExpireAllSenders), async () => await ExpireAllSenders());
}
private void OnObjectChanged(DBObject dbObject) =>
_topLevelExceptionHandler.CatchUnhandled(() => OnChangeChangedObjectIds(dbObject));
@@ -123,6 +176,19 @@ public abstract class AutocadSendBaseBinding : ISendBinding
ChangedObjectIds = new();
}
/// <summary>
/// Expires all sender model cards when a global change occurs (like UCS change).
/// </summary>
private async Task ExpireAllSenders()
{
var senders = _store.GetSenders();
var expiredSenderIds = senders.Select(s => s.ModelCardId.NotNull()).ToList();
if (expiredSenderIds.Count > 0)
{
await Commands.SetModelsExpired(expiredSenderIds);
}
}
public List<ISendFilter> GetSendFilters() => _sendFilters;
public List<ICardSetting> GetSendSettings() => [];
@@ -3,9 +3,9 @@ using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp.Extensions;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Instances;
using Speckle.Converters.Autocad.Helpers;
using Speckle.Converters.AutocadShared.ToSpeckle;
using Speckle.Converters.Common;
using Speckle.DoubleNumerics;
using Speckle.Sdk;
using Speckle.Sdk.Models.Instances;
@@ -46,6 +46,7 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
{
UnpackInstance(blockReference, 0, transaction);
}
_instanceObjectsManager.AddAtomicObject(obj.ApplicationId, obj);
}
return _instanceObjectsManager.GetUnpackResult();
@@ -66,13 +67,14 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
? instance.AnonymousBlockTableRecord
: instance.BlockTableRecord;
// transforms on instances are always stored in WCS
InstanceProxy instanceProxy =
new()
{
applicationId = instanceId,
definitionId = definitionId.ToString(),
maxDepth = depth,
transform = GetMatrix(instance.BlockTransform.ToArray()),
transform = TransformHelper.ConvertToInstanceMatrix4x4(instance.BlockTransform),
units = _unitsConverter.ConvertOrThrow(Application.DocumentManager.CurrentDocument.Database.Insunits)
};
@@ -173,6 +175,7 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
UnpackInstance(blockReference, depth + 1, transaction);
}
_instanceObjectsManager.AddAtomicDefinitionObjectId(appId);
_instanceObjectsManager.AddAtomicObject(appId, new(obj, appId));
}
@@ -183,7 +186,4 @@ public class AutocadInstanceUnpacker : IInstanceUnpacker<AutocadRootObject>
_logger.LogError(ex, "Failed unpacking Autocad instance");
}
}
private Matrix4x4 GetMatrix(double[] t) =>
new(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
}
@@ -51,6 +51,12 @@ public class AutocadMaterialUnpacker
if (transaction.GetObject(entity.MaterialId, OpenMode.ForRead) is Material material)
{
// skip default material
if (material.Name == "Global")
{
continue;
}
string materialId = material.GetSpeckleApplicationId();
if (materialProxies.TryGetValue(materialId, out RenderMaterialProxy? value))
{
@@ -77,6 +83,12 @@ public class AutocadMaterialUnpacker
{
if (transaction.GetObject(layer.MaterialId, OpenMode.ForRead) is Material material)
{
// skip default material
if (material.Name == "Global")
{
continue;
}
string materialId = material.GetSpeckleApplicationId();
string layerId = layer.GetSpeckleApplicationId(); // Do not use handle directly, see note in the 'GetSpeckleApplicationId' method
if (materialProxies.TryGetValue(materialId, out RenderMaterialProxy? value))
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Common.Builders;
@@ -7,6 +8,8 @@ using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Extensions;
using Speckle.Connectors.Common.Operations;
using Speckle.Converters.Autocad;
using Speckle.Converters.Autocad.Helpers;
using Speckle.Converters.Common;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
@@ -19,6 +22,7 @@ namespace Speckle.Connectors.Autocad.Operations.Send;
public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadRootObject>
{
private readonly IRootToSpeckleConverter _converter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _converterSettings;
private readonly string[] _documentPathSeparator = ["\\"];
private readonly ISendConversionCache _sendConversionCache;
private readonly AutocadInstanceUnpacker _instanceUnpacker;
@@ -30,6 +34,7 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
protected AutocadRootObjectBaseBuilder(
IRootToSpeckleConverter converter,
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
@@ -40,6 +45,7 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
)
{
_converter = converter;
_converterSettings = converterSettings;
_sendConversionCache = sendConversionCache;
_instanceUnpacker = instanceObjectManager;
_materialUnpacker = materialUnpacker;
@@ -81,17 +87,35 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
using Transaction tr = doc.Database.TransactionManager.StartTransaction();
// 1 - Unpack the instances
var (atomicObjects, instanceProxies, instanceDefinitionProxies) = _instanceUnpacker.UnpackSelection(objects);
var (atomicObjects, atomicDefinitionObjectIds, instanceProxies, instanceDefinitionProxies) =
_instanceUnpacker.UnpackSelection(objects);
root[ProxyKeys.INSTANCE_DEFINITION] = instanceDefinitionProxies;
// 2 - Unpack the groups
root[ProxyKeys.GROUP] = _groupUnpacker.UnpackGroups(atomicObjects);
// 3 - Add the Reference Point
Matrix3d? referenceTransform = null;
if (
Application.DocumentManager.CurrentDocument.Editor.CurrentUserCoordinateSystem is Matrix3d matrix
&& matrix != Matrix3d.Identity
)
{
referenceTransform = matrix.Inverse();
/* POC: Do not attach transform to root for now! we are not consuming this in autocad/civil on receive and in revit it will undo all baked transforms :(
var transformMatrix = ReferencePointHelper.CreateTransformDataForRootObject(matrix);
root[ReferencePointHelper.REFERENCE_POINT_TRANSFORM_KEY] = transformMatrix;
*/
}
using (var _ = _activityFactory.Start("Converting objects"))
{
// 3 - Convert atomic objects
List<LayerTableRecord> usedAcadLayers = new(); // Keeps track of autocad layers used, so we can pass them on later to the material and color unpacker.
List<SendConversionResult> results = new();
int count = 0;
// 4 - Convert atomic objects
foreach (var (entity, applicationId) in atomicObjects)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -104,9 +128,28 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
root.elements.Add(objectCollection);
}
var result = ConvertAutocadEntity(entity, applicationId, objectCollection, instanceProxies, projectId);
results.Add(result);
SendConversionResult? result = null;
// If this is a atomic definition object, we *do not* want to bake in the reference point transform to the object
if (atomicDefinitionObjectIds.Contains(applicationId))
{
using (_converterSettings.Push(currentSettings => currentSettings with { ReferencePointTransform = null }))
{
result = ConvertAutocadEntity(entity, applicationId, objectCollection, instanceProxies, projectId);
}
}
else // this is a selected atomic object (not part of definition)
{
result = ConvertAutocadEntity(
entity,
applicationId,
objectCollection,
instanceProxies,
projectId,
referenceTransform // set this for top level instance proxies to use if needed
);
}
results.Add(result);
onOperationProgressed.Report(new("Converting", (double)++count / atomicObjects.Count));
}
@@ -115,10 +158,10 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
throw new SpeckleException("Failed to convert all objects."); // fail fast instead creating empty commit! It will appear as model card error with red color.
}
// 4 - Unpack the render material proxies
// 5 - Unpack the render material proxies
root[ProxyKeys.RENDER_MATERIAL] = _materialUnpacker.UnpackMaterials(atomicObjects, usedAcadLayers);
// 5 - Unpack the color proxies
// 6 - Unpack the color proxies
root[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, usedAcadLayers);
// add any additional properties (most likely from verticals)
@@ -143,15 +186,24 @@ public abstract class AutocadRootObjectBaseBuilder : IRootObjectBuilder<AutocadR
string applicationId,
Collection collectionHost,
IReadOnlyDictionary<string, InstanceProxy> instanceProxies,
string projectId
string projectId,
Matrix3d? transform = null
)
{
string sourceType = entity.GetType().ToString();
try
{
Base converted;
if (entity is BlockReference && instanceProxies.TryGetValue(applicationId, out InstanceProxy? instanceProxy))
if (entity is BlockReference br && instanceProxies.TryGetValue(applicationId, out InstanceProxy? instanceProxy))
{
// modify transform by reference point this if it is top level
if (instanceProxy.maxDepth == 0 && transform is Matrix3d validTransform)
{
instanceProxy.transform = TransformHelper.ConvertToInstanceMatrix4x4(
br.BlockTransform.PreMultiplyBy(validTransform)
);
}
converted = instanceProxy;
}
else if (_sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value))
@@ -2,6 +2,7 @@ using Autodesk.AutoCAD.DatabaseServices;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Common.Caching;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models.Collections;
@@ -15,6 +16,7 @@ public sealed class AutocadRootObjectBuilder : AutocadRootObjectBaseBuilder
public AutocadRootObjectBuilder(
AutocadLayerUnpacker layerUnpacker,
IRootToSpeckleConverter converter,
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
@@ -25,6 +27,7 @@ public sealed class AutocadRootObjectBuilder : AutocadRootObjectBaseBuilder
)
: base(
converter,
converterSettings,
sendConversionCache,
instanceObjectManager,
materialUnpacker,
@@ -4,6 +4,7 @@ using Speckle.Connectors.Autocad.HostApp;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Operations;
using Speckle.Converters.Autocad;
using Speckle.Converters.Civil3dShared.ToSpeckle;
using Speckle.Converters.Common;
using Speckle.Sdk.Logging;
@@ -20,6 +21,7 @@ public sealed class Civil3dRootObjectBuilder : AutocadRootObjectBaseBuilder
AutocadLayerUnpacker layerUnpacker,
PropertySetDefinitionHandler propertySetDefinitionHandler,
IRootToSpeckleConverter converter,
IConverterSettingsStore<AutocadConversionSettings> converterSettings,
ISendConversionCache sendConversionCache,
AutocadInstanceUnpacker instanceObjectManager,
AutocadMaterialUnpacker materialUnpacker,
@@ -30,6 +32,7 @@ public sealed class Civil3dRootObjectBuilder : AutocadRootObjectBaseBuilder
)
: base(
converter,
converterSettings,
sendConversionCache,
instanceObjectManager,
materialUnpacker,
@@ -86,7 +86,7 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
unpackResults = _instanceUnpacker.UnpackSelection(rhinoObjects);
}
var (atomicObjects, instanceProxies, instanceDefinitionProxies) = unpackResults;
var (atomicObjects, atomicDefinitionObjectIds, instanceProxies, instanceDefinitionProxies) = unpackResults;
// POC: we should formalise this, sooner or later - or somehow fix it a bit more
rootObjectCollection[ProxyKeys.INSTANCE_DEFINITION] = instanceDefinitionProxies; // this won't work re traversal on receive
@@ -1,3 +1,3 @@
namespace Speckle.Converters.Autocad;
namespace Speckle.Converters.Autocad;
public record AutocadConversionSettings(Document Document, string SpeckleUnits);
public record AutocadConversionSettings(Document Document, AG.Matrix3d? ReferencePointTransform, string SpeckleUnits);
@@ -1,4 +1,4 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common;
using Speckle.InterfaceGenerator;
namespace Speckle.Converters.Autocad;
@@ -7,6 +7,12 @@ namespace Speckle.Converters.Autocad;
public class AutocadConversionSettingsFactory(IHostToSpeckleUnitConverter<ADB.UnitsValue> unitsConverter)
: IAutocadConversionSettingsFactory
{
public AutocadConversionSettings Create(Document document) =>
new(document, unitsConverter.ConvertOrThrow(document.Database.Insunits));
public AutocadConversionSettings Create(Document document)
{
AG.Matrix3d? m =
document.Editor.CurrentUserCoordinateSystem == AG.Matrix3d.Identity
? null
: document.Editor.CurrentUserCoordinateSystem;
return new(document, m, unitsConverter.ConvertOrThrow(document.Database.Insunits));
}
}
@@ -2,34 +2,6 @@ namespace Speckle.Converters.Autocad.Extensions;
public static class ListExtensions
{
public static SOG.Polyline ConvertToSpecklePolyline(this List<double> pointList, string speckleUnits)
{
// throw if list is malformed
if (pointList.Count % 3 != 0)
{
throw new ArgumentException("Point list of xyz values is malformed", nameof(pointList));
}
return new() { value = pointList, units = speckleUnits };
}
public static List<AG.Point2d> ConvertToPoint2d(this List<double> pointList, double conversionFactor = 1)
{
// throw if list is malformed
if (pointList.Count % 2 != 0)
{
throw new ArgumentException("Point list of xy values is malformed", nameof(pointList));
}
List<AG.Point2d> points2d = new(pointList.Count / 2);
for (int i = 1; i < pointList.Count; i += 2)
{
points2d.Add(new AG.Point2d(pointList[i - 1] * conversionFactor, pointList[i] * conversionFactor));
}
return points2d;
}
public static List<AG.Point3d> ConvertToPoint3d(this List<double> pointList, double conversionFactor = 1)
{
// throw if list is malformed
@@ -52,4 +24,18 @@ public static class ListExtensions
return points3d;
}
/// <summary>
/// Converts a list of doubles to Point3d objects and transforms them to OCS (Object Coordinate System)
/// based on the provided normal vector
/// </summary>
public static List<AG.Point3d> ConvertToPoint3dInOcs(
this List<double> pointList,
AG.Vector3d normal,
double conversionFactor = 1
)
{
AG.Matrix3d matrixOcs = AG.Matrix3d.WorldToPlane(normal);
return pointList.ConvertToPoint3d(conversionFactor).Select(p => p.TransformBy(matrixOcs)).ToList();
}
}
@@ -0,0 +1,42 @@
namespace Speckle.Converters.Autocad.Helpers;
/// <summary>
/// Helper class for working with reference points
/// </summary>
public static class ReferencePointHelper
{
public const string REFERENCE_POINT_TRANSFORM_KEY = "referencePointTransform";
/// <summary>
/// Changes Autocad Matrix3d Transform to a double array.
/// Uses a 16-element column-major matrix representation. See https://speckle.guide/dev/objects.html
/// </summary>
public static Dictionary<string, object> CreateTransformDataForRootObject(AG.Matrix3d transform)
{
return new Dictionary<string, object>
{
{
"transform", // TODO: it would also be nice to include the key-value pair for reference point type as a string
new[]
{
transform.CoordinateSystem3d.Xaxis.X,
transform.CoordinateSystem3d.Xaxis.Y,
transform.CoordinateSystem3d.Xaxis.Z,
0,
transform.CoordinateSystem3d.Yaxis.X,
transform.CoordinateSystem3d.Yaxis.Y,
transform.CoordinateSystem3d.Yaxis.Z,
0,
transform.CoordinateSystem3d.Zaxis.X,
transform.CoordinateSystem3d.Zaxis.Y,
transform.CoordinateSystem3d.Zaxis.Z,
0,
transform.CoordinateSystem3d.Origin.X,
transform.CoordinateSystem3d.Origin.Y,
transform.CoordinateSystem3d.Origin.Z,
1
}
}
};
}
}
@@ -0,0 +1,73 @@
using Speckle.DoubleNumerics;
namespace Speckle.Converters.Autocad.Helpers;
/// <summary>
/// Helper class for working with transforms
/// </summary>
public static class TransformHelper
{
/// <summary>
/// Converts an AutoCAD matrix3d to a row-dominant Speckle Matrix4x4
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
/// <remarks>
/// Use for System Numerics operations, eg matrix and vector multiplication
/// </remarks>
public static Matrix4x4 ConvertToMatrix4x4(AG.Matrix3d m) =>
new(
m[0, 0],
m[1, 0],
m[2, 0],
m[3, 0],
m[0, 1],
m[1, 1],
m[2, 1],
m[3, 1],
m[0, 2],
m[1, 2],
m[2, 2],
m[3, 2],
m[0, 3],
m[1, 3],
m[2, 3],
m[3, 3]
);
/// <summary>
/// Speckle Instances use a transform that is column-dominant, not row dominant.
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
/// <remarks>Use only for Speckle Instance object transforms.</remarks>
public static Matrix4x4 ConvertToInstanceMatrix4x4(AG.Matrix3d m) =>
new(
m[0, 0],
m[0, 1],
m[0, 2],
m[0, 3],
m[1, 0],
m[1, 1],
m[1, 2],
m[1, 3],
m[2, 0],
m[2, 1],
m[2, 2],
m[2, 3],
m[3, 0],
m[3, 1],
m[3, 2],
m[3, 3]
);
/// <summary>
/// Get the transform matrix from an entity's OCS to the WCS
/// </summary>
/// <param name="normal"></param>
/// <returns></returns>
/// <remarks>
/// Use this method for certain properties or methods on entities that return values in OCS
/// </remarks>
public static AG.Matrix3d GetTransformFromOCSToWCS(AG.Vector3d normal) => AG.Matrix3d.WorldToPlane(normal);
}
@@ -0,0 +1,33 @@
namespace Speckle.Converters.Autocad;
public interface IReferencePointConverter
{
/// <summary>
/// Converts a list of doubles representing point3ds in WCS coordinates to the current active coordinate system
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
List<double> ConvertWCSDoublesToExternalCoordinates(List<double> d);
/// <summary>
/// Converts a Point in WCS coordinates to the current active coordinate system
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
AG.Point3d ConvertWCSPointToExternalCoordinates(AG.Point3d p);
/// <summary>
/// Converts a Vector in WCS coordinates to the current active coordinate system
/// </summary>
/// <param name="v"></param>
/// <returns></returns>
AG.Vector3d ConvertWCSVectorToExternalCoordinates(AG.Vector3d v);
/// <summary>
/// Converts an elevation in OCS coordinates to the current active coordinate system
/// </summary>
/// <param name="e"> elevation in OCS</param>
/// <param name="normal">OCS plane normal in WCS</param>
/// <returns></returns>
double ConvertOCSElevationDoubleToExternalCoordinates(double e, AG.Vector3d normal);
}
@@ -0,0 +1,74 @@
using Speckle.Converters.Autocad.Helpers;
using Speckle.Converters.Common;
using Speckle.DoubleNumerics;
namespace Speckle.Converters.Autocad;
/// <summary>
/// POC: reference point functionality needs to be revisited (we are currently baking in these transforms into all geometry using the point and vector converters, and losing the transform).
/// This converter uses the transform from the converter settings (from the current doc)
/// </summary>
public class ReferencePointConverter(IConverterSettingsStore<AutocadConversionSettings> converterSettings)
: IReferencePointConverter
{
public List<double> ConvertWCSDoublesToExternalCoordinates(List<double> d)
{
if (d.Count % 3 != 0)
{
throw new ArgumentException("Point list of xyz values is malformed", nameof(d));
}
if (converterSettings.Current.ReferencePointTransform is AG.Matrix3d m)
{
Matrix4x4 transform = TransformHelper.ConvertToMatrix4x4(m.Inverse());
var transformed = new List<double>(d.Count);
for (int i = 0; i < d.Count; i += 3)
{
Vector3 p = Vector3.Transform(new(d[i], d[i + 1], d[i + 2]), transform);
transformed.Add(p.X);
transformed.Add(p.Y);
transformed.Add(p.Z);
}
return transformed;
}
return d;
}
public AG.Point3d ConvertWCSPointToExternalCoordinates(AG.Point3d p)
{
if (converterSettings.Current.ReferencePointTransform is AG.Matrix3d transform)
{
return p.TransformBy(transform.Inverse());
}
return p;
}
public AG.Vector3d ConvertWCSVectorToExternalCoordinates(AG.Vector3d v)
{
if (converterSettings.Current.ReferencePointTransform is AG.Matrix3d transform)
{
return v.TransformBy(transform.Inverse());
}
return v;
}
public double ConvertOCSElevationDoubleToExternalCoordinates(double elevation, AG.Vector3d normal)
{
// get a point on the plane in WCS
AG.Point3d wcsPoint = AG.Point3d.Origin + normal * elevation;
// transform to external coords
AG.Point3d extPoint = ConvertWCSPointToExternalCoordinates(wcsPoint);
AG.Vector3d extNormal = ConvertWCSVectorToExternalCoordinates(normal);
// calculate elevation as perpendicular distance in external coords
return extPoint.GetAsVector().DotProduct(extNormal);
}
}
@@ -26,6 +26,8 @@ public static class ServiceRegistration
>();
serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetExecutingAssembly());
serviceCollection.AddScoped<IReferencePointConverter, ReferencePointConverter>();
// add other classes
serviceCollection.AddScoped<PropertiesExtractor>();
serviceCollection.AddScoped<IPropertiesExtractor, PropertiesExtractor>();
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
@@ -16,6 +16,10 @@
<Compile Include="$(MSBuildThisFileDirectory)AutocadToSpeckleUnitConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\EntityExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ListExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\TransformHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\ReferencePointHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IReferencePointConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ReferencePointConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ServiceRegistration.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\AutocadPolycurveToHostConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\BrepToHostConverter.cs" />
@@ -54,6 +58,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\HatchToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\MTextToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\RegionToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\SubDMeshToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\SurfaceToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\Solid3dToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\DBTextToSpeckleConverter.cs" />
@@ -62,6 +67,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Properties\IPropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Properties\PropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\Solid3dToRawEncodingConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBSubDMeshToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\BrepToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\CircularArc2dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBArcToSpeckleRawConverter.cs" />
@@ -80,7 +86,6 @@
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\Polyline3dToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\PolylineToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\SplineToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\SubDMeshToSpeckleConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\BoxToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\CircularArc3dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBTextToSpeckleRawConverter.cs" />
@@ -88,9 +93,11 @@
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\LineSegment3dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\MTextToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\PlaneToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\PointToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\Point2dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DoublesToSpecklePolylineRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\Point3dToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBSplineToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\VectorToSpeckleRawConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\Vector3dToSpeckleRawConverter.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)ToHost\Helpers\" />
@@ -11,16 +11,19 @@ public class AutocadPolycurveToHostConverter : IToHostTopLevelConverter
private readonly ITypedConverter<SOG.Autocad.AutocadPolycurve, ADB.Polyline> _polylineConverter;
private readonly ITypedConverter<SOG.Autocad.AutocadPolycurve, ADB.Polyline2d> _polyline2dConverter;
private readonly ITypedConverter<SOG.Autocad.AutocadPolycurve, ADB.Polyline3d> _polyline3dConverter;
private readonly ITypedConverter<SOG.Polycurve, List<(ADB.Entity, Base)>> _polycurveConverter;
public AutocadPolycurveToHostConverter(
ITypedConverter<SOG.Autocad.AutocadPolycurve, ADB.Polyline> polylineConverter,
ITypedConverter<SOG.Autocad.AutocadPolycurve, ADB.Polyline2d> polyline2dConverter,
ITypedConverter<SOG.Autocad.AutocadPolycurve, ADB.Polyline3d> polyline3dConverter
ITypedConverter<SOG.Autocad.AutocadPolycurve, ADB.Polyline3d> polyline3dConverter,
ITypedConverter<SOG.Polycurve, List<(ADB.Entity, Base)>> polycurveConverter
)
{
_polylineConverter = polylineConverter;
_polyline2dConverter = polyline2dConverter;
_polyline3dConverter = polyline3dConverter;
_polycurveConverter = polycurveConverter;
}
public object Convert(Base target)
@@ -30,7 +33,7 @@ public class AutocadPolycurveToHostConverter : IToHostTopLevelConverter
switch (polycurve.polyType)
{
case SOG.Autocad.AutocadPolyType.Light:
return _polylineConverter.Convert(polycurve);
return Has2DValue(polycurve) ? _polycurveConverter.Convert(polycurve) : _polylineConverter.Convert(polycurve);
case SOG.Autocad.AutocadPolyType.Simple2d:
case SOG.Autocad.AutocadPolyType.FitCurve2d:
@@ -47,4 +50,29 @@ public class AutocadPolycurveToHostConverter : IToHostTopLevelConverter
throw new ValidationException("Unknown poly type for AutocadPolycurve");
}
}
// Method for backwards compatibility: polylines from 3.10 and before had point2d values in OCS instead of point3d values in WCS/UCS
private bool Has2DValue(SOG.Autocad.AutocadPolycurve polycurve)
{
int pointListCount = polycurve.value.Count;
if (pointListCount % 3 == 0 && pointListCount % 2 != 0)
{
return false;
}
if (pointListCount % 2 != 0)
{
throw new ValidationException(
"Polycurve value list was deformed, could not translate into 2d or 3d coordinates."
);
}
int segmentVertexCount = polycurve.closed ? polycurve.segments.Count : polycurve.segments.Count + 1;
if (pointListCount / 2 == segmentVertexCount)
{
return true;
}
return false;
}
}
@@ -26,33 +26,33 @@ public class AutocadPolycurveToHostPolyline2dRawConverter
// check for normal
if (target.normal is not SOG.Vector normal)
{
throw new System.ArgumentException($"Autocad polycurve of type {target.polyType} did not have a normal");
throw new ArgumentException($"Autocad polycurve of type {target.polyType} did not have a normal");
}
// check for elevation
if (target.elevation is not double elevation)
{
throw new System.ArgumentException($"Autocad polycurve of type {target.polyType} did not have an elevation");
throw new ArgumentException($"Autocad polycurve of type {target.polyType} did not have an elevation");
}
// get vertices
// convert the normal, get vertices and transform them to ocs
var convertedNormal = _vectorConverter.Convert(normal);
double f = Units.GetConversionFactor(target.units, _settingsStore.Current.SpeckleUnits);
List<AG.Point3d> points = target.value.ConvertToPoint3d(f);
List<AG.Point3d> points = target.value.ConvertToPoint3dInOcs(convertedNormal, f);
// check for invalid bulges
if (target.bulges is null || target.bulges.Count < points.Count)
{
throw new System.ArgumentException($"Autocad polycurve of type {target.polyType} had null or malformed bulges");
throw new ArgumentException($"Autocad polycurve of type {target.polyType} had null or malformed bulges");
}
// check for invalid tangents
if (target.tangents is null || target.tangents.Count < points.Count)
{
throw new System.ArgumentException($"Autocad polycurve of type {target.polyType} had null or malformed tangents");
throw new ArgumentException($"Autocad polycurve of type {target.polyType} had null or malformed tangents");
}
// create the polyline2d using the empty constructor
AG.Vector3d convertedNormal = _vectorConverter.Convert(normal);
double convertedElevation = elevation * f;
ADB.Polyline2d polyline =
new()
@@ -24,26 +24,26 @@ public class AutocadPolycurveToHostPolylineRawConverter : ITypedConverter<SOG.Au
{
if (target.normal is null || target.elevation is null)
{
throw new System.ArgumentException(
"Autocad polycurve of type light did not have a valid normal and/or elevation"
);
throw new ArgumentException("Autocad polycurve of type light did not have a valid normal and/or elevation");
}
// convert the normal, get vertices and transform them to ocs
AG.Vector3d normal = _vectorConverter.Convert(target.normal);
double f = Units.GetConversionFactor(target.units, _settingsStore.Current.SpeckleUnits);
List<AG.Point2d> points2d = target.value.ConvertToPoint2d(f);
List<AG.Point3d> points3d = target.value.ConvertToPoint3dInOcs(normal, f);
ADB.Polyline polyline =
new()
{
Normal = _vectorConverter.Convert(target.normal),
Normal = normal,
Elevation = (double)target.elevation * f,
Closed = target.closed
};
for (int i = 0; i < points2d.Count; i++)
for (int i = 0; i < points3d.Count; i++)
{
var bulge = target.bulges is null ? 0 : target.bulges[i];
polyline.AddVertexAt(i, points2d[i], bulge, 0, 0);
polyline.AddVertexAt(i, new(points3d[i].X, points3d[i].Y), bulge, 0, 0);
}
return polyline;
@@ -1,4 +1,3 @@
using Autodesk.AutoCAD.Geometry;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Sdk.Models;
@@ -14,18 +13,15 @@ namespace Speckle.Converters.Autocad.Geometry;
[NameAndRankValue(typeof(ADB.PolyFaceMesh), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK)]
public class DBPolyfaceMeshToSpeckleConverter : IToSpeckleTopLevelConverter
{
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBPolyfaceMeshToSpeckleConverter(
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_boxConverter = boxConverter;
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -33,7 +29,7 @@ public class DBPolyfaceMeshToSpeckleConverter : IToSpeckleTopLevelConverter
public SOG.Mesh RawConvert(ADB.PolyFaceMesh target)
{
List<Point3d> dbVertices = new();
List<double> vertices = new();
List<int> faces = new();
List<int> faceVisibility = new();
List<int> colors = new();
@@ -45,7 +41,9 @@ public class DBPolyfaceMeshToSpeckleConverter : IToSpeckleTopLevelConverter
switch (obj)
{
case ADB.PolyFaceMeshVertex o:
dbVertices.Add(o.Position);
vertices.Add(o.Position.X);
vertices.Add(o.Position.Y);
vertices.Add(o.Position.Z);
colors.Add(o.Color.ColorValue.ToArgb());
break;
case ADB.FaceRecord o:
@@ -84,22 +82,13 @@ public class DBPolyfaceMeshToSpeckleConverter : IToSpeckleTopLevelConverter
tr.Commit();
}
List<double> vertices = new(dbVertices.Count * 3);
foreach (Point3d vert in dbVertices)
{
vertices.AddRange(_pointConverter.Convert(vert).ToList());
}
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);
SOG.Mesh speckleMesh =
new()
{
vertices = vertices,
vertices = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(vertices), // transform by reference point
faces = faces,
colors = colors,
units = _settingsStore.Current.SpeckleUnits,
bbox = bbox,
["faceVisibility"] = faceVisibility
};
@@ -19,30 +19,30 @@ public class Polyline2dToSpeckleConverter
: IToSpeckleTopLevelConverter,
ITypedConverter<ADB.Polyline2d, SOG.Autocad.AutocadPolycurve>
{
private readonly ITypedConverter<List<double>, SOG.Polyline> _doublesConverter;
private readonly ITypedConverter<ADB.Arc, SOG.Arc> _arcConverter;
private readonly ITypedConverter<ADB.Line, SOG.Line> _lineConverter;
private readonly ITypedConverter<ADB.Polyline, SOG.Autocad.AutocadPolycurve> _polylineConverter;
private readonly ITypedConverter<ADB.Spline, SOG.Curve> _splineConverter;
private readonly ITypedConverter<AG.Vector3d, SOG.Vector> _vectorConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public Polyline2dToSpeckleConverter(
ITypedConverter<List<double>, SOG.Polyline> doublesConverter,
ITypedConverter<ADB.Arc, SOG.Arc> arcConverter,
ITypedConverter<ADB.Line, SOG.Line> lineConverter,
ITypedConverter<ADB.Polyline, SOG.Autocad.AutocadPolycurve> polylineConverter,
ITypedConverter<ADB.Spline, SOG.Curve> splineConverter,
ITypedConverter<AG.Vector3d, SOG.Vector> vectorConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_doublesConverter = doublesConverter;
_arcConverter = arcConverter;
_lineConverter = lineConverter;
_polylineConverter = polylineConverter;
_splineConverter = splineConverter;
_vectorConverter = vectorConverter;
_boxConverter = boxConverter;
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -85,11 +85,13 @@ public class Polyline2dToSpeckleConverter
for (int i = 0; i < vertices.Count; i++)
{
ADB.Vertex2d vertex = vertices[i];
ADB.Vertex2d vertex = vertices[i]; // this is in OCS
// get vertex value in the Global Coordinate System (GCS).
// NOTE: for some reason, the z value of the position for rotated polyline2ds doesn't seem to match the exploded segment endpoint values
value.AddRange(vertex.Position.ToArray());
AG.Point3d vertexGCS = target.VertexPosition(vertex);
value.Add(vertexGCS.X);
value.Add(vertexGCS.Y);
value.Add(vertexGCS.Z);
// get the bulge and tangent
bulges.Add(vertex.Bulge);
@@ -160,31 +162,31 @@ public class Polyline2dToSpeckleConverter
if (isSpline)
{
SOG.Curve spline = _splineConverter.Convert(target.Spline);
SOG.Polyline displayValue = segmentValues.ConvertToSpecklePolyline(_settingsStore.Current.SpeckleUnits);
if (displayValue != null)
{
spline.displayValue = displayValue;
}
spline.displayValue = _doublesConverter.Convert(segmentValues);
segments.Add(spline);
}
SOG.Vector normal = _vectorConverter.Convert(target.Normal);
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);
SOG.Vector normal = _vectorConverter.Convert(target.Normal); // wcs
// get the elevation transformed by ucs
double elevation = _referencePointConverter.ConvertOCSElevationDoubleToExternalCoordinates(
target.Elevation,
target.Normal
);
SOG.Autocad.AutocadPolycurve polycurve =
new()
{
segments = segments,
value = value,
value = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(value), // convert with reference point
bulges = bulges,
tangents = tangents,
normal = normal,
elevation = target.Elevation,
elevation = elevation,
polyType = polyType,
closed = target.Closed,
length = target.Length,
area = target.Area,
bbox = bbox,
units = _settingsStore.Current.SpeckleUnits
};
@@ -18,21 +18,21 @@ public class Polyline3dToSpeckleConverter
: IToSpeckleTopLevelConverter,
ITypedConverter<ADB.Polyline3d, SOG.Autocad.AutocadPolycurve>
{
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<List<double>, SOG.Polyline> _doublesConverter;
private readonly ITypedConverter<ADB.Spline, SOG.Curve> _splineConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public Polyline3dToSpeckleConverter(
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<List<double>, SOG.Polyline> doublesConverter,
ITypedConverter<ADB.Spline, SOG.Curve> splineConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_doublesConverter = doublesConverter;
_splineConverter = splineConverter;
_boxConverter = boxConverter;
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -56,7 +56,6 @@ public class Polyline3dToSpeckleConverter
}
// get all vertex data except control vertices
List<double> value = new();
List<ADB.PolylineVertex3d> vertices = target
.GetSubEntities<ADB.PolylineVertex3d>(
ADB.OpenMode.ForRead,
@@ -64,10 +63,13 @@ public class Polyline3dToSpeckleConverter
)
.Where(e => e.VertexType != ADB.Vertex3dType.FitVertex) // Do not collect fit vertex points, they are not used for creation
.ToList();
List<double> value = new(vertices.Count * 3);
for (int i = 0; i < vertices.Count; i++)
{
// vertex value is in the Global Coordinate System (GCS).
value.AddRange(vertices[i].Position.ToArray());
value.Add(vertices[i].Position.X);
value.Add(vertices[i].Position.Y);
value.Add(vertices[i].Position.Z);
}
List<Objects.ICurve> segments = new();
@@ -94,18 +96,15 @@ public class Polyline3dToSpeckleConverter
}
}
SOG.Polyline displayValue = segmentValues.ConvertToSpecklePolyline(_settingsStore.Current.SpeckleUnits);
if (displayValue != null)
{
spline.displayValue = displayValue;
}
// set displayValue of spline
spline.displayValue = _doublesConverter.Convert(segmentValues);
segments.Add(spline);
}
// for simple polyline3ds just get the polyline segment from the value
else
{
SOG.Polyline polyline = value.ConvertToSpecklePolyline(_settingsStore.Current.SpeckleUnits);
SOG.Polyline polyline = _doublesConverter.Convert(value);
if (target.Closed)
{
polyline.closed = true;
@@ -114,8 +113,6 @@ public class Polyline3dToSpeckleConverter
segments.Add(polyline);
}
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);
SOG.Autocad.AutocadPolycurve polycurve =
new()
{
@@ -123,11 +120,10 @@ public class Polyline3dToSpeckleConverter
bulges = null,
tangents = null,
normal = null,
value = value,
value = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(value), // convert with reference point
polyType = polyType,
closed = target.Closed,
length = target.Length,
bbox = bbox,
units = _settingsStore.Current.SpeckleUnits
};
@@ -17,22 +17,23 @@ public class PolylineToSpeckleConverter
{
private readonly ITypedConverter<AG.LineSegment3d, SOG.Line> _lineConverter;
private readonly ITypedConverter<AG.CircularArc3d, SOG.Arc> _arcConverter;
private readonly ITypedConverter<AG.Vector3d, SOG.Vector> _vectorConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public PolylineToSpeckleConverter(
ITypedConverter<AG.LineSegment3d, SOG.Line> lineConverter,
ITypedConverter<AG.CircularArc3d, SOG.Arc> arcConverter,
ITypedConverter<AG.Vector3d, SOG.Vector> vectorConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_lineConverter = lineConverter;
_arcConverter = arcConverter;
_vectorConverter = vectorConverter;
_boxConverter = boxConverter;
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -45,9 +46,11 @@ public class PolylineToSpeckleConverter
List<Objects.ICurve> segments = new();
for (int i = 0; i < target.NumberOfVertices; i++)
{
// get vertex value in the Object Coordinate System (OCS)
AG.Point2d vertex = target.GetPoint2dAt(i);
value.AddRange(vertex.ToArray());
// get vertex value in the World Coordinate System (WCS)
AG.Point3d vertex = target.GetPoint3dAt(i);
value.Add(vertex.X);
value.Add(vertex.Y);
value.Add(vertex.Z);
// get the bulge
bulges.Add(target.GetBulgeAt(i));
@@ -71,22 +74,26 @@ public class PolylineToSpeckleConverter
}
SOG.Vector normal = _vectorConverter.Convert(target.Normal);
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);
// get the elevation transformed by ucs
double elevation = _referencePointConverter.ConvertOCSElevationDoubleToExternalCoordinates(
target.Elevation,
target.Normal
);
SOG.Autocad.AutocadPolycurve polycurve =
new()
{
segments = segments,
value = value,
value = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(value), // convert with reference point
bulges = bulges,
normal = normal,
tangents = null,
elevation = target.Elevation,
elevation = elevation,
polyType = SOG.Autocad.AutocadPolyType.Light,
closed = target.Closed,
length = target.Length,
area = target.Area,
bbox = bbox,
units = _settingsStore.Current.SpeckleUnits
};
@@ -1,85 +1,20 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Sdk;
using Speckle.Sdk.Models;
namespace Speckle.Converters.Autocad.Geometry;
namespace Speckle.Converters.Autocad.ToSpeckle.Geometry;
[NameAndRankValue(typeof(ADB.SubDMesh), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK)]
public class DBSubDMeshToSpeckleConverter : IToSpeckleTopLevelConverter
public class SubDMeshToSpeckleConverter : IToSpeckleTopLevelConverter
{
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
private readonly ITypedConverter<ADB.SubDMesh, SOG.Mesh> _subDMeshConverter;
public DBSubDMeshToSpeckleConverter(IConverterSettingsStore<AutocadConversionSettings> settingsStore)
public SubDMeshToSpeckleConverter(ITypedConverter<ADB.SubDMesh, SOG.Mesh> subDMeshConverter)
{
_settingsStore = settingsStore;
_subDMeshConverter = subDMeshConverter;
}
public Base Convert(object target) => RawConvert((ADB.SubDMesh)target);
public Base Convert(object target) => Convert((ADB.SubDMesh)target);
public SOG.Mesh RawConvert(ADB.SubDMesh target)
{
//vertices
var vertices = new List<double>(target.Vertices.Count * 3);
foreach (AG.Point3d vert in target.Vertices)
{
vertices.Add(vert.X);
vertices.Add(vert.Y);
vertices.Add(vert.Z);
}
// faces
var faces = new List<int>();
int[] faceArr = target.FaceArray.ToArray(); // contains vertex indices
int edgeCount = 0;
for (int i = 0; i < faceArr.Length; i = i + edgeCount + 1)
{
List<int> faceVertices = new();
edgeCount = faceArr[i];
for (int j = i + 1; j <= i + edgeCount; j++)
{
faceVertices.Add(faceArr[j]);
}
if (edgeCount == 4) // quad face
{
faces.AddRange(new List<int> { 4, faceVertices[0], faceVertices[1], faceVertices[2], faceVertices[3] });
}
else // triangle face
{
faces.AddRange(new List<int> { 3, faceVertices[0], faceVertices[1], faceVertices[2] });
}
}
// colors
var colors = target
.VertexColorArray.Select(o =>
System
.Drawing.Color.FromArgb(
System.Convert.ToInt32(o.Red),
System.Convert.ToInt32(o.Green),
System.Convert.ToInt32(o.Blue)
)
.ToArgb()
)
.ToList();
SOG.Mesh speckleMesh =
new()
{
vertices = vertices,
faces = faces,
colors = colors,
units = _settingsStore.Current.SpeckleUnits,
area = target.ComputeSurfaceArea()
};
try
{
speckleMesh.volume = target.ComputeVolume();
}
catch (Exception e) when (!e.IsFatal()) { } // for non-volumetric meshes
return speckleMesh;
}
public SOG.Mesh Convert(ADB.SubDMesh target) => _subDMeshConverter.Convert(target);
}
@@ -7,10 +7,15 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class BrepToSpeckleRawConverter : ITypedConverter<ABR.Brep, SOG.Mesh>
{
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public BrepToSpeckleRawConverter(IConverterSettingsStore<AutocadConversionSettings> settingsStore)
public BrepToSpeckleRawConverter(
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -65,7 +70,7 @@ public class BrepToSpeckleRawConverter : ITypedConverter<ABR.Brep, SOG.Mesh>
new()
{
faces = faces,
vertices = vertices,
vertices = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(vertices), // transform by reference point
units = _settingsStore.Current.SpeckleUnits,
area = target.GetSurfaceArea()
};
@@ -5,14 +5,17 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class CircularArc2dToSpeckleRawConverter : ITypedConverter<AG.CircularArc2d, SOG.Arc>
{
private readonly ITypedConverter<AG.Point2d, SOG.Point> _pointConverter;
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public CircularArc2dToSpeckleRawConverter(
ITypedConverter<AG.Point2d, SOG.Point> pointConverter,
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_planeConverter = planeConverter;
_settingsStore = settingsStore;
}
@@ -35,27 +38,9 @@ public class CircularArc2dToSpeckleRawConverter : ITypedConverter<AG.CircularArc
var arc = new SOG.Arc()
{
plane = _planeConverter.Convert(plane),
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
},
startPoint = _pointConverter.Convert(target.StartPoint),
endPoint = _pointConverter.Convert(target.EndPoint),
midPoint = _pointConverter.Convert(midPoint),
domain = new SOP.Interval { start = startParam, end = endParam },
units = units
};
@@ -8,19 +8,16 @@ public class DBArcToSpeckleRawConverter : ITypedConverter<ADB.Arc, SOG.Arc>
{
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBArcToSpeckleRawConverter(
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_planeConverter = planeConverter;
_boxConverter = boxConverter;
_settingsStore = settingsStore;
}
@@ -33,7 +30,6 @@ public class DBArcToSpeckleRawConverter : ITypedConverter<ADB.Arc, SOG.Arc>
SOG.Point end = _pointConverter.Convert(target.EndPoint);
SOG.Point mid = _pointConverter.Convert(target.GetPointAtDist(target.Length / 2.0));
SOP.Interval domain = new() { start = target.StartParam, end = target.EndParam };
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);
SOG.Arc arc =
new()
@@ -43,7 +39,6 @@ public class DBArcToSpeckleRawConverter : ITypedConverter<ADB.Arc, SOG.Arc>
endPoint = end,
midPoint = mid,
domain = domain,
bbox = bbox,
units = _settingsStore.Current.SpeckleUnits
};
@@ -7,17 +7,14 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class DBCircleToSpeckleRawConverter : ITypedConverter<ADB.Circle, SOG.Circle>
{
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBCircleToSpeckleRawConverter(
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_planeConverter = planeConverter;
_boxConverter = boxConverter;
_settingsStore = settingsStore;
}
@@ -26,14 +23,12 @@ public class DBCircleToSpeckleRawConverter : ITypedConverter<ADB.Circle, SOG.Cir
public SOG.Circle Convert(ADB.Circle target)
{
SOG.Plane plane = _planeConverter.Convert(target.GetPlane());
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);
SOG.Circle circle =
new()
{
plane = plane,
radius = target.Radius,
units = _settingsStore.Current.SpeckleUnits,
bbox = bbox
units = _settingsStore.Current.SpeckleUnits
};
return circle;
@@ -1,4 +1,3 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Sdk.Models;
@@ -15,7 +14,6 @@ public class DBCurveToSpeckleRawConverter : ITypedConverter<ADB.Curve, Objects.I
private readonly ITypedConverter<ADB.Circle, SOG.Circle> _circleConverter;
private readonly ITypedConverter<ADB.Ellipse, SOG.Ellipse> _ellipseConverter;
private readonly ITypedConverter<ADB.Spline, SOG.Curve> _splineConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBCurveToSpeckleRawConverter(
ITypedConverter<ADB.Line, SOG.Line> lineConverter,
@@ -25,8 +23,7 @@ public class DBCurveToSpeckleRawConverter : ITypedConverter<ADB.Curve, Objects.I
ITypedConverter<ADB.Arc, SOG.Arc> arcConverter,
ITypedConverter<ADB.Circle, SOG.Circle> circleConverter,
ITypedConverter<ADB.Ellipse, SOG.Ellipse> ellipseConverter,
ITypedConverter<ADB.Spline, SOG.Curve> splineConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
ITypedConverter<ADB.Spline, SOG.Curve> splineConverter
)
{
_lineConverter = lineConverter;
@@ -37,7 +34,6 @@ public class DBCurveToSpeckleRawConverter : ITypedConverter<ADB.Curve, Objects.I
_circleConverter = circleConverter;
_ellipseConverter = ellipseConverter;
_splineConverter = splineConverter;
_settingsStore = settingsStore;
}
/// <summary>
@@ -6,18 +6,18 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class DBEllipseToSpeckleRawConverter : ITypedConverter<ADB.Ellipse, SOG.Ellipse>
{
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<AG.Vector3d, SOG.Vector> _vectorConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBEllipseToSpeckleRawConverter(
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<AG.Vector3d, SOG.Vector> vectorConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_planeConverter = planeConverter;
_boxConverter = boxConverter;
_pointConverter = pointConverter;
_vectorConverter = vectorConverter;
_settingsStore = settingsStore;
}
@@ -25,8 +25,15 @@ public class DBEllipseToSpeckleRawConverter : ITypedConverter<ADB.Ellipse, SOG.E
public SOG.Ellipse Convert(ADB.Ellipse target)
{
SOG.Plane plane = _planeConverter.Convert(new AG.Plane(target.Center, target.MajorAxis, target.MinorAxis));
SOG.Box bbox = _boxConverter.Convert(target.GeometricExtents);
SOG.Plane plane =
new()
{
origin = _pointConverter.Convert(target.Center),
normal = _vectorConverter.Convert(target.Normal),
xdir = _vectorConverter.Convert(target.MajorAxis),
ydir = _vectorConverter.Convert(target.MinorAxis),
units = _settingsStore.Current.SpeckleUnits
};
// the start and end param corresponds to start and end angle in radians
SOP.Interval trim = new() { start = target.StartAngle, end = target.EndAngle };
@@ -37,11 +44,10 @@ public class DBEllipseToSpeckleRawConverter : ITypedConverter<ADB.Ellipse, SOG.E
plane = plane,
firstRadius = target.MajorRadius,
secondRadius = target.MinorRadius,
units = _settingsStore.Current.SpeckleUnits,
domain = new SOP.Interval { start = 0, end = Math.PI * 2 },
trimDomain = trim,
length = target.GetDistanceAtParameter(target.EndParam),
bbox = bbox
units = _settingsStore.Current.SpeckleUnits
};
return ellipse;
@@ -7,17 +7,14 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class DBLineToSpeckleRawConverter : ITypedConverter<ADB.Line, SOG.Line>
{
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBLineToSpeckleRawConverter(
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_boxConverter = boxConverter;
_settingsStore = settingsStore;
}
@@ -28,8 +25,7 @@ public class DBLineToSpeckleRawConverter : ITypedConverter<ADB.Line, SOG.Line>
{
start = _pointConverter.Convert(target.StartPoint),
end = _pointConverter.Convert(target.EndPoint),
units = _settingsStore.Current.SpeckleUnits,
domain = new SOP.Interval { start = 0, end = target.Length },
bbox = _boxConverter.Convert(target.GeometricExtents)
units = _settingsStore.Current.SpeckleUnits
};
}
@@ -8,18 +8,21 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class DBSplineToSpeckleRawConverter : ITypedConverter<ADB.Spline, SOG.Curve>
{
private readonly ITypedConverter<List<double>, SOG.Polyline> _doublesConverter;
private readonly ITypedConverter<AG.Interval, SOP.Interval> _intervalConverter;
private readonly ITypedConverter<ADB.Extents3d, SOG.Box> _boxConverter;
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBSplineToSpeckleRawConverter(
ITypedConverter<List<double>, SOG.Polyline> doublesConverter,
ITypedConverter<AG.Interval, SOP.Interval> intervalConverter,
ITypedConverter<ADB.Extents3d, SOG.Box> boxConverter,
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_doublesConverter = doublesConverter;
_intervalConverter = intervalConverter;
_boxConverter = boxConverter;
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -44,11 +47,11 @@ public class DBSplineToSpeckleRawConverter : ITypedConverter<ADB.Spline, SOG.Cur
}
}
// get points
// get points, transformed by reference point setting
List<Point3d> points = new();
foreach (Point3d point in data.GetControlPoints().OfType<Point3d>())
{
points.Add(point);
points.Add(_referencePointConverter.ConvertWCSPointToExternalCoordinates(point));
}
// NOTE: for closed periodic splines, autocad does not track last #degree points.
@@ -108,7 +111,6 @@ public class DBSplineToSpeckleRawConverter : ITypedConverter<ADB.Spline, SOG.Cur
closed = periodicClosed || target.Closed,
length = length,
domain = domain,
bbox = _boxConverter.Convert(target.GeometricExtents),
units = _settingsStore.Current.SpeckleUnits,
displayValue = target.Database is not null ? GetDisplayValue(target) : null!, //TODO change?
};
@@ -147,6 +149,6 @@ public class DBSplineToSpeckleRawConverter : ITypedConverter<ADB.Spline, SOG.Cur
break;
}
return verticesList.ConvertToSpecklePolyline(_settingsStore.Current.SpeckleUnits);
return _doublesConverter.Convert(verticesList);
}
}
@@ -0,0 +1,86 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Sdk;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class DBSubDMeshToSpeckleRawConverter : ITypedConverter<ADB.SubDMesh, SOG.Mesh>
{
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBSubDMeshToSpeckleRawConverter(
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
public SOG.Mesh Convert(ADB.SubDMesh target)
{
// vertices
List<double> vertices = new(target.Vertices.Count * 3);
foreach (AG.Point3d vert in target.Vertices)
{
vertices.Add(vert.X);
vertices.Add(vert.Y);
vertices.Add(vert.Z);
}
// faces
List<int> faces = new();
int[] faceArr = target.FaceArray.ToArray(); // contains vertex indices
int edgeCount = 0;
for (int i = 0; i < faceArr.Length; i = i + edgeCount + 1)
{
List<int> faceVertices = new();
edgeCount = faceArr[i];
for (int j = i + 1; j <= i + edgeCount; j++)
{
faceVertices.Add(faceArr[j]);
}
if (edgeCount == 4) // quad face
{
faces.AddRange(new List<int> { 4, faceVertices[0], faceVertices[1], faceVertices[2], faceVertices[3] });
}
else // triangle face
{
faces.AddRange(new List<int> { 3, faceVertices[0], faceVertices[1], faceVertices[2] });
}
}
// colors
var colors = target
.VertexColorArray.Select(o =>
System
.Drawing.Color.FromArgb(
System.Convert.ToInt32(o.Red),
System.Convert.ToInt32(o.Green),
System.Convert.ToInt32(o.Blue)
)
.ToArgb()
)
.ToList();
SOG.Mesh speckleMesh =
new()
{
vertices = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(vertices), // transform with reference point
faces = faces,
colors = colors,
units = _settingsStore.Current.SpeckleUnits,
area = target.ComputeSurfaceArea()
};
try
{
speckleMesh.volume = target.ComputeVolume();
}
catch (Exception e) when (!e.IsFatal()) { } // for non-volumetric meshes
return speckleMesh;
}
}
@@ -1,3 +1,4 @@
using Speckle.Converters.Autocad.Helpers;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Objects.Annotation;
@@ -7,17 +8,17 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class DBTextToSpeckleRawConverter : ITypedConverter<ADB.DBText, Text>
{
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly ITypedConverter<AG.Vector3d, SOG.Vector> _vectorConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DBTextToSpeckleRawConverter(
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
ITypedConverter<AG.Vector3d, SOG.Vector> vectorConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_planeConverter = planeConverter;
_vectorConverter = vectorConverter;
_settingsStore = settingsStore;
}
@@ -41,15 +42,24 @@ public class DBTextToSpeckleRawConverter : ITypedConverter<ADB.DBText, Text>
units = _settingsStore.Current.SpeckleUnits
};
// For DBText, the following properties are stored in:
// - Position: WCS
// - Normal: WCS
// - Rotation: OCS -> WCS https://help.autodesk.com/view/OARX/2020/ENU/?guid=OARX-ManagedRefGuide-Autodesk_AutoCAD_DatabaseServices_DBText_Rotation
private SOG.Plane GetTextPlane(ADB.DBText target)
{
AG.Plane plane = new(target.Position, target.Normal);
// Rotation prop is in OCS: calculate the x and y axis based in WCS
AG.Matrix3d transform = TransformHelper.GetTransformFromOCSToWCS(target.Normal).Inverse();
AG.Vector3d xDir = AG.Vector3d.XAxis.RotateBy(target.Rotation, target.Normal).TransformBy(transform);
AG.Vector3d yDir = AG.Vector3d.YAxis.RotateBy(target.Rotation, target.Normal).TransformBy(transform);
if (target.Rotation != 0)
return new()
{
plane.RotateBy(target.Rotation, target.Normal, target.Position);
}
return _planeConverter.Convert(plane);
origin = _pointConverter.Convert(target.Position),
normal = _vectorConverter.Convert(target.Normal),
xdir = _vectorConverter.Convert(xDir),
ydir = _vectorConverter.Convert(yDir),
units = _settingsStore.Current.SpeckleUnits,
};
}
}
@@ -0,0 +1,32 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class DoublesToSpeckleRawConverter : ITypedConverter<List<double>, SOG.Polyline>
{
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public DoublesToSpeckleRawConverter(
IConverterSettingsStore<AutocadConversionSettings> settingsStore,
IReferencePointConverter referencePointConverter
)
{
_settingsStore = settingsStore;
_referencePointConverter = referencePointConverter;
}
public SOG.Polyline Convert(List<double> target)
{
// throw if list is malformed
if (target.Count % 3 != 0)
{
throw new ArgumentException("Point list of xyz values is malformed", nameof(target));
}
List<double> value = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(target);
return new() { value = value, units = _settingsStore.Current.SpeckleUnits };
}
}
@@ -6,17 +6,17 @@ namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class MTextToSpeckleRawConverter : ITypedConverter<ADB.MText, SA.Text>
{
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly ITypedConverter<AG.Vector3d, SOG.Vector> _vectorConverter;
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public MTextToSpeckleRawConverter(
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
ITypedConverter<AG.Vector3d, SOG.Vector> vectorConverter,
IConverterSettingsStore<AutocadConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_planeConverter = planeConverter;
_vectorConverter = vectorConverter;
_settingsStore = settingsStore;
}
@@ -38,16 +38,28 @@ public class MTextToSpeckleRawConverter : ITypedConverter<ADB.MText, SA.Text>
units = _settingsStore.Current.SpeckleUnits
};
// For MText, the following properties are stored in:
// - Position: WCS
// - Normal: WCS??
// - Rotation: OCS -> UCS?? https://help.autodesk.com/view/OARX/2020/ENU/?guid=OARX-ManagedRefGuide-Autodesk_AutoCAD_DatabaseServices_MText_Rotation
// "Accesses the angle between the X axis of the OCS for the normal vector of the current AutoCAD editor's UCS
// and the projection of the MText object's direction vector onto the plane of the AutoCAD editor's current UCS."
// - Direction: WCS
// "Note that the direction vector need not be orthogonal to the normal vector." <- do not use FML
private SOG.Plane GetTextPlane(ADB.MText target)
{
AG.Plane plane = new(target.Location, target.Normal);
// Rotation prop is in UCS already: do NOT use vector converter or it will transform again!
AG.Vector3d xDir = AG.Vector3d.XAxis.RotateBy(target.Rotation, target.Normal);
AG.Vector3d yDir = AG.Vector3d.YAxis.RotateBy(target.Rotation, target.Normal);
if (target.Rotation != 0)
return new()
{
plane.RotateBy(target.Rotation, target.Normal, target.Location);
}
return _planeConverter.Convert(plane);
origin = _pointConverter.Convert(target.Location),
normal = _vectorConverter.Convert(target.Normal),
xdir = new(xDir.X, xDir.Y, xDir.Z, _settingsStore.Current.SpeckleUnits),
ydir = new(yDir.X, yDir.Y, yDir.Z, _settingsStore.Current.SpeckleUnits),
units = _settingsStore.Current.SpeckleUnits,
};
}
/// <summary>
@@ -23,13 +23,16 @@ public class PlaneToSpeckleRawConverter : ITypedConverter<AG.Plane, SOG.Plane>
public Base Convert(object target) => Convert((AG.Plane)target);
public SOG.Plane Convert(AG.Plane target) =>
new()
public SOG.Plane Convert(AG.Plane target)
{
AG.CoordinateSystem3d cs = target.GetCoordinateSystem(); // TODO: validate if this returns the coordinate system in GCS or already transformed
return new()
{
origin = _pointConverter.Convert(target.PointOnPlane),
normal = _vectorConverter.Convert(target.Normal),
xdir = _vectorConverter.Convert(target.GetCoordinateSystem().Xaxis),
ydir = _vectorConverter.Convert(target.GetCoordinateSystem().Yaxis),
xdir = _vectorConverter.Convert(cs.Xaxis),
ydir = _vectorConverter.Convert(cs.Yaxis),
units = _settingsStore.Current.SpeckleUnits,
};
}
}
@@ -0,0 +1,26 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class Point2dToSpeckleRawConverter : ITypedConverter<AG.Point2d, SOG.Point>
{
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
private readonly IReferencePointConverter _referencePointConverter;
public Point2dToSpeckleRawConverter(
IConverterSettingsStore<AutocadConversionSettings> settingsStore,
IReferencePointConverter referencePointConverter
)
{
_settingsStore = settingsStore;
_referencePointConverter = referencePointConverter;
}
public SOG.Point Convert(AG.Point2d target)
{
var extPt = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(new(3) { target.X, target.Y, 0 });
return new(extPt[0], extPt[1], extPt[2], _settingsStore.Current.SpeckleUnits);
}
}
@@ -0,0 +1,25 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class Point3dToSpeckleRawConverter : ITypedConverter<AG.Point3d, SOG.Point>
{
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
private readonly IReferencePointConverter _referencePointConverter;
public Point3dToSpeckleRawConverter(
IConverterSettingsStore<AutocadConversionSettings> settingsStore,
IReferencePointConverter referencePointConverter
)
{
_settingsStore = settingsStore;
_referencePointConverter = referencePointConverter;
}
public SOG.Point Convert(AG.Point3d target)
{
AG.Point3d extPt = _referencePointConverter.ConvertWCSPointToExternalCoordinates(target);
return new(extPt.X, extPt.Y, extPt.Z, _settingsStore.Current.SpeckleUnits);
}
}
@@ -1,16 +0,0 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class PointToSpeckleRawConverter : ITypedConverter<AG.Point3d, SOG.Point>
{
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public PointToSpeckleRawConverter(IConverterSettingsStore<AutocadConversionSettings> settingsStore)
{
_settingsStore = settingsStore;
}
public SOG.Point Convert(AG.Point3d target) => new(target.X, target.Y, target.Z, _settingsStore.Current.SpeckleUnits);
}
@@ -0,0 +1,25 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class Vector3dToSpeckleRawConverter : ITypedConverter<AG.Vector3d, SOG.Vector>
{
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
private readonly IReferencePointConverter _referencePointConverter;
public Vector3dToSpeckleRawConverter(
IConverterSettingsStore<AutocadConversionSettings> settingsStore,
IReferencePointConverter referencePointConverter
)
{
_settingsStore = settingsStore;
_referencePointConverter = referencePointConverter;
}
public SOG.Vector Convert(AG.Vector3d target)
{
AG.Vector3d extVector = _referencePointConverter.ConvertWCSVectorToExternalCoordinates(target);
return new(extVector.X, extVector.Y, extVector.Z, _settingsStore.Current.SpeckleUnits);
}
}
@@ -1,17 +0,0 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
public class VectorToSpeckleRawConverter : ITypedConverter<AG.Vector3d, SOG.Vector>
{
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
public VectorToSpeckleRawConverter(IConverterSettingsStore<AutocadConversionSettings> settingsStore)
{
_settingsStore = settingsStore;
}
public SOG.Vector Convert(AG.Vector3d target) =>
new(target.X, target.Y, target.Z, _settingsStore.Current.SpeckleUnits);
}
@@ -34,6 +34,7 @@ public static class ServiceRegistration
IConverterSettingsStore<AutocadConversionSettings>,
ConverterSettingsStore<AutocadConversionSettings>
>();
serviceCollection.AddScoped<IReferencePointConverter, ReferencePointConverter>();
// add other classes
serviceCollection.AddScoped<Speckle.Converters.Civil3dShared.ToSpeckle.PropertiesExtractor>(); // for civil
@@ -6,14 +6,17 @@ namespace Speckle.Converters.Civil3dShared.ToSpeckle.Raw;
public class AlignmentSubentityArcToSpeckleRawConverter : ITypedConverter<CDB.AlignmentSubEntityArc, SOG.Arc>
{
private readonly ITypedConverter<AG.Point2d, SOG.Point> _pointConverter;
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
private readonly IConverterSettingsStore<Civil3dConversionSettings> _settingsStore;
public AlignmentSubentityArcToSpeckleRawConverter(
ITypedConverter<AG.Point2d, SOG.Point> pointConverter,
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
IConverterSettingsStore<Civil3dConversionSettings> settingsStore
)
{
_pointConverter = pointConverter;
_planeConverter = planeConverter;
_settingsStore = settingsStore;
}
@@ -53,27 +56,9 @@ public class AlignmentSubentityArcToSpeckleRawConverter : ITypedConverter<CDB.Al
SOG.Arc arc =
new()
{
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 = midPointX,
y = midPointY,
z = 0,
units = units
},
startPoint = _pointConverter.Convert(target.StartPoint),
endPoint = _pointConverter.Convert(target.EndPoint),
midPoint = _pointConverter.Convert(new AG.Point2d(midPointX, midPointY)),
plane = _planeConverter.Convert(plane),
units = units
};
@@ -7,33 +7,23 @@ namespace Speckle.Converters.Civil3dShared.ToSpeckle.Raw;
public class AlignmentSubentityLineToSpeckleRawConverter : ITypedConverter<CDB.AlignmentSubEntityLine, SOG.Line>
{
private readonly IConverterSettingsStore<Civil3dConversionSettings> _settingsStore;
private readonly ITypedConverter<AG.Point2d, SOG.Point> _pointConverter;
public AlignmentSubentityLineToSpeckleRawConverter(IConverterSettingsStore<Civil3dConversionSettings> settingsStore)
public AlignmentSubentityLineToSpeckleRawConverter(
IConverterSettingsStore<Civil3dConversionSettings> settingsStore,
ITypedConverter<AG.Point2d, SOG.Point> pointConverter
)
{
_settingsStore = settingsStore;
_pointConverter = pointConverter;
}
public SOG.Line Convert(object target) => Convert((CDB.AlignmentSubEntityLine)target);
public SOG.Line Convert(CDB.AlignmentSubEntityLine target)
{
SOG.Point start =
new()
{
x = target.StartPoint.X,
y = target.StartPoint.Y,
z = 0,
units = _settingsStore.Current.SpeckleUnits
};
SOG.Point end =
new()
{
x = target.EndPoint.X,
y = target.EndPoint.Y,
z = 0,
units = _settingsStore.Current.SpeckleUnits
};
SOG.Point start = _pointConverter.Convert(target.StartPoint);
SOG.Point end = _pointConverter.Convert(target.EndPoint);
SOG.Line line =
new()
@@ -1,3 +1,4 @@
using Speckle.Converters.Autocad;
using Speckle.Converters.Civil3dShared.Helpers;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
@@ -7,10 +8,15 @@ namespace Speckle.Converters.Civil3dShared.ToSpeckle.Raw;
public class AlignmentSubentitySpiralToSpeckleRawConverter
: ITypedConverter<(CDB.AlignmentSubEntitySpiral, CDB.Alignment), SOG.Polyline>
{
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<Civil3dConversionSettings> _settingsStore;
public AlignmentSubentitySpiralToSpeckleRawConverter(IConverterSettingsStore<Civil3dConversionSettings> settingsStore)
public AlignmentSubentitySpiralToSpeckleRawConverter(
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<Civil3dConversionSettings> settingsStore
)
{
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -45,7 +51,7 @@ public class AlignmentSubentitySpiralToSpeckleRawConverter
SOG.Polyline polyline =
new()
{
value = polylineValue,
value = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(polylineValue), // convert by ref point transform
units = units,
closed = spiral.StartPoint == spiral.EndPoint
};
@@ -1,4 +1,4 @@
using Autodesk.AutoCAD.Geometry;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
@@ -6,10 +6,15 @@ namespace Speckle.Converters.Civil3dShared.ToSpeckle.Raw;
public class GridSurfaceToSpeckleMeshRawConverter : ITypedConverter<CDB.GridSurface, SOG.Mesh>
{
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<Civil3dConversionSettings> _settingsStore;
public GridSurfaceToSpeckleMeshRawConverter(IConverterSettingsStore<Civil3dConversionSettings> settingsStore)
public GridSurfaceToSpeckleMeshRawConverter(
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<Civil3dConversionSettings> settingsStore
)
{
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -19,14 +24,14 @@ public class GridSurfaceToSpeckleMeshRawConverter : ITypedConverter<CDB.GridSurf
{
List<double> vertices = new();
List<int> faces = new();
Dictionary<Point3d, int> indices = new();
Dictionary<AG.Point3d, int> indices = new();
int indexCounter = 0;
foreach (var cell in target.GetCells(false))
{
try
{
Point3d[] cellVertices =
AG.Point3d[] cellVertices =
{
cell.BottomLeftVertex.Location,
cell.BottomRightVertex.Location,
@@ -34,7 +39,7 @@ public class GridSurfaceToSpeckleMeshRawConverter : ITypedConverter<CDB.GridSurf
cell.TopRightVertex.Location
};
foreach (Point3d p in cellVertices)
foreach (AG.Point3d p in cellVertices)
{
if (indices.ContainsKey(p))
{
@@ -63,7 +68,7 @@ public class GridSurfaceToSpeckleMeshRawConverter : ITypedConverter<CDB.GridSurf
SOG.Mesh mesh =
new()
{
vertices = vertices,
vertices = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(vertices), // transform by reference point
faces = faces,
units = _settingsStore.Current.SpeckleUnits
};
@@ -1,3 +1,4 @@
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
@@ -5,10 +6,15 @@ namespace Speckle.Converters.Civil3dShared.ToSpeckle.Raw;
public class Point3dCollectionToSpeckleRawConverter : ITypedConverter<AG.Point3dCollection, SOG.Polyline>
{
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<Civil3dConversionSettings> _settingsStore;
public Point3dCollectionToSpeckleRawConverter(IConverterSettingsStore<Civil3dConversionSettings> settingsStore)
public Point3dCollectionToSpeckleRawConverter(
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<Civil3dConversionSettings> settingsStore
)
{
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -33,7 +39,7 @@ public class Point3dCollectionToSpeckleRawConverter : ITypedConverter<AG.Point3d
return new()
{
value = value,
value = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(value), // transform by reference point
units = _settingsStore.Current.SpeckleUnits,
closed = false,
length = length
@@ -1,4 +1,5 @@
using Autodesk.AutoCAD.Geometry;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
@@ -6,10 +7,15 @@ namespace Speckle.Converters.Civil3dShared.ToSpeckle.Raw;
public class TinSurfaceToSpeckleMeshRawConverter : ITypedConverter<CDB.TinSurface, SOG.Mesh>
{
private readonly IReferencePointConverter _referencePointConverter;
private readonly IConverterSettingsStore<Civil3dConversionSettings> _settingsStore;
public TinSurfaceToSpeckleMeshRawConverter(IConverterSettingsStore<Civil3dConversionSettings> settingsStore)
public TinSurfaceToSpeckleMeshRawConverter(
IReferencePointConverter referencePointConverter,
IConverterSettingsStore<Civil3dConversionSettings> settingsStore
)
{
_referencePointConverter = referencePointConverter;
_settingsStore = settingsStore;
}
@@ -60,7 +66,7 @@ public class TinSurfaceToSpeckleMeshRawConverter : ITypedConverter<CDB.TinSurfac
new()
{
faces = faces,
vertices = vertices,
vertices = _referencePointConverter.ConvertWCSDoublesToExternalCoordinates(vertices), // transform by reference point
units = _settingsStore.Current.SpeckleUnits
};
@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Connectors.Common.Instances;
@@ -8,6 +8,7 @@ public interface IInstanceObjectsManager<THostObjectType, TAppIdMapValueType>
void AddInstanceProxy(string objectId, InstanceProxy instanceProxy);
void AddDefinitionProxy(string objectId, InstanceDefinitionProxy instanceDefinitionProxy);
void AddAtomicObject(string objectId, THostObjectType obj);
void AddAtomicDefinitionObjectId(string objectId);
void AddInstanceProxiesByDefinitionId(string definitionId, List<InstanceProxy> instanceProxies);
UnpackResult<THostObjectType> GetUnpackResult();
bool TryGetInstanceProxiesFromDefinitionId(
@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using Speckle.Sdk.Models.Instances;
namespace Speckle.Connectors.Common.Instances;
@@ -10,6 +10,7 @@ public class InstanceObjectsManager<THostObjectType, TAppIdMapValueType>
private readonly Dictionary<string, List<InstanceProxy>> _instanceProxiesByDefinitionId = new();
private readonly Dictionary<string, InstanceDefinitionProxy> _definitionProxies = new();
private readonly Dictionary<string, THostObjectType> _flatAtomicObjects = new();
private readonly HashSet<string> _flatAtomicDefinitionObjectIds = new();
public void AddInstanceProxy(string objectId, InstanceProxy instanceProxy) =>
_instanceProxies[objectId] = instanceProxy;
@@ -19,11 +20,13 @@ public class InstanceObjectsManager<THostObjectType, TAppIdMapValueType>
public void AddAtomicObject(string objectId, THostObjectType obj) => _flatAtomicObjects[objectId] = obj;
public void AddAtomicDefinitionObjectId(string objectId) => _flatAtomicDefinitionObjectIds.Add(objectId);
public void AddInstanceProxiesByDefinitionId(string definitionId, List<InstanceProxy> instanceProxies) =>
_instanceProxiesByDefinitionId[definitionId] = instanceProxies;
public UnpackResult<THostObjectType> GetUnpackResult() =>
new(GetAtomicObjects(), GetInstanceProxies(), GetDefinitionProxies());
new(GetAtomicObjects(), GetAtomicDefinitionObjectIds(), GetInstanceProxies(), GetDefinitionProxies());
public bool TryGetInstanceProxiesFromDefinitionId(
string definitionId,
@@ -58,6 +61,8 @@ public class InstanceObjectsManager<THostObjectType, TAppIdMapValueType>
private List<THostObjectType> GetAtomicObjects() => _flatAtomicObjects.Values.ToList();
private HashSet<string> GetAtomicDefinitionObjectIds() => _flatAtomicDefinitionObjectIds;
private List<InstanceDefinitionProxy> GetDefinitionProxies() => _definitionProxies.Values.ToList();
private Dictionary<string, InstanceProxy> GetInstanceProxies() => _instanceProxies;
@@ -4,6 +4,7 @@ namespace Speckle.Connectors.Common.Instances;
public record UnpackResult<T>(
List<T> AtomicObjects,
HashSet<string> AtomicDefinitionObjectIds,
Dictionary<string, InstanceProxy> InstanceProxies,
List<InstanceDefinitionProxy> InstanceDefinitionProxies
);