Skip to content

Commit

Permalink
DUI3-426 PR moved from specklesystems/speckle-sharp#3545 (#7)
Browse files Browse the repository at this point in the history
* PR moved from specklesystems/speckle-sharp#3545

* ArcGISDocument to Singleton

* read offsets from metadata

* move crs assignment on send to RootObjBuilder

* move all conversions to activeCRS

* safer read from metadata

* default degrees to meters (like QGIS)

* csharpier

* scoped

* remove UoW from root builders as send/recieve bindings already use it (#21)

* remove POC comment

* remove unnecessary assignments; add offsets to incoming dataset name

* limit dataset name length

* tilt ellipse on receive

* fix substrings

* remove Rhino uow comment

* add SR to the received dataset name

* format

---------

Co-authored-by: Adam Hathcock <[email protected]>
  • Loading branch information
KatKatKateryna and adamhathcock authored Jul 15, 2024
1 parent 99caeb2 commit abe5a07
Show file tree
Hide file tree
Showing 25 changed files with 416 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public HostObjectBuilderResult Build(
CancellationToken cancellationToken
)
{
// TODO get spatialRef and offsets & rotation from ProjectInfo in CommitObject
// ATM, GIS commit CRS is stored per layer (in FeatureClass converter), but should be moved to the Root level too

// Prompt the UI conversion started. Progress bar will swoosh.
onOperationProgressed?.Invoke("Converting", null);

Expand Down Expand Up @@ -211,7 +214,7 @@ Dictionary<string, GroupLayer> createdLayerGroups
)
{
// get layer details
string? datasetId = trackerItem.DatasetId; // should not ne null here
string? datasetId = trackerItem.DatasetId; // should not be null here
Uri uri = new($"{_contextStack.Current.Document.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{datasetId}");
string nestedLayerName = trackerItem.NestedLayerName;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using System.Diagnostics;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Mapping;
using Objects.GIS;
using Speckle.Autofac.DependencyInjection;
using Speckle.Connectors.Utils.Builders;
using Speckle.Connectors.Utils.Caching;
using Speckle.Connectors.Utils.Conversion;
using Speckle.Connectors.Utils.Operations;
using Speckle.Converters.ArcGIS3;
using Speckle.Converters.ArcGIS3.Utils;
using Speckle.Converters.Common;
using Speckle.Core.Logging;
using Speckle.Core.Models;
Expand All @@ -16,13 +20,19 @@ namespace Speckle.Connectors.ArcGis.Operations.Send;
/// </summary>
public class ArcGISRootObjectBuilder : IRootObjectBuilder<MapMember>
{
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
private readonly IRootToSpeckleConverter _rootToSpeckleConverter;
private readonly ISendConversionCache _sendConversionCache;
private readonly IConversionContextStack<ArcGISDocument, Unit> _contextStack;

public ArcGISRootObjectBuilder(IUnitOfWorkFactory unitOfWorkFactory, ISendConversionCache sendConversionCache)
public ArcGISRootObjectBuilder(
ISendConversionCache sendConversionCache,
IConversionContextStack<ArcGISDocument, Unit> contextStack,
IRootToSpeckleConverter rootToSpeckleConverter
)
{
_unitOfWorkFactory = unitOfWorkFactory;
_sendConversionCache = sendConversionCache;
_contextStack = contextStack;
_rootToSpeckleConverter = rootToSpeckleConverter;
}

public RootObjectBuilderResult Build(
Expand All @@ -32,10 +42,8 @@ public RootObjectBuilderResult Build(
CancellationToken ct = default
)
{
// POC: does this feel like the right place? I am wondering if this should be called from within send/rcv?
// begin the unit of work
using var uow = _unitOfWorkFactory.Resolve<IRootToSpeckleConverter>();
var converter = uow.Service;
// TODO: add a warning if Geographic CRS is set
// "Data has been sent in the units 'degrees'. It is advisable to set the project CRS to Projected type (e.g. EPSG:32631) to be able to receive geometry correctly in CAD/BIM software"

int count = 0;

Expand All @@ -60,7 +68,23 @@ public RootObjectBuilderResult Build(
}
else
{
converted = converter.Convert(mapMember);
converted = _rootToSpeckleConverter.Convert(mapMember);

// get Active CRS (for writing geometry coords)
var spatialRef = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference;
converted["crs"] = new CRS
{
wkt = spatialRef.Wkt,
name = spatialRef.Name,
offset_y = System.Convert.ToSingle(_contextStack.Current.Document.ActiveCRSoffsetRotation.LatOffset),
offset_x = System.Convert.ToSingle(_contextStack.Current.Document.ActiveCRSoffsetRotation.LonOffset),
rotation = System.Convert.ToSingle(_contextStack.Current.Document.ActiveCRSoffsetRotation.TrueNorthRadians),
units_native = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpeckleUnitString,
};

// other properties
converted["name"] = mapMember.Name;
converted["units"] = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpeckleUnitString;
converted.applicationId = applicationId;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ namespace Speckle.Connectors.Rhino7.Operations.Send;
/// </summary>
public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
{
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
private readonly IRootToSpeckleConverter _rootToSpeckleConverter;
private readonly ISendConversionCache _sendConversionCache;
private readonly RhinoInstanceObjectsManager _instanceObjectsManager;
private readonly IConversionContextStack<RhinoDoc, UnitSystem> _contextStack;
private readonly RhinoLayerManager _layerManager;

public RhinoRootObjectBuilder(
IUnitOfWorkFactory unitOfWorkFactory,
ISendConversionCache sendConversionCache,
IConversionContextStack<RhinoDoc, UnitSystem> contextStack,
RhinoLayerManager layerManager,
RhinoInstanceObjectsManager instanceObjectsManager
RhinoInstanceObjectsManager instanceObjectsManager,
IRootToSpeckleConverter rootToSpeckleConverter
)
{
_unitOfWorkFactory = unitOfWorkFactory;
_sendConversionCache = sendConversionCache;
_contextStack = contextStack;
_layerManager = layerManager;
_instanceObjectsManager = instanceObjectsManager;
_rootToSpeckleConverter = rootToSpeckleConverter;
}

public RootObjectBuilderResult Build(
Expand All @@ -54,11 +54,6 @@ private RootObjectBuilderResult ConvertObjects(
CancellationToken cancellationToken = default
)
{
// POC: does this feel like the right place? I am wondering if this should be called from within send/rcv?
// begin the unit of work
using var uow = _unitOfWorkFactory.Resolve<IRootToSpeckleConverter>();
var converter = uow.Service;

var rootObjectCollection = new Collection { name = _contextStack.Current.Document.Name ?? "Unnamed document" };
int count = 0;

Expand Down Expand Up @@ -100,7 +95,7 @@ private RootObjectBuilderResult ConvertObjects(
}
else
{
converted = converter.Convert(rhinoObject);
converted = _rootToSpeckleConverter.Convert(rhinoObject);
converted.applicationId = applicationId;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using Speckle.Converters.ArcGIS3.Utils;
using Speckle.Converters.Common;

namespace Speckle.Converters.ArcGIS3;
Expand All @@ -13,12 +14,16 @@ public class ArcGISDocument
public Project Project { get; }
public Map Map { get; }
public Uri SpeckleDatabasePath { get; }
public CRSoffsetRotation ActiveCRSoffsetRotation { get; set; }

public ArcGISDocument()
{
Project = Project.Current;
Map = MapView.Active.Map;
SpeckleDatabasePath = EnsureOrAddSpeckleDatabase();
// CRS of either: incoming commit to be applied to all received objects, or CRS to convert all objects to, before sending
// created per Send/Receive operation, will be the same for all objects in the operation
ActiveCRSoffsetRotation = new CRSoffsetRotation(MapView.Active.Map);
}

private const string FGDB_NAME = "Speckle.gdb";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ private static IReadOnlyDictionary<int, string> Create()

public string ConvertOrThrow(Unit hostUnit)
{
// allow to send data in degrees (RootObjBuilder will send a warning)
if (hostUnit.UnitType == UnitType.Angular && hostUnit.FactoryCode == 9102)
{
return Units.Meters;
}

int linearUnit = LinearUnit.CreateLinearUnit(hostUnit.Wkt).FactoryCode;

if (s_unitMapping.TryGetValue(linearUnit, out string? value))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,25 @@ public FeatureClass Convert(VectorLayer target)
{
wktString = target.crs.wkt;
}
// ATM, GIS commit CRS is stored per layer, but should be moved to the Root level too, and created once per Receive
ACG.SpatialReference spatialRef = ACG.SpatialReferenceBuilder.CreateSpatialReference(wktString);

double trueNorthRadians = System.Convert.ToDouble(
(target.crs == null || target.crs?.rotation == null) ? 0 : target.crs.rotation
);
double latOffset = System.Convert.ToDouble(
(target.crs == null || target.crs?.offset_y == null) ? 0 : target.crs.offset_y
);
double lonOffset = System.Convert.ToDouble(
(target.crs == null || target.crs?.offset_x == null) ? 0 : target.crs.offset_x
);
_contextStack.Current.Document.ActiveCRSoffsetRotation = new CRSoffsetRotation(
spatialRef,
latOffset,
lonOffset,
trueNorthRadians
);

// create Fields
List<FieldDescription> fields = _fieldsUtils.GetFieldsFromSpeckleLayer(target);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public ACG.Multipatch Convert(List<SOG.Mesh> target)
{
throw new SpeckleConversionException("Feature contains no geometries");
}
ACG.MultipatchBuilderEx multipatchPart = new(_contextStack.Current.Document.Map.SpatialReference);
ACG.MultipatchBuilderEx multipatchPart =
new(_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference);
foreach (SOG.Mesh part in target)
{
part.TriangulateMesh();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Core.Kits;
using Speckle.Core.Models;

namespace Speckle.Converters.ArcGIS3.ToHost.Raw;
Expand All @@ -18,12 +17,14 @@ public PointToHostConverter(IConversionContextStack<ArcGISDocument, ACG.Unit> co

public ACG.MapPoint Convert(SOG.Point target)
{
double scaleFactor = Units.GetConversionFactor(target.units, _contextStack.Current.SpeckleUnits);
SOG.Point scaledMovedRotatedPoint = _contextStack.Current.Document.ActiveCRSoffsetRotation.OffsetRotateOnReceive(
target
);
return new ACG.MapPointBuilderEx(
target.x * scaleFactor,
target.y * scaleFactor,
target.z * scaleFactor,
_contextStack.Current.Document.Map.SpatialReference
scaledMovedRotatedPoint.x,
scaledMovedRotatedPoint.y,
scaledMovedRotatedPoint.z,
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ public ACG.Polyline Convert(SOG.Arc target)
fromPt,
toPt,
new ACG.Coordinate2D(midPt),
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
);

return new ACG.PolylineBuilderEx(
segment,
ACG.AttributeFlags.HasZ,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ public ACG.Polyline Convert(SOG.Circle target)
new ACG.Coordinate2D(centerPt.X, centerPt.Y),
(double)target.radius * scaleFactor,
ACG.ArcOrientation.ArcClockwise,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
);

return new ACG.PolylineBuilderEx(
circleSegment,
ACG.AttributeFlags.HasZ,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public ACG.Polyline Convert(SOG.Ellipse target)
double scaleFactor = Units.GetConversionFactor(target.units, _contextStack.Current.SpeckleUnits);

// set default values
double angle = Math.Atan2(target.plane.xdir.y, target.plane.xdir.x);
double angle =
Math.Atan2(target.plane.xdir.y, target.plane.xdir.x)
+ _contextStack.Current.Document.ActiveCRSoffsetRotation.TrueNorthRadians;
double majorAxisRadius = (double)target.firstRadius;
double minorAxisRatio = (double)target.secondRadius / majorAxisRadius;

Expand All @@ -61,13 +63,13 @@ public ACG.Polyline Convert(SOG.Ellipse target)
majorAxisRadius * scaleFactor,
minorAxisRatio,
ACG.ArcOrientation.ArcCounterClockwise,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
);

return new ACG.PolylineBuilderEx(
segment,
ACG.AttributeFlags.HasZ,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public ACG.Polyline Convert(SOG.Line target)
return new ACG.PolylineBuilderEx(
points,
ACG.AttributeFlags.HasZ,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public ACG.Polyline Convert(SOG.Polycurve target)
return new ACG.PolylineBuilderEx(
segments,
ACG.AttributeFlags.HasZ,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public ACG.Polyline Convert(SOG.Polyline target)
return new ACG.PolylineBuilderEx(
points,
ACG.AttributeFlags.HasZ,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ public SOG.Box Convert(Envelope target)
target.XMin,
target.YMin,
target.ZMin,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
MapPoint pointMax = new MapPointBuilderEx(
target.XMax,
target.YMax,
target.ZMax,
_contextStack.Current.Document.Map.SpatialReference
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference
).ToGeometry();
SOG.Point minPtSpeckle = _pointConverter.Convert(pointMin);
SOG.Point maxPtSpeckle = _pointConverter.Convert(pointMax);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,34 @@ public SOG.Point Convert(MapPoint target)
{
try
{
// reproject to Active CRS
if (
GeometryEngine.Instance.Project(target, _contextStack.Current.Document.Map.SpatialReference)
GeometryEngine.Instance.Project(target, _contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference)
is not MapPoint reprojectedPt
)
{
throw new SpeckleConversionException(
$"Conversion to Spatial Reference {_contextStack.Current.Document.Map.SpatialReference.Name} failed"
$"Conversion to Spatial Reference {_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference.Name} failed"
);
}
return new(reprojectedPt.X, reprojectedPt.Y, reprojectedPt.Z, _contextStack.Current.SpeckleUnits);

// convert to Speckle Pt
SOG.Point reprojectedSpecklePt =
new(
reprojectedPt.X,
reprojectedPt.Y,
reprojectedPt.Z,
_contextStack.Current.Document.ActiveCRSoffsetRotation.SpeckleUnitString
);
SOG.Point scaledMovedRotatedPoint = _contextStack.Current.Document.ActiveCRSoffsetRotation.OffsetRotateOnSend(
reprojectedSpecklePt
);
return scaledMovedRotatedPoint;
}
catch (ArgumentException ex)
{
throw new SpeckleConversionException(
$"Conversion to Spatial Reference {_contextStack.Current.Document.Map.SpatialReference} failed",
$"Conversion to Spatial Reference {_contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference.Name} failed",
ex
);
}
Expand Down
Loading

0 comments on commit abe5a07

Please sign in to comment.