@@ -126,10 +126,9 @@ public class RevitMaterialBaker
|
||||
string materialId = speckleRenderMaterial.applicationId ?? speckleRenderMaterial.id.NotNull();
|
||||
string matName = _revitUtils.RemoveInvalidChars($"{speckleRenderMaterial.name}-({materialId})-{baseLayerName}");
|
||||
|
||||
var newMaterialId = Autodesk.Revit.DB.Material.Create(_converterSettings.Current.Document, matName);
|
||||
var revitMaterial = (Autodesk.Revit.DB.Material)_converterSettings.Current.Document.GetElement(newMaterialId);
|
||||
var newMaterialId = Material.Create(_converterSettings.Current.Document, matName);
|
||||
var revitMaterial = (Material)_converterSettings.Current.Document.GetElement(newMaterialId);
|
||||
revitMaterial.Color = new Color(diffuse.R, diffuse.G, diffuse.B);
|
||||
|
||||
revitMaterial.Transparency = (int)(transparency * 100);
|
||||
revitMaterial.Shininess = (int)(speckleRenderMaterial.metalness * 128);
|
||||
revitMaterial.Smoothness = (int)(smoothness * 128);
|
||||
@@ -156,7 +155,7 @@ public class RevitMaterialBaker
|
||||
using (var collector = new FilteredElementCollector(document))
|
||||
{
|
||||
var materialIds = collector
|
||||
.OfClass(typeof(Autodesk.Revit.DB.Material))
|
||||
.OfClass(typeof(Material))
|
||||
.Where(m => m.Name.Contains(validBaseGroupName))
|
||||
.Select(m => m.Id)
|
||||
.ToList();
|
||||
|
||||
+62
-30
@@ -101,7 +101,68 @@ public sealed class RevitHostObjectBuilder(
|
||||
unpackedRoot.ObjectsToConvert.ToList()
|
||||
);
|
||||
|
||||
// 2 - Bake materials
|
||||
// NOTE: below is 💩... https://github.com/specklesystems/speckle-sharp-connectors/pull/813 broke sketchup to revit workflow
|
||||
// ids were modified to fix receiving instances [CNX-1707](https://linear.app/speckle/issue/CNX-1707/revit-curves-and-meshes-in-blocks-come-as-duplicated)
|
||||
// but we then broke sketchup to revit because applicationIds in proxies didn't match modified application ids which cam from #813 hack
|
||||
// given urgency to get sketchup to revit workflow back up and running, temp fix involves setting modified ids before material baking, mapping original app ids to modified ids and using those
|
||||
// this way, CNX-1707 fix stays in tact and we fix sketchup to revit
|
||||
// TODO: TransformTo and material baking needs to be fixed in Revit!!
|
||||
|
||||
// create a mapping from original to modified IDs <- so that we can actually map ids in the proxies to the objects
|
||||
Dictionary<string, string> originalToModifiedIds = new();
|
||||
|
||||
// modify application IDs BEFORE material baking
|
||||
foreach (LocalToGlobalMap localToGlobalMap in localToGlobalMaps)
|
||||
{
|
||||
if (
|
||||
localToGlobalMap.AtomicObject is ITransformable transformable
|
||||
&& localToGlobalMap.Matrix.Count > 0
|
||||
&& localToGlobalMap.AtomicObject["units"] is string units
|
||||
)
|
||||
{
|
||||
var id = localToGlobalMap.AtomicObject.id;
|
||||
var originalAppId = localToGlobalMap.AtomicObject.applicationId ?? id;
|
||||
|
||||
// Apply transformations...
|
||||
ITransformable? newTransformable = null;
|
||||
foreach (var mat in localToGlobalMap.Matrix)
|
||||
{
|
||||
transformable.TransformTo(new Transform() { matrix = mat, units = units }, out newTransformable);
|
||||
transformable = newTransformable;
|
||||
}
|
||||
|
||||
localToGlobalMap.AtomicObject = (newTransformable as Base)!;
|
||||
localToGlobalMap.AtomicObject.id = id;
|
||||
|
||||
// create modified ID and store mapping <- fixes CNX-1707 but causes us material mapping headache!!!
|
||||
string modifiedAppId = $"{originalAppId}_{Guid.NewGuid().ToString("N")[..8]}";
|
||||
if (originalAppId != null)
|
||||
{
|
||||
originalToModifiedIds[originalAppId] = modifiedAppId;
|
||||
}
|
||||
|
||||
localToGlobalMap.AtomicObject.applicationId = modifiedAppId;
|
||||
localToGlobalMap.Matrix = new HashSet<Matrix4x4>();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the RenderMaterialProxies with the "new" (aka hacked) application IDs
|
||||
if (unpackedRoot.RenderMaterialProxies != null)
|
||||
{
|
||||
foreach (var proxy in unpackedRoot.RenderMaterialProxies)
|
||||
{
|
||||
var updatedObjects = new List<string>();
|
||||
foreach (var objectId in proxy.objects)
|
||||
{
|
||||
// Use the modified ID if it exists, otherwise keep the original <- this SUCKS and we need to change
|
||||
string idToUse = originalToModifiedIds.TryGetValue(objectId, out var modifiedId) ? modifiedId : objectId;
|
||||
updatedObjects.Add(idToUse);
|
||||
}
|
||||
proxy.objects = updatedObjects;
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - Bake materials (now with the updated IDs)
|
||||
if (unpackedRoot.RenderMaterialProxies != null)
|
||||
{
|
||||
transactionManager.StartTransaction(true, "Baking materials");
|
||||
@@ -178,35 +239,6 @@ public sealed class RevitHostObjectBuilder(
|
||||
{
|
||||
using var activity = activityFactory.Start("BakeObject");
|
||||
|
||||
// POC hack of the ages: try to pre transform curves, points and meshes before baking
|
||||
// we need to bypass the local to global converter as there we don't have access to what we want. that service will/should stop existing.
|
||||
if (
|
||||
localToGlobalMap.AtomicObject is ITransformable transformable // and ICurve
|
||||
&& localToGlobalMap.Matrix.Count > 0
|
||||
&& localToGlobalMap.AtomicObject["units"] is string units
|
||||
)
|
||||
{
|
||||
//TODO TransformTo will be deprecated as it's dangerous and requires ID transposing which is wrong!
|
||||
//ID needs to be copied to the new instance
|
||||
var id = localToGlobalMap.AtomicObject.id;
|
||||
var originalAppId = localToGlobalMap.AtomicObject.applicationId;
|
||||
|
||||
ITransformable? newTransformable = null;
|
||||
foreach (var mat in localToGlobalMap.Matrix)
|
||||
{
|
||||
transformable.TransformTo(new Transform() { matrix = mat, units = units }, out newTransformable);
|
||||
transformable = newTransformable;
|
||||
}
|
||||
|
||||
localToGlobalMap.AtomicObject = (newTransformable as Base)!;
|
||||
localToGlobalMap.AtomicObject.id = id;
|
||||
|
||||
// Make applicationId unique by appending a short GUID
|
||||
// This prevents DirectShapeLibrary from using the same definition for multiple instances
|
||||
localToGlobalMap.AtomicObject.applicationId = $"{originalAppId ?? id}_{Guid.NewGuid().ToString("N")[..8]}"; // hack of all of the ages. related to CNX-1707
|
||||
localToGlobalMap.Matrix = new HashSet<Matrix4x4>(); // flush out the list, as we've applied the transforms already
|
||||
}
|
||||
|
||||
// actual conversion happens here!
|
||||
var result = converter.Convert(localToGlobalMap.AtomicObject);
|
||||
onOperationProgressed.Report(new("Converting", (double)++count / localToGlobalMaps.Count));
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+9
-1
@@ -31,7 +31,7 @@ public class DeconstructSpeckleParam : GH_Component, IGH_VariableParameterCompon
|
||||
pManager.AddGenericParameter(
|
||||
"Speckle Param",
|
||||
"SP",
|
||||
"Speckle param to deconstruct. Expects Collections, Objects, or Materials",
|
||||
"Speckle param to deconstruct. Expects Collections, Objects, Materials, or Properties",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
}
|
||||
@@ -61,6 +61,14 @@ public class DeconstructSpeckleParam : GH_Component, IGH_VariableParameterCompon
|
||||
Name = string.IsNullOrEmpty(matGoo.Value.Name) ? matGoo.Value.Material.speckle_type : matGoo.Value.Name;
|
||||
outputParams = CreateOutputParamsFromBase(matGoo.Value.Base);
|
||||
break;
|
||||
case SpecklePropertyGroupGoo propGoo:
|
||||
Name = $"properties ({propGoo.Value.Count})";
|
||||
outputParams = new();
|
||||
foreach (var key in propGoo.Value.Keys)
|
||||
{
|
||||
outputParams.Add(CreateOutputParamByKeyValue(key, propGoo.Value[key].Value, GH_ParamAccess.item));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
+13
-3
@@ -28,12 +28,17 @@ public class CreateSpeckleObject : GH_Component
|
||||
pManager.AddGenericParameter(
|
||||
"Object",
|
||||
"O",
|
||||
"Input Object. Speckle objects, Model Objects, and geometry are accepted.",
|
||||
"Input Object. Speckle Objects, Model Objects, and geometry are accepted.",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
Params.Input[0].Optional = true;
|
||||
|
||||
pManager.AddGenericParameter("Geometry", "G", "The geometry of the Speckle Object", GH_ParamAccess.item);
|
||||
pManager.AddGenericParameter(
|
||||
"Geometry",
|
||||
"G",
|
||||
"Geometry of the Speckle Object. GeometryBase in Grasshopper includes text entities.",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
Params.Input[1].Optional = true;
|
||||
|
||||
pManager.AddTextParameter("Name", "N", "Name of the Speckle Object", GH_ParamAccess.item);
|
||||
@@ -73,7 +78,12 @@ public class CreateSpeckleObject : GH_Component
|
||||
{
|
||||
pManager.AddParameter(new SpeckleObjectParam(), "Object", "O", "Speckle Object", GH_ParamAccess.item);
|
||||
|
||||
pManager.AddGenericParameter("Geometry", "G", "The geometry of the Speckle Object", GH_ParamAccess.item);
|
||||
pManager.AddGenericParameter(
|
||||
"Geometry",
|
||||
"G",
|
||||
"Geometry of the Speckle Object. GeometryBase in Grasshopper includes text entities.",
|
||||
GH_ParamAccess.item
|
||||
);
|
||||
|
||||
pManager.AddTextParameter("Name", "N", "Name of the Speckle Object", GH_ParamAccess.item);
|
||||
|
||||
|
||||
+44
-3
@@ -23,6 +23,8 @@ public class CreateSpeckleProperties : GH_Component, IGH_VariableParameterCompon
|
||||
|
||||
protected override Bitmap Icon => Resources.speckle_properties_create;
|
||||
|
||||
public bool CreateEmptyProperties { get; set; }
|
||||
|
||||
private readonly DebounceDispatcher _debounceDispatcher = new();
|
||||
|
||||
protected override void RegisterInputParams(GH_InputParamManager pManager)
|
||||
@@ -39,7 +41,6 @@ public class CreateSpeckleProperties : GH_Component, IGH_VariableParameterCompon
|
||||
protected override void SolveInstance(IGH_DataAccess da)
|
||||
{
|
||||
// Create a data tree to store output
|
||||
|
||||
Dictionary<string, object?> properties = new();
|
||||
|
||||
// Check for structure of all inputs to see matching branches
|
||||
@@ -60,8 +61,18 @@ public class CreateSpeckleProperties : GH_Component, IGH_VariableParameterCompon
|
||||
{
|
||||
object? value = null;
|
||||
var success = da.GetData(i, ref value);
|
||||
if (!success)
|
||||
{
|
||||
AddRuntimeMessage(
|
||||
GH_RuntimeMessageLevel.Warning,
|
||||
$"Parameter {Params.Input[i].NickName} does not have any values."
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var actualValue = value?.GetType().GetProperty("Value").GetValue(value); // note: unsure if reflection here hurts our performance
|
||||
if (!success || value == null || actualValue == null)
|
||||
if (value == null || actualValue == null)
|
||||
{
|
||||
AddRuntimeMessage(
|
||||
GH_RuntimeMessageLevel.Warning,
|
||||
@@ -80,7 +91,7 @@ public class CreateSpeckleProperties : GH_Component, IGH_VariableParameterCompon
|
||||
|
||||
public bool CanInsertParameter(GH_ParameterSide side, int index)
|
||||
{
|
||||
return side == GH_ParameterSide.Input;
|
||||
return side == GH_ParameterSide.Input && !CreateEmptyProperties;
|
||||
}
|
||||
|
||||
public bool CanRemoveParameter(GH_ParameterSide side, int index)
|
||||
@@ -137,4 +148,34 @@ public class CreateSpeckleProperties : GH_Component, IGH_VariableParameterCompon
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override void AppendAdditionalMenuItems(ToolStripDropDown menu)
|
||||
{
|
||||
base.AppendAdditionalMenuItems(menu);
|
||||
|
||||
Menu_AppendSeparator(menu);
|
||||
ToolStripMenuItem emptyPropsMenuItem = Menu_AppendItem(
|
||||
menu,
|
||||
"Create empty Properties",
|
||||
(s, e) =>
|
||||
{
|
||||
CreateEmptyProperties = !CreateEmptyProperties;
|
||||
if (CreateEmptyProperties)
|
||||
{
|
||||
Params.Input.Clear();
|
||||
ClearData();
|
||||
}
|
||||
else if (Params.Input.Count == 0)
|
||||
{
|
||||
var p = CreateParameter(GH_ParameterSide.Input, 0);
|
||||
Params.RegisterInputParam(p);
|
||||
}
|
||||
ExpireSolution(true);
|
||||
},
|
||||
true,
|
||||
CreateEmptyProperties
|
||||
);
|
||||
emptyPropsMenuItem.ToolTipText =
|
||||
"Toggle creating empty Properties. If set, the output Properties will be empty. Use for removing properties from objects.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,8 @@ public static class GrasshopperHelpers
|
||||
/// <exception cref="SpeckleException">If it fails to cast</exception>
|
||||
public static GeometryBase GeometricGooToGeometryBase(this IGH_GeometricGoo geoGeo)
|
||||
{
|
||||
var value = geoGeo.GetType().GetProperty("Value")?.GetValue(geoGeo);
|
||||
// note: some objects (like text entities) can have multiple properties of name "Value"
|
||||
var value = geoGeo.GetType().GetProperties().FirstOrDefault(x => x.Name == "Value")?.GetValue(geoGeo);
|
||||
switch (value)
|
||||
{
|
||||
case GeometryBase gb:
|
||||
|
||||
+11
-1
@@ -1,4 +1,4 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
@@ -59,6 +59,16 @@ namespace Speckle.Connectors.GrasshopperShared.Properties {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap speckle_logo {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("logo", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
|
||||
@@ -118,6 +118,9 @@
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="logo" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\logo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="speckle_collections_create" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\speckle_collections_create.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Grasshopper;
|
||||
using Grasshopper.Kernel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Speckle.Connectors.Common;
|
||||
@@ -6,9 +7,11 @@ using Speckle.Connectors.Common.Builders;
|
||||
using Speckle.Connectors.Common.Operations;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Connectors.Common.Threading;
|
||||
using Speckle.Connectors.GrasshopperShared.Components;
|
||||
using Speckle.Connectors.GrasshopperShared.Operations.Receive;
|
||||
using Speckle.Connectors.GrasshopperShared.Operations.Send;
|
||||
using Speckle.Connectors.GrasshopperShared.Parameters;
|
||||
using Speckle.Connectors.GrasshopperShared.Properties;
|
||||
using Speckle.Converters.Rhino;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Credentials;
|
||||
@@ -23,6 +26,9 @@ public class PriorityLoader : GH_AssemblyPriority
|
||||
|
||||
public override GH_LoadingInstruction PriorityLoad()
|
||||
{
|
||||
Instances.ComponentServer.AddCategoryIcon(ComponentCategories.PRIMARY_RIBBON, Resources.speckle_logo);
|
||||
Instances.ComponentServer.AddCategorySymbolName(ComponentCategories.PRIMARY_RIBBON, 'S');
|
||||
|
||||
try
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 682 B |
+3
@@ -91,4 +91,7 @@
|
||||
<ItemGroup>
|
||||
<None Include="$(MSBuildThisFileDirectory)Resources\speckle_objects_object.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="$(MSBuildThisFileDirectory)Resources\logo.png" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+1
-1
@@ -86,4 +86,4 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\DBSplineToSpeckleRawConverter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Raw\VectorToSpeckleRawConverter.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
+8
-2
@@ -62,9 +62,15 @@ public class CurveToHostRawConverter : ITypedConverter<SOG.Curve, AG.NurbCurve3d
|
||||
: new AG.DoubleCollection(weightsList.ToArray());
|
||||
|
||||
AG.NurbCurve3d curve = new(target.degree, knots, pointCollection, weights, target.periodic);
|
||||
if (target.closed)
|
||||
if (target.closed && pointCollection[0].DistanceTo(pointCollection[^1]) > 0.001)
|
||||
{
|
||||
curve.MakeClosed();
|
||||
// method curve.MakeClosed() is unreliable: after TopLevelConverter uses ADB.Curve.CreateFromGeCurve to convert it to Spline, sometimes the spline.Closed=false
|
||||
pointCollection.Add(pointCollection[0]);
|
||||
if (weights.Count > 0)
|
||||
{
|
||||
weights.Add(weights[0]);
|
||||
}
|
||||
curve = new(target.degree, knots, pointCollection, weights, target.periodic);
|
||||
}
|
||||
|
||||
curve.SetInterval(_intervalConverter.Convert(target.domain));
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ public class RegionHatchToHostRawConverter : ITypedConverter<SOG.Region, ADB.Hat
|
||||
CheckForNonPlanarLoops(convertedCurve);
|
||||
var dbCurve = (ADB.Curve)convertedCurve[0].Item1;
|
||||
|
||||
// If Spline, turn into segmented polyline - this is how AutoCAD imports Hatches with Curve boundaries from Rhino
|
||||
// If Spline, turn into segmented polyline - this is how AutoCAD best imports Hatches with Curve boundaries from Rhino
|
||||
// Splines from AutoCAD don't need to be segmented (shape is fully preserved), but we don't have a way to distinguish them
|
||||
if (dbCurve is ADB.Spline spline)
|
||||
{
|
||||
if (spline.NurbsData.Degree == 1)
|
||||
|
||||
+5
-15
@@ -21,21 +21,21 @@ public class RegionToHostRawConverter : ITypedConverter<SOG.Region, ADB.Region>
|
||||
|
||||
// Converted boundary
|
||||
List<(ADB.Entity, Base)> convertedBoundary = _curveConverter.Convert(target.boundary);
|
||||
ADB.Curve nativeBoundary = ValidateCurve(convertedBoundary);
|
||||
List<ADB.Entity> nativeBoundary = convertedBoundary.Select(x => x.Item1).ToList();
|
||||
|
||||
// Converted loops
|
||||
var nativeLoops = new List<ADB.Curve>();
|
||||
List<List<ADB.Entity>> nativeLoops = new();
|
||||
foreach (var loop in target.innerLoops)
|
||||
{
|
||||
List<(ADB.Entity, Base)> convertedLoop = _curveConverter.Convert(loop);
|
||||
nativeLoops.Add(ValidateCurve(convertedLoop));
|
||||
nativeLoops.Add(convertedLoop.Select(x => x.Item1).ToList());
|
||||
}
|
||||
|
||||
// Add boundary to the ADB.DBObjectCollection
|
||||
// Calculate the outer region, method should return an array with 1 region
|
||||
// https://help.autodesk.com/view/OARX/2025/ENU/?guid=GUID-684E602E-3555-4370-BCDC-1CE594676C43
|
||||
ADB.DBObjectCollection boundaryDBObjColl = new();
|
||||
boundaryDBObjColl.Add(nativeBoundary);
|
||||
nativeBoundary.ForEach(x => boundaryDBObjColl.Add(x));
|
||||
using (ADB.DBObjectCollection outerRegionColl = ADB.Region.CreateFromCurves(boundaryDBObjColl))
|
||||
{
|
||||
if (outerRegionColl.Count != 1)
|
||||
@@ -52,7 +52,7 @@ public class RegionToHostRawConverter : ITypedConverter<SOG.Region, ADB.Region>
|
||||
// Same as above: Add loop segments to the ADB.DBObjectCollection
|
||||
// Calculate the inner region, method should return an array with 1 region
|
||||
ADB.DBObjectCollection loopDBObjColl = new();
|
||||
loopDBObjColl.Add(nativeLoop);
|
||||
nativeLoop.ForEach(x => loopDBObjColl.Add(x));
|
||||
using (ADB.DBObjectCollection innerRegionColl = ADB.Region.CreateFromCurves(loopDBObjColl))
|
||||
{
|
||||
if (innerRegionColl.Count != 1)
|
||||
@@ -76,14 +76,4 @@ public class RegionToHostRawConverter : ITypedConverter<SOG.Region, ADB.Region>
|
||||
|
||||
throw new ConversionException($"Region conversion failed: {target}");
|
||||
}
|
||||
|
||||
private ADB.Curve ValidateCurve(List<(ADB.Entity, Base)> convertedResult)
|
||||
{
|
||||
if (convertedResult.Count != 1)
|
||||
{
|
||||
// this will only be the case if it was a non-planar Polycurve: throw error
|
||||
throw new ConversionException($"Non-planar Polycurve cannot be used as a Region loop: {convertedResult}");
|
||||
}
|
||||
return (ADB.Curve)convertedResult[0].Item1;
|
||||
}
|
||||
}
|
||||
|
||||
+106
-33
@@ -17,19 +17,25 @@ public class HatchToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConver
|
||||
|
||||
public Base Convert(object target) => Convert((ADB.Hatch)target);
|
||||
|
||||
/// <summary>
|
||||
/// Converting AutoCAD Hatch to Speckle Region.
|
||||
/// This method first converts Hatch to AutoCAD Region, and then uses RegionToSpeckle converter.
|
||||
/// AutoCAD Region is a much simpler class than Hatch, and converting to region allows us to handle a bunch of unsupported conditions in Hatches.
|
||||
/// </summary>
|
||||
/// <param name="target">AutoCAD Hatch object</param>
|
||||
/// <returns>Speckle Region with property 'hasHatchPattern' as 'true'</returns>
|
||||
public SOG.Region Convert(ADB.Hatch target)
|
||||
{
|
||||
ADB.Region? regionToConvert = null;
|
||||
|
||||
for (int i = 0; i < target.NumberOfLoops; i++)
|
||||
{
|
||||
// Create 3d polyline from the HatchLoop
|
||||
// Convert HatchLoop into DBObjectCollection for the subsequent construction of the Region (.CreateFromCurves())
|
||||
ADB.HatchLoop loop = target.GetLoopAt(i);
|
||||
ADB.Curve polyline = PolylineFromLoop(loop);
|
||||
List<ADB.Curve> polyline = ConvertHatchLoopToCurveEntityList(loop);
|
||||
ADB.DBObjectCollection objCollection = new();
|
||||
objCollection.Add(polyline);
|
||||
polyline.ForEach(x => objCollection.Add(x));
|
||||
|
||||
// Convert polyline into an individual Region
|
||||
// Convert a loop (represented by DBObjectCollection) into an individual Region
|
||||
using (ADB.DBObjectCollection regionCollection = ADB.Region.CreateFromCurves(objCollection))
|
||||
{
|
||||
if (regionCollection.Count != 1)
|
||||
@@ -38,6 +44,7 @@ public class HatchToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConver
|
||||
$"Hatch conversion failed {target}: unexpected number of regions generated from 1 hatch loop"
|
||||
);
|
||||
}
|
||||
|
||||
ADB.Region loopRegion = (ADB.Region)regionCollection[0];
|
||||
|
||||
// Assign first loop as the main Region, other Regions will be subtracted from it
|
||||
@@ -51,6 +58,7 @@ public class HatchToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConver
|
||||
{
|
||||
throw new ConversionException($"Hatch conversion failed: {target}");
|
||||
}
|
||||
|
||||
// subtract region from Boundary region
|
||||
double areaBefore = regionToConvert.Area;
|
||||
regionToConvert.BooleanOperation(ADB.BooleanOperationType.BoolSubtract, loopRegion);
|
||||
@@ -69,6 +77,10 @@ public class HatchToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConver
|
||||
throw new ConversionException($"Hatch conversion failed: {target}");
|
||||
}
|
||||
|
||||
// move this region to the target elevation
|
||||
// POC: I've tried passing this elevation to ConvertHatchLoopToCurveEntityList() for direct assignment when converting 2d to 3d points, but this results in non-planarity in splines for some reason.
|
||||
regionToConvert.TransformBy(AG.Matrix3d.Displacement(new AG.Vector3d(0, 0, target.Elevation)));
|
||||
|
||||
// convert and store Regions
|
||||
SOG.Region convertedRegion = _regionConverter.Convert(regionToConvert);
|
||||
convertedRegion.hasHatchPattern = true;
|
||||
@@ -76,44 +88,105 @@ public class HatchToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConver
|
||||
return convertedRegion;
|
||||
}
|
||||
|
||||
private ADB.Curve PolylineFromLoop(ADB.HatchLoop loop)
|
||||
/// <summary>
|
||||
/// Converts Hatchloops to database-resident curve entities.
|
||||
/// Curve entities are required by the Region create method.
|
||||
/// </summary>
|
||||
private List<ADB.Curve> ConvertHatchLoopToCurveEntityList(ADB.HatchLoop loop)
|
||||
{
|
||||
List<ADB.Curve> curveList = new();
|
||||
|
||||
// 1 - handle the case of a polyline first
|
||||
if (loop.IsPolyline)
|
||||
{
|
||||
// disposable object, wrapping into "using"
|
||||
using (AG.Point3dCollection vertices = new())
|
||||
// create a polyline from the loop.Polyline BulgeVertexCollection
|
||||
ADB.Polyline polyline = new() { Closed = true };
|
||||
|
||||
for (int i = 0; i < loop.Polyline.Count; i++)
|
||||
{
|
||||
// collect vertices and construct a polyline simultaneously, it will be clear what to use after iterating
|
||||
ADB.Polyline polyline = new() { Closed = true };
|
||||
var vertex = loop.Polyline[i];
|
||||
|
||||
int count = 0;
|
||||
foreach (ADB.BulgeVertex bVertex in loop.Polyline)
|
||||
// check if this is the last point, the closed property is already set and duplicated endpoints will result in an invalid polyline
|
||||
if (i == loop.Polyline.Count - 1 && vertex.Vertex.GetDistanceTo(loop.Polyline[0].Vertex) < 0.001)
|
||||
{
|
||||
// don't add the end point that's the same as the start point
|
||||
AG.Point3d newPt = new(bVertex.Vertex.X, bVertex.Vertex.Y, 0);
|
||||
if (count == 0 || vertices[0].DistanceTo(newPt) > 0.00001)
|
||||
{
|
||||
vertices.Add(newPt);
|
||||
polyline.AddVertexAt(count, bVertex.Vertex, bVertex.Bulge, 0, 0);
|
||||
count++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// if only 2 points, that's a circle
|
||||
if (vertices.Count == 2)
|
||||
{
|
||||
AG.Point3d centerPt =
|
||||
new(
|
||||
vertices[0].X + (vertices[1].X - vertices[0].X) / 2,
|
||||
vertices[0].Y + (vertices[1].Y - vertices[0].Y) / 2,
|
||||
0
|
||||
);
|
||||
return new ADB.Circle(centerPt, AG.Vector3d.ZAxis, vertices[0].DistanceTo(vertices[1]) / 2);
|
||||
}
|
||||
return polyline;
|
||||
polyline.AddVertexAt(i, vertex.Vertex, vertex.Bulge, 0, 0);
|
||||
}
|
||||
|
||||
curveList.Add(polyline);
|
||||
return curveList;
|
||||
}
|
||||
|
||||
throw new ConversionException("Hatch loop conversion failed.");
|
||||
// 2 - if the loop is not a polyline, handle the loop curves
|
||||
// Notes: empirically, it seems that whenever the curve count is 1, it is a closed curve type like circle, ellipse, etc
|
||||
// and when the curve count is > 1, they are line segments that will comprise of a closed area
|
||||
// We'll process curves accordingly
|
||||
if (loop.Curves.Count == 0)
|
||||
{
|
||||
throw new ConversionException($"Hatch loop doesn't contain any segments.");
|
||||
}
|
||||
|
||||
foreach (AG.Curve2d curve in loop.Curves)
|
||||
{
|
||||
ADB.Curve? curveEntity = null;
|
||||
switch (curve)
|
||||
{
|
||||
case AG.LineSegment2d l:
|
||||
curveEntity = new ADB.Line(
|
||||
new AG.Point3d(l.StartPoint.X, l.StartPoint.Y, 0),
|
||||
new AG.Point3d(l.EndPoint.X, l.EndPoint.Y, 0)
|
||||
);
|
||||
break;
|
||||
|
||||
case AG.CircularArc2d c:
|
||||
AG.Point3d cCenter = new(c.Center.X, c.Center.Y, 0);
|
||||
curveEntity =
|
||||
c.EndPoint == c.StartPoint
|
||||
? new ADB.Circle(cCenter, AG.Vector3d.ZAxis, c.Radius)
|
||||
: new ADB.Arc(cCenter, c.Radius, c.StartAngle, c.EndAngle);
|
||||
break;
|
||||
|
||||
case AG.EllipticalArc2d e:
|
||||
curveEntity = new ADB.Ellipse(
|
||||
new AG.Point3d(e.Center.X, e.Center.Y, 0),
|
||||
AG.Vector3d.ZAxis,
|
||||
new AG.Vector3d(e.MajorAxis.X, e.MajorAxis.Y, 0),
|
||||
e.MinorRadius / e.MajorRadius,
|
||||
e.StartAngle,
|
||||
e.EndAngle
|
||||
);
|
||||
break;
|
||||
|
||||
case AG.NurbCurve2d n: // need to convert to spline, ew
|
||||
AG.Point3dCollection controlPoints = new();
|
||||
AG.DoubleCollection knots = new();
|
||||
n.Knots.Cast<double>().ToList().ForEach(x => knots.Add(x));
|
||||
n.DefinitionData.ControlPoints.Cast<AG.Point2d>()
|
||||
.ToList()
|
||||
.ForEach(x => controlPoints.Add(new AG.Point3d(x.X, x.Y, 0)));
|
||||
|
||||
curveEntity = new ADB.Spline(
|
||||
n.Degree,
|
||||
n.IsRational,
|
||||
n.IsClosed(),
|
||||
n.IsPeriodic(out _),
|
||||
controlPoints,
|
||||
knots,
|
||||
n.DefinitionData.Weights,
|
||||
0,
|
||||
0
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ConversionException($"Segments of type {curve.GetType()} are not supported");
|
||||
}
|
||||
|
||||
curveList.Add(curveEntity);
|
||||
}
|
||||
|
||||
return curveList;
|
||||
}
|
||||
}
|
||||
|
||||
+72
-58
@@ -12,21 +12,27 @@ public class RegionToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConve
|
||||
private readonly ITypedConverter<ABR.Brep, SOG.Mesh> _brepConverter;
|
||||
private readonly ITypedConverter<AG.LineSegment3d, SOG.Line> _lineConverter;
|
||||
private readonly ITypedConverter<AG.CircularArc3d, SOG.Arc> _arcConverter;
|
||||
private readonly ITypedConverter<ADB.Curve, ICurve> _nurbConverter;
|
||||
private readonly ITypedConverter<ADB.Circle, SOG.Circle> _circleConverter;
|
||||
private readonly ITypedConverter<ADB.Ellipse, SOG.Ellipse> _ellipseConverter;
|
||||
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
|
||||
|
||||
public RegionToSpeckleConverter(
|
||||
ITypedConverter<ABR.Brep, SOG.Mesh> brepConverter,
|
||||
ITypedConverter<AG.LineSegment3d, SOG.Line> lineConverter,
|
||||
ITypedConverter<AG.CircularArc3d, SOG.Arc> arcConverter,
|
||||
ITypedConverter<ADB.Curve, ICurve> nurbConverter,
|
||||
ITypedConverter<ADB.Circle, SOG.Circle> circleConverter,
|
||||
ITypedConverter<ADB.Ellipse, SOG.Ellipse> ellipseConverter,
|
||||
IConverterSettingsStore<AutocadConversionSettings> settingsStore
|
||||
)
|
||||
{
|
||||
_brepConverter = brepConverter;
|
||||
_lineConverter = lineConverter;
|
||||
_arcConverter = arcConverter;
|
||||
_nurbConverter = nurbConverter;
|
||||
_circleConverter = circleConverter;
|
||||
_ellipseConverter = ellipseConverter;
|
||||
_settingsStore = settingsStore;
|
||||
}
|
||||
|
||||
@@ -51,12 +57,15 @@ public class RegionToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConve
|
||||
.SelectMany(face => face.Loops);
|
||||
|
||||
// Get and convert boundary and inner loops
|
||||
var boundary = GetConvertedLoops(brepLoops, true)[0];
|
||||
var innerLoops = GetConvertedLoops(brepLoops, false);
|
||||
List<ICurve> innerLoops = ParseAndConvertBrepLoops(brepLoops, out ICurve? outerLoop);
|
||||
if (outerLoop is null)
|
||||
{
|
||||
throw new ConversionException("Could not convert outer region loop from brep.");
|
||||
}
|
||||
|
||||
return new SOG.Region()
|
||||
{
|
||||
boundary = boundary,
|
||||
boundary = outerLoop,
|
||||
innerLoops = innerLoops,
|
||||
hasHatchPattern = false,
|
||||
displayValue = [mesh],
|
||||
@@ -64,82 +73,87 @@ public class RegionToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConve
|
||||
};
|
||||
}
|
||||
|
||||
private List<ICurve> GetConvertedLoops(IEnumerable<ABR.BoundaryLoop> brepLoops, bool getOuterLoop)
|
||||
// Iterates through a list of brep boundary loops, converting them to Speckle and parsing between inner and outer loops
|
||||
private List<ICurve> ParseAndConvertBrepLoops(IEnumerable<ABR.BoundaryLoop> brepLoops, out ICurve? outerLoop)
|
||||
{
|
||||
var loops = new List<ICurve>();
|
||||
List<ICurve> innerLoops = new();
|
||||
outerLoop = null;
|
||||
foreach (var loop in brepLoops)
|
||||
{
|
||||
bool outer = loop.LoopType == ABR.LoopType.LoopExterior;
|
||||
|
||||
// continue only if the loop type is as requester (outer or inner)
|
||||
if ((outer && getOuterLoop) || (!outer && !getOuterLoop))
|
||||
List<AG.Curve3d> segments = new();
|
||||
foreach (ABR.Edge edge in loop.Edges)
|
||||
{
|
||||
// create segment collection for the current loop
|
||||
var segments = new List<AG.Curve3d>();
|
||||
foreach (var edge in loop.Edges)
|
||||
if (edge.Curve is AG.ExternalCurve3d xCurve && xCurve.IsNativeCurve)
|
||||
{
|
||||
var curve = edge.Curve;
|
||||
if (curve is AG.ExternalCurve3d xCurve && xCurve.IsNativeCurve)
|
||||
{
|
||||
segments.Add(xCurve.NativeCurve);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ConversionException("Unsupported curve type for Region conversion");
|
||||
}
|
||||
segments.Add(xCurve.NativeCurve);
|
||||
}
|
||||
// reverse segment collection with arcs in case end-start points of subsequent segments don't match
|
||||
if (segments.Count > 1 && Math.Abs(segments[0].EndPoint.DistanceTo(segments[1].StartPoint)) > 0.00001)
|
||||
else
|
||||
{
|
||||
segments.Reverse();
|
||||
throw new ConversionException("Unsupported curve type for Region conversion");
|
||||
}
|
||||
}
|
||||
|
||||
// convert segments to Speckle Polycurve or Circle
|
||||
var convertedLoop = ConvertSegmentsToICurve(segments);
|
||||
loops.Add(convertedLoop);
|
||||
ICurve convertedLoop =
|
||||
segments.Count == 1 ? ConvertSegmentToICurve(segments.First()) : ConvertSegmentsToICurve(segments);
|
||||
|
||||
// sort inner or outer loop
|
||||
if (loop.LoopType == ABR.LoopType.LoopExterior)
|
||||
{
|
||||
outerLoop = convertedLoop;
|
||||
}
|
||||
else
|
||||
{
|
||||
innerLoops.Add(convertedLoop);
|
||||
}
|
||||
}
|
||||
|
||||
return loops;
|
||||
return innerLoops;
|
||||
}
|
||||
|
||||
private ICurve ConvertSegmentToICurve(AG.Curve3d segment)
|
||||
{
|
||||
switch (segment)
|
||||
{
|
||||
case AG.CircularArc3d arc: // expected to be closed
|
||||
return arc.StartPoint == arc.EndPoint
|
||||
? _circleConverter.Convert(new ADB.Circle(arc.Center, arc.Normal, arc.Radius))
|
||||
: _arcConverter.Convert(arc);
|
||||
case AG.EllipticalArc3d ellipse:
|
||||
return _ellipseConverter.Convert(
|
||||
new ADB.Ellipse(
|
||||
ellipse.Center,
|
||||
ellipse.Normal,
|
||||
ellipse.MajorRadius * ellipse.MajorAxis,
|
||||
ellipse.MinorRadius / ellipse.MajorRadius,
|
||||
ellipse.StartAngle,
|
||||
ellipse.EndAngle
|
||||
)
|
||||
);
|
||||
case AG.NurbCurve3d nurbs:
|
||||
return _nurbConverter.Convert(ADB.Curve.CreateFromGeCurve(nurbs));
|
||||
default:
|
||||
throw new ConversionException($"Unsupported curve type for Region conversion: {segment}");
|
||||
}
|
||||
}
|
||||
|
||||
private ICurve ConvertSegmentsToICurve(List<AG.Curve3d> segments)
|
||||
{
|
||||
ICurve convertedLoop;
|
||||
|
||||
// Handle edge case: if the segment is a closed Arc, then use Circle conversion to create a valid shape.
|
||||
// Also, closed arcs cause errors when receiving in other host apps, like Rhino.
|
||||
if (segments.Count == 1 && segments[0] is AG.CircularArc3d arc && arc.StartAngle + arc.EndAngle == 0)
|
||||
return new SOG.Polycurve()
|
||||
{
|
||||
convertedLoop = _circleConverter.Convert(
|
||||
new ADB.Circle(arc.GetPlane().PointOnPlane, arc.GetPlane().Normal, arc.Radius)
|
||||
);
|
||||
}
|
||||
// otherwise, just construct a Polycurve from subsequent segments
|
||||
else
|
||||
{
|
||||
// Maybe we need to convert to AutoCAD Polycurve
|
||||
convertedLoop = new SOG.Polycurve()
|
||||
{
|
||||
segments = segments.Select(x => ConvertSegment(x)).ToList(),
|
||||
closed = true,
|
||||
units = _settingsStore.Current.SpeckleUnits
|
||||
};
|
||||
}
|
||||
|
||||
return convertedLoop;
|
||||
segments = segments.Select(x => ConvertSegment(x)).ToList(),
|
||||
closed = true,
|
||||
units = _settingsStore.Current.SpeckleUnits
|
||||
};
|
||||
}
|
||||
|
||||
private ICurve ConvertSegment(AG.Curve3d curve)
|
||||
{
|
||||
switch (curve)
|
||||
return curve switch
|
||||
{
|
||||
case AG.LineSegment3d line:
|
||||
return _lineConverter.Convert(line);
|
||||
case AG.CircularArc3d arc:
|
||||
return _arcConverter.Convert(arc);
|
||||
}
|
||||
|
||||
throw new ConversionException($"Unsupported curve type for Region conversion: {curve}");
|
||||
AG.LineSegment3d line => _lineConverter.Convert(line),
|
||||
AG.CircularArc3d arc => _arcConverter.Convert(arc),
|
||||
AG.NurbCurve3d nurb => _nurbConverter.Convert(ADB.Curve.CreateFromGeCurve(nurb)),
|
||||
_ => throw new ConversionException($"Unsupported curve type for Region conversion: {curve}")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,12 +3,12 @@ using Speckle.Converters.Common.Objects;
|
||||
|
||||
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
|
||||
|
||||
public class CircularArc2dToSpeckleConverter : ITypedConverter<AG.CircularArc2d, SOG.Arc>
|
||||
public class CircularArc2dToSpeckleRawConverter : ITypedConverter<AG.CircularArc2d, SOG.Arc>
|
||||
{
|
||||
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
|
||||
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
|
||||
|
||||
public CircularArc2dToSpeckleConverter(
|
||||
public CircularArc2dToSpeckleRawConverter(
|
||||
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
|
||||
IConverterSettingsStore<AutocadConversionSettings> settingsStore
|
||||
)
|
||||
|
||||
+2
-2
@@ -3,13 +3,13 @@ using Speckle.Converters.Common.Objects;
|
||||
|
||||
namespace Speckle.Converters.Autocad.ToSpeckle.Raw;
|
||||
|
||||
public class CircularArc3dToSpeckleConverter : ITypedConverter<AG.CircularArc3d, SOG.Arc>
|
||||
public class CircularArc3dToSpeckleRawConverter : ITypedConverter<AG.CircularArc3d, SOG.Arc>
|
||||
{
|
||||
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
|
||||
private readonly ITypedConverter<AG.Plane, SOG.Plane> _planeConverter;
|
||||
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
|
||||
|
||||
public CircularArc3dToSpeckleConverter(
|
||||
public CircularArc3dToSpeckleRawConverter(
|
||||
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
|
||||
ITypedConverter<AG.Plane, SOG.Plane> planeConverter,
|
||||
IConverterSettingsStore<AutocadConversionSettings> settingsStore
|
||||
|
||||
+4
@@ -16,6 +16,7 @@ public class GeometryBaseConverter : IToSpeckleTopLevelConverter
|
||||
private readonly ITypedConverter<RG.PointCloud, SOG.Pointcloud> _pointcloudConverter;
|
||||
private readonly ITypedConverter<RG.PolyCurve, SOG.Polycurve> _polycurveConverter;
|
||||
private readonly ITypedConverter<RG.Polyline, SOG.Polyline> _polylineConverter;
|
||||
private readonly ITypedConverter<RG.TextEntity, SA.Text> _textConverter;
|
||||
private readonly ITypedConverter<RG.Mesh, SOG.Mesh> _meshConverter;
|
||||
private readonly ITypedConverter<RG.Extrusion, SOG.ExtrusionX> _extrusionConverter;
|
||||
private readonly ITypedConverter<RG.SubD, SOG.SubDX> _subdConverter;
|
||||
@@ -30,6 +31,7 @@ public class GeometryBaseConverter : IToSpeckleTopLevelConverter
|
||||
ITypedConverter<RG.PointCloud, SOG.Pointcloud> pointcloudConverter,
|
||||
ITypedConverter<RG.PolyCurve, SOG.Polycurve> polycurveConverter,
|
||||
ITypedConverter<RG.Polyline, SOG.Polyline> polylineConverter,
|
||||
ITypedConverter<RG.TextEntity, SA.Text> textConverter,
|
||||
ITypedConverter<RG.Mesh, SOG.Mesh> meshConverter,
|
||||
ITypedConverter<RG.Brep, SOG.BrepX> brepConverter,
|
||||
ITypedConverter<RG.Extrusion, SOG.ExtrusionX> extrusionConverter,
|
||||
@@ -44,6 +46,7 @@ public class GeometryBaseConverter : IToSpeckleTopLevelConverter
|
||||
_pointcloudConverter = pointcloudConverter;
|
||||
_polycurveConverter = polycurveConverter;
|
||||
_polylineConverter = polylineConverter;
|
||||
_textConverter = textConverter;
|
||||
_meshConverter = meshConverter;
|
||||
_brepConverter = brepConverter;
|
||||
_extrusionConverter = extrusionConverter;
|
||||
@@ -63,6 +66,7 @@ public class GeometryBaseConverter : IToSpeckleTopLevelConverter
|
||||
RG.PolyCurve polyCurve => _polycurveConverter.Convert(polyCurve),
|
||||
RG.Polyline polyline => _polylineConverter.Convert(polyline),
|
||||
RG.PolylineCurve polylineCurve => _polylineConverter.Convert(polylineCurve.ToPolyline()),
|
||||
RG.TextEntity text => _textConverter.Convert(text),
|
||||
RG.Mesh mesh => _meshConverter.Convert(mesh),
|
||||
RG.Brep brep => _brepConverter.Convert(brep),
|
||||
RG.Extrusion ext => _extrusionConverter.Convert(ext),
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
using Rhino.DocObjects;
|
||||
using Rhino.DocObjects;
|
||||
using Speckle.Converters.Common;
|
||||
using Speckle.Converters.Common.Objects;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class TextEntityToSpeckleConverter : ITypedConverter<RG.TextEntity, SA.Te
|
||||
new()
|
||||
{
|
||||
value = target.PlainText,
|
||||
height = target.TextHeight,
|
||||
height = target.TextHeight * target.DimensionScale,
|
||||
maxWidth = target.FormatWidth == 0 ? null : target.FormatWidth,
|
||||
origin = _pointConverter.Convert(target.Plane.Origin),
|
||||
plane = GetTextPlane(target),
|
||||
|
||||
Reference in New Issue
Block a user