From 6277f7e6d63b6a805d5d74b6f274676a17f99857 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Mon, 24 Jun 2024 19:58:44 +0100 Subject: [PATCH 01/17] offset-rotation data container --- .../Utils/CRSoffsetRotation.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs new file mode 100644 index 0000000000..ac85c65b96 --- /dev/null +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -0,0 +1,24 @@ +namespace Speckle.Converters.ArcGIS3.Utils; + +/// +/// Container with origin offsets and rotation angle +/// +public readonly struct CRSoffsetRotation +{ + public double LatOffset { get; } + public double LonOffset { get; } + public double TrueNorthRadians { get; } + + /// + /// Initializes a new instance of . + /// + /// Latitude (Y) in degrees. + /// Longitude (X) in degrees. + /// Angle to True North in radians. + public CRSoffsetRotation(double latDegrees, double lonDegrees, double trueNorthRadians) + { + LatOffset = latDegrees; + LonOffset = lonDegrees; + TrueNorthRadians = trueNorthRadians; + } +} From 8bcaa731dd0906d408ca32c2ac320915e90da5ec Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Mon, 24 Jun 2024 20:00:18 +0100 Subject: [PATCH 02/17] typos --- .../Utils/CRSoffsetRotation.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index ac85c65b96..f151e8cfc3 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -10,15 +10,15 @@ public readonly struct CRSoffsetRotation public double TrueNorthRadians { get; } /// - /// Initializes a new instance of . + /// Initializes a new instance of . /// - /// Latitude (Y) in degrees. - /// Longitude (X) in degrees. + /// Latitude (Y) ofsset in the current SpatialReference units. + /// Longitude (X) ofsset in the current SpatialReference units. /// Angle to True North in radians. - public CRSoffsetRotation(double latDegrees, double lonDegrees, double trueNorthRadians) + public CRSoffsetRotation(double latOffset, double lonOffset, double trueNorthRadians) { - LatOffset = latDegrees; - LonOffset = lonDegrees; + LatOffset = latOffset; + LonOffset = lonOffset; TrueNorthRadians = trueNorthRadians; } } From 2d72914fe868a04c51983153c37c01e330bcbf42 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Thu, 27 Jun 2024 00:25:25 +0100 Subject: [PATCH 03/17] more complete constructor --- .../Utils/CRSoffsetRotation.cs | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index f151e8cfc3..85ee84de48 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -1,22 +1,44 @@ +using ArcGIS.Core.Geometry; + namespace Speckle.Converters.ArcGIS3.Utils; /// -/// Container with origin offsets and rotation angle +/// Container with origin offsets and rotation angle for the specified SpatialReference /// -public readonly struct CRSoffsetRotation +public struct CRSoffsetRotation { - public double LatOffset { get; } - public double LonOffset { get; } - public double TrueNorthRadians { get; } + public SpatialReference SpatialReference { get; } + public double LatOffset { get; set; } + public double LonOffset { get; set; } + public double TrueNorthRadians { get; set; } + + /// + /// Initializes a new instance of . + /// + /// Latitude (Y) ofsset in the current SpatialReference units. + public CRSoffsetRotation(SpatialReference spatialReference) + { + SpatialReference = spatialReference; + LatOffset = 0; + LonOffset = 0; + TrueNorthRadians = 0; + } /// /// Initializes a new instance of . /// + /// SpatialReference to apply offsets and rotation to. /// Latitude (Y) ofsset in the current SpatialReference units. /// Longitude (X) ofsset in the current SpatialReference units. /// Angle to True North in radians. - public CRSoffsetRotation(double latOffset, double lonOffset, double trueNorthRadians) + public CRSoffsetRotation( + SpatialReference spatialReference, + double latOffset, + double lonOffset, + double trueNorthRadians + ) { + SpatialReference = spatialReference; LatOffset = latOffset; LonOffset = lonOffset; TrueNorthRadians = trueNorthRadians; From 13a405fd592c0c8c873f71e533c29c246cf62916 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Thu, 27 Jun 2024 01:10:02 +0100 Subject: [PATCH 04/17] add Send-Receive transforms --- .../Utils/CRSoffsetRotation.cs | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 85ee84de48..1d31bab5cc 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -12,10 +12,41 @@ public struct CRSoffsetRotation public double LonOffset { get; set; } public double TrueNorthRadians { get; set; } + private void NormalizeAngle() + { + if (TrueNorthRadians < -2 * Math.PI || TrueNorthRadians > 2 * Math.PI) + { + // do something + TrueNorthRadians += 0; + } + } + + public SOG.Point OffsetRotateOnReceive(SOG.Point point) + { + // ?? scale PT first, to match CRS? + NormalizeAngle(); + double x2 = point.x * Math.Cos(TrueNorthRadians) - point.y * Math.Sin(TrueNorthRadians); + double y2 = point.x * Math.Sin(TrueNorthRadians) + point.y * Math.Cos(TrueNorthRadians); + x2 += LonOffset; + y2 += LatOffset; + return new SOG.Point(x2, y2, point.z, point.units); + } + + public SOG.Point OffsetRotateOnSend(SOG.Point point) + { + // ?? scale PT first, to match CRS? + NormalizeAngle(); + double x2 = point.x - LonOffset; + double y2 = point.y - LatOffset; + x2 = x2 * Math.Cos(TrueNorthRadians) + y2 * Math.Sin(TrueNorthRadians); + y2 = -x2 * Math.Sin(TrueNorthRadians) + y2 * Math.Cos(TrueNorthRadians); + return new SOG.Point(x2, y2, point.z, point.units); + } + /// /// Initializes a new instance of . /// - /// Latitude (Y) ofsset in the current SpatialReference units. + /// SpatialReference to apply offsets and rotation to. public CRSoffsetRotation(SpatialReference spatialReference) { SpatialReference = spatialReference; From 3758ae7e7f17580e778e0c993a29ca2e4f129e6b Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 01:28:43 +0100 Subject: [PATCH 05/17] all offset operations; add to ContextStack --- .../ArcGISConversionContextStack.cs | 2 + .../Utils/CRSoffsetRotation.cs | 64 ++++++++++++++----- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs index 1649d205dc..ff1c84d05c 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs @@ -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; @@ -13,6 +14,7 @@ public class ArcGISDocument public Project Project { get; } public Map Map { get; } public Uri SpeckleDatabasePath { get; } + public CRSoffsetRotation CRSoffsetRotation { get; } public ArcGISDocument() { diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 1d31bab5cc..c53249bce4 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -1,4 +1,4 @@ -using ArcGIS.Core.Geometry; +using Speckle.Core.Kits; namespace Speckle.Converters.ArcGIS3.Utils; @@ -7,49 +7,78 @@ namespace Speckle.Converters.ArcGIS3.Utils; /// public struct CRSoffsetRotation { - public SpatialReference SpatialReference { get; } + public ACG.SpatialReference SpatialReference { get; } + public string SpeckleUnitString { get; set; } public double LatOffset { get; set; } public double LonOffset { get; set; } public double TrueNorthRadians { get; set; } - private void NormalizeAngle() - { - if (TrueNorthRadians < -2 * Math.PI || TrueNorthRadians > 2 * Math.PI) - { - // do something - TrueNorthRadians += 0; - } - } - public SOG.Point OffsetRotateOnReceive(SOG.Point point) { - // ?? scale PT first, to match CRS? + // scale point to match units of the SpatialReference + string originalUnits = point.units; + point = ScalePoint(point, originalUnits, SpeckleUnitString); + NormalizeAngle(); double x2 = point.x * Math.Cos(TrueNorthRadians) - point.y * Math.Sin(TrueNorthRadians); double y2 = point.x * Math.Sin(TrueNorthRadians) + point.y * Math.Cos(TrueNorthRadians); x2 += LonOffset; y2 += LatOffset; - return new SOG.Point(x2, y2, point.z, point.units); + SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); + + // scale back to original units + movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); + + return movedPoint; } public SOG.Point OffsetRotateOnSend(SOG.Point point) { - // ?? scale PT first, to match CRS? + // scale point to match units of the SpatialReference + string originalUnits = point.units; + point = ScalePoint(point, originalUnits, SpeckleUnitString); + + // rotate and move point NormalizeAngle(); double x2 = point.x - LonOffset; double y2 = point.y - LatOffset; x2 = x2 * Math.Cos(TrueNorthRadians) + y2 * Math.Sin(TrueNorthRadians); y2 = -x2 * Math.Sin(TrueNorthRadians) + y2 * Math.Cos(TrueNorthRadians); - return new SOG.Point(x2, y2, point.z, point.units); + SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); + + // scale back to original units + movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); + + return movedPoint; + } + + private readonly SOG.Point ScalePoint(SOG.Point point, string fromUnit, string toUnit) + { + double scaleFactor = Units.GetConversionFactor(fromUnit, toUnit); + return new SOG.Point(point.x * scaleFactor, point.x * scaleFactor, point.z * scaleFactor, toUnit); + } + + private readonly string GetSpeckleUnit(ACG.SpatialReference spatialReference) + { + return new ArcGISToSpeckleUnitConverter().ConvertOrThrow(spatialReference.Unit); + } + + private void NormalizeAngle() + { + if (TrueNorthRadians < -2 * Math.PI || TrueNorthRadians > 2 * Math.PI) + { + TrueNorthRadians = TrueNorthRadians % 2 * Math.PI; + } } /// /// Initializes a new instance of . /// /// SpatialReference to apply offsets and rotation to. - public CRSoffsetRotation(SpatialReference spatialReference) + public CRSoffsetRotation(ACG.SpatialReference spatialReference) { SpatialReference = spatialReference; + SpeckleUnitString = GetSpeckleUnit(spatialReference); LatOffset = 0; LonOffset = 0; TrueNorthRadians = 0; @@ -63,13 +92,14 @@ public CRSoffsetRotation(SpatialReference spatialReference) /// Longitude (X) ofsset in the current SpatialReference units. /// Angle to True North in radians. public CRSoffsetRotation( - SpatialReference spatialReference, + ACG.SpatialReference spatialReference, double latOffset, double lonOffset, double trueNorthRadians ) { SpatialReference = spatialReference; + SpeckleUnitString = GetSpeckleUnit(spatialReference); LatOffset = latOffset; LonOffset = lonOffset; TrueNorthRadians = trueNorthRadians; From 7b6e692ce566e8e9036416741671fc0dec0d18a9 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 02:45:27 +0100 Subject: [PATCH 06/17] set active crs --- .../Operations/Receive/HostObjectBuilder.cs | 7 ++- .../Send/ArcGISRootObjectBuilder.cs | 16 ++++++- .../ArcGISConversionContextStack.cs | 3 +- .../Utils/CRSoffsetRotation.cs | 45 +++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs index 3e22f2d85d..4b375d27a1 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs @@ -44,6 +44,11 @@ public HostObjectBuilderResult Build( CancellationToken cancellationToken ) { + // set active CRS & offsets + double trueNorth = 0; // example = CRSoffsetRotation.RotationFromRevitData(rootObject); + CRSoffsetRotation crsOffsetRotation = new(_contextStack.Current.Document.Map.SpatialReference, trueNorth); + _contextStack.Current.Document.ActiveCRSoffsetRotation = crsOffsetRotation; + // Prompt the UI conversion started. Progress bar will swoosh. onOperationProgressed?.Invoke("Converting", null); @@ -177,7 +182,7 @@ Dictionary 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; diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs index 9b371194e0..91750774b5 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs @@ -1,10 +1,13 @@ using System.Diagnostics; +using ArcGIS.Core.Geometry; using ArcGIS.Desktop.Mapping; 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; @@ -18,11 +21,17 @@ public class ArcGISRootObjectBuilder : IRootObjectBuilder { private readonly IUnitOfWorkFactory _unitOfWorkFactory; private readonly ISendConversionCache _sendConversionCache; + private readonly IConversionContextStack _contextStack; - public ArcGISRootObjectBuilder(IUnitOfWorkFactory unitOfWorkFactory, ISendConversionCache sendConversionCache) + public ArcGISRootObjectBuilder( + IUnitOfWorkFactory unitOfWorkFactory, + ISendConversionCache sendConversionCache, + IConversionContextStack contextStack + ) { _unitOfWorkFactory = unitOfWorkFactory; _sendConversionCache = sendConversionCache; + _contextStack = contextStack; } public RootObjectBuilderResult Build( @@ -32,6 +41,11 @@ public RootObjectBuilderResult Build( CancellationToken ct = default ) { + // set active CRS & offsets + double trueNorth = 0; + CRSoffsetRotation crsOffsetRotation = new(_contextStack.Current.Document.Map.SpatialReference, trueNorth); + _contextStack.Current.Document.ActiveCRSoffsetRotation = crsOffsetRotation; + // 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(); diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs index ff1c84d05c..05bceaee2c 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs @@ -14,13 +14,14 @@ public class ArcGISDocument public Project Project { get; } public Map Map { get; } public Uri SpeckleDatabasePath { get; } - public CRSoffsetRotation CRSoffsetRotation { get; } + public CRSoffsetRotation ActiveCRSoffsetRotation { get; set; } public ArcGISDocument() { Project = Project.Current; Map = MapView.Active.Map; SpeckleDatabasePath = EnsureOrAddSpeckleDatabase(); + ActiveCRSoffsetRotation = new CRSoffsetRotation(MapView.Active.Map.SpatialReference); } private const string FGDB_NAME = "Speckle.gdb"; diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index c53249bce4..18e8ea12c4 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -1,4 +1,6 @@ +using Objects.BuiltElements.Revit; using Speckle.Core.Kits; +using Speckle.Core.Models; namespace Speckle.Converters.ArcGIS3.Utils; @@ -71,6 +73,35 @@ private void NormalizeAngle() } } + public static double? RotationFromRevitData(Base rootObject) + { + // rewrite function to take into account Local reference point in Revit, and Transformation matrix + foreach (KeyValuePair prop in rootObject.GetMembers(DynamicBaseMemberType.Dynamic)) + { + if (prop.Key == "info") + { + ProjectInfo? revitProjInfo = (ProjectInfo?)rootObject[prop.Key]; + if (revitProjInfo != null) + { + try + { + if (revitProjInfo["locations"] is List locationList && locationList.Count > 0) + { + Base location = locationList[0]; + return Convert.ToDouble(location["trueNorth"]); + } + } + catch (Exception ex) when (ex is FormatException || ex is InvalidCastException || ex is OverflowException) + { + // origin not found, do nothing + } + break; + } + } + } + return null; + } + /// /// Initializes a new instance of . /// @@ -84,6 +115,20 @@ public CRSoffsetRotation(ACG.SpatialReference spatialReference) TrueNorthRadians = 0; } + /// + /// Initializes a new instance of . + /// + /// SpatialReference to apply offsets and rotation to. + /// Angle to True North in radians. + public CRSoffsetRotation(ACG.SpatialReference spatialReference, double trueNorthRadians) + { + SpatialReference = spatialReference; + SpeckleUnitString = GetSpeckleUnit(spatialReference); + LatOffset = 0; + LonOffset = 0; + TrueNorthRadians = trueNorthRadians; + } + /// /// Initializes a new instance of . /// From e6720a0608da22014be0e9f941d1408985c77ce7 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 03:05:13 +0100 Subject: [PATCH 07/17] basic to and from converters with offsets --- .../Geometry/PointSingleToHostConverter.cs | 11 +++++----- .../Geometry/PointToSpeckleConverter.cs | 21 +++++++++++++++---- .../Utils/CRSoffsetRotation.cs | 4 ++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointSingleToHostConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointSingleToHostConverter.cs index e30ec589e5..85fd338da0 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointSingleToHostConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointSingleToHostConverter.cs @@ -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.Geometry; @@ -18,11 +17,13 @@ public PointToHostConverter(IConversionContextStack 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 + scaledMovedRotatedPoint.x, + scaledMovedRotatedPoint.y, + scaledMovedRotatedPoint.z ).ToGeometry(); } } diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointToSpeckleConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointToSpeckleConverter.cs index 198af4e5ee..c0b5e0a6b5 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointToSpeckleConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Geometry/PointToSpeckleConverter.cs @@ -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} 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 ); } diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 18e8ea12c4..4aaedc6559 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -29,7 +29,7 @@ public SOG.Point OffsetRotateOnReceive(SOG.Point point) SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); // scale back to original units - movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); + // movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); return movedPoint; } @@ -49,7 +49,7 @@ public SOG.Point OffsetRotateOnSend(SOG.Point point) SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); // scale back to original units - movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); + // movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); return movedPoint; } From 1f6191fc1c0486ba6e6f69d85e93814679d87d28 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 14:02:24 +0100 Subject: [PATCH 08/17] add customCRS option --- .../Operations/Receive/HostObjectBuilder.cs | 14 +++- .../Layers/FeatureClassToHostConverter.cs | 1 + .../Utils/CRSorigin.cs | 68 +++++++++++++++++++ .../Utils/NonNativeFeaturesUtils.cs | 2 +- 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSorigin.cs diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs index 4b375d27a1..94c7363dad 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs @@ -44,9 +44,19 @@ public HostObjectBuilderResult Build( CancellationToken cancellationToken ) { + // get active CRS & offsets + SpatialReference activeSpatialRef = _contextStack.Current.Document.Map.SpatialReference; + // Browse for any trace of geolocation in non-GIS apps (e.g. Revit: implemented, Blender: todo on Blender side, Civil3d: ?) + CRSorigin? dataOrigin = null; // e.g. CRSorigin.FromRevitData(rootObject); + if (dataOrigin is CRSorigin crsOrigin) + { + activeSpatialRef = crsOrigin.CreateCustomCRS(); + } + double trueNorthRadians = 0; // example = CRSoffsetRotation.RotationFromRevitData(rootObject); + double latOffset = 0; + double lonOffset = 0; + CRSoffsetRotation crsOffsetRotation = new(activeSpatialRef, latOffset, lonOffset, trueNorthRadians); // set active CRS & offsets - double trueNorth = 0; // example = CRSoffsetRotation.RotationFromRevitData(rootObject); - CRSoffsetRotation crsOffsetRotation = new(_contextStack.Current.Document.Map.SpatialReference, trueNorth); _contextStack.Current.Document.ActiveCRSoffsetRotation = crsOffsetRotation; // Prompt the UI conversion started. Progress bar will swoosh. diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs index 0a084ffee8..31d2f9b83a 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs @@ -88,6 +88,7 @@ public FeatureClass Convert(VectorLayer target) wktString = target.crs.wkt.ToString(); } ACG.SpatialReference spatialRef = ACG.SpatialReferenceBuilder.CreateSpatialReference(wktString); + _contextStack.Current.Document.ActiveCRSoffsetRotation = new CRSoffsetRotation(spatialRef); // create Fields List fields = _fieldsUtils.GetFieldsFromSpeckleLayer(target); diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSorigin.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSorigin.cs new file mode 100644 index 0000000000..0ceb2954c3 --- /dev/null +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSorigin.cs @@ -0,0 +1,68 @@ +using ArcGIS.Core.Geometry; +using Objects.BuiltElements.Revit; +using Speckle.Core.Models; + +namespace Speckle.Converters.ArcGIS3.Utils; + +/// +/// Container with origin coordinates and rotation angle +/// +public readonly struct CRSorigin +{ + public double LatDegrees { get; } + public double LonDegrees { get; } + + /// + /// Initializes a new instance of . + /// + /// Latitude (Y) in degrees. + /// Longitude (X) in degrees. + public CRSorigin(double latDegrees, double lonDegrees) + { + LatDegrees = latDegrees; + LonDegrees = lonDegrees; + } + + public static CRSorigin? FromRevitData(Base rootObject) + { + // rewrite function to take into account Local reference point in Revit, and Transformation matrix + foreach (KeyValuePair prop in rootObject.GetMembers(DynamicBaseMemberType.Dynamic)) + { + if (prop.Key == "info") + { + ProjectInfo? revitProjInfo = (ProjectInfo?)rootObject[prop.Key]; + if (revitProjInfo != null) + { + try + { + double lat = Convert.ToDouble(revitProjInfo["latitude"]); + double lon = Convert.ToDouble(revitProjInfo["longitude"]); + double trueNorth; + if (revitProjInfo["locations"] is List locationList && locationList.Count > 0) + { + Base location = locationList[0]; + trueNorth = Convert.ToDouble(location["trueNorth"]); + } + return new CRSorigin(lat * 180 / Math.PI, lon * 180 / Math.PI); + } + catch (Exception ex) when (ex is FormatException || ex is InvalidCastException || ex is OverflowException) + { + // origin not found, do nothing + } + break; + } + } + } + return null; + } + + public SpatialReference CreateCustomCRS() + { + string wktString = + // QGIS example: $"PROJCS[\"unknown\", GEOGCS[\"unknown\", DATUM[\"WGS_1984\", SPHEROID[\"WGS 84\", 6378137, 298.257223563], AUTHORITY[\"EPSG\", \"6326\"]], PRIMEM[\"Greenwich\", 0, AUTHORITY[\"EPSG\", \"8901\"]], UNIT[\"degree\", 0.0174532925199433]], PROJECTION[\"Transverse_Mercator\"], PARAMETER[\"latitude_of_origin\", {LatDegrees}], PARAMETER[\"central_meridian\", {LonDegrees}], PARAMETER[\"scale_factor\", 1], PARAMETER[\"false_easting\", 0], PARAMETER[\"false_northing\", 0], UNIT[\"metre\", 1, AUTHORITY[\"EPSG\", \"9001\"]], AXIS[\"Easting\", EAST], AXIS[\"Northing\", NORTH]]"; + // replicating ArcGIS created custom WKT: + $"PROJCS[\"SpeckleSpatialReference_latlon_{LatDegrees}_{LonDegrees}\", GEOGCS[\"GCS_WGS_1984\", DATUM[\"D_WGS_1984\", SPHEROID[\"WGS_1984\", 6378137.0, 298.257223563]], PRIMEM[\"Greenwich\", 0.0], UNIT[\"Degree\", 0.0174532925199433]], PROJECTION[\"Transverse_Mercator\"], PARAMETER[\"False_Easting\", 0.0], PARAMETER[\"False_Northing\", 0.0], PARAMETER[\"Central_Meridian\", {LonDegrees}], PARAMETER[\"Scale_Factor\", 1.0], PARAMETER[\"Latitude_Of_Origin\", {LatDegrees}], UNIT[\"Meter\", 1.0]]"; + + return SpatialReferenceBuilder.CreateSpatialReference(wktString); + } +} diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs index 3a17ff8796..10f25caf23 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs @@ -118,7 +118,7 @@ private void CreateDatasetInDatabase( SchemaBuilder schemaBuilder = new(geodatabase); // get Spatial Reference from the document - ACG.SpatialReference spatialRef = _contextStack.Current.Document.Map.SpatialReference; + ACG.SpatialReference spatialRef = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference; // create Fields List<(FieldDescription, Func)> fieldsAndFunctions = _fieldUtils.CreateFieldsFromListOfBase( From b2d59d8f2a502494a6877f9e18872ee12b963f49 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 14:16:16 +0100 Subject: [PATCH 09/17] sync creation and assignment of ActiveCRS on send&receive (host&root obj builder); assignment to Sent & Received GIS/nonGIS classes --- .../Operations/Receive/HostObjectBuilder.cs | 5 +++-- .../Operations/Send/ArcGISRootObjectBuilder.cs | 7 +++++-- .../ArcGISConversionContextStack.cs | 2 ++ .../Layers/FeatureClassToHostConverter.cs | 1 + .../Layers/VectorLayerToSpeckleConverter.cs | 8 ++++---- .../Utils/NonNativeFeaturesUtils.cs | 2 +- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs index 94c7363dad..4039247a30 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs @@ -44,9 +44,10 @@ public HostObjectBuilderResult Build( CancellationToken cancellationToken ) { - // get active CRS & offsets + // get active CRS & offsets on Receive SpatialReference activeSpatialRef = _contextStack.Current.Document.Map.SpatialReference; // Browse for any trace of geolocation in non-GIS apps (e.g. Revit: implemented, Blender: todo on Blender side, Civil3d: ?) + // ATM, GIS commit CRS is stored per layer, but should be moved to the Root level too CRSorigin? dataOrigin = null; // e.g. CRSorigin.FromRevitData(rootObject); if (dataOrigin is CRSorigin crsOrigin) { @@ -56,7 +57,7 @@ CancellationToken cancellationToken double latOffset = 0; double lonOffset = 0; CRSoffsetRotation crsOffsetRotation = new(activeSpatialRef, latOffset, lonOffset, trueNorthRadians); - // set active CRS & offsets + // set active CRS & offsets on Receive _contextStack.Current.Document.ActiveCRSoffsetRotation = crsOffsetRotation; // Prompt the UI conversion started. Progress bar will swoosh. diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs index 91750774b5..ece09d44eb 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs @@ -41,9 +41,12 @@ public RootObjectBuilderResult Build( CancellationToken ct = default ) { - // set active CRS & offsets + // set active CRS & offsets on Send double trueNorth = 0; - CRSoffsetRotation crsOffsetRotation = new(_contextStack.Current.Document.Map.SpatialReference, trueNorth); + double latOffset = 0; + double lonOffset = 0; + CRSoffsetRotation crsOffsetRotation = + new(_contextStack.Current.Document.Map.SpatialReference, latOffset, lonOffset, trueNorth); _contextStack.Current.Document.ActiveCRSoffsetRotation = crsOffsetRotation; // POC: does this feel like the right place? I am wondering if this should be called from within send/rcv? diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs index 05bceaee2c..ed7258eded 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ArcGISConversionContextStack.cs @@ -21,6 +21,8 @@ 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.SpatialReference); } diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs index 31d2f9b83a..9cbcb21e95 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/FeatureClassToHostConverter.cs @@ -87,6 +87,7 @@ public FeatureClass Convert(VectorLayer target) { wktString = target.crs.wkt.ToString(); } + // 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); _contextStack.Current.Document.ActiveCRSoffsetRotation = new CRSoffsetRotation(spatialRef); diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/VectorLayerToSpeckleConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/VectorLayerToSpeckleConverter.cs index 5712ecc8ee..5435de3f73 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/VectorLayerToSpeckleConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Layers/VectorLayerToSpeckleConverter.cs @@ -54,18 +54,18 @@ public VectorLayer Convert(FeatureLayer target) { VectorLayer speckleLayer = new(); - // get document CRS (for writing geometry coords) - var spatialRef = _contextStack.Current.Document.Map.SpatialReference; + // get Active CRS (for writing geometry coords) + var spatialRef = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference; speckleLayer.crs = new CRS { wkt = spatialRef.Wkt, name = spatialRef.Name, - units_native = spatialRef.Unit.ToString(), + units_native = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpeckleUnitString, }; // other properties speckleLayer.name = target.Name; - speckleLayer.units = _contextStack.Current.SpeckleUnits; + speckleLayer.units = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpeckleUnitString; // get feature class fields var allLayerAttributes = new Base(); diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs index 10f25caf23..9f95c740e8 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/NonNativeFeaturesUtils.cs @@ -117,7 +117,7 @@ private void CreateDatasetInDatabase( Geodatabase geodatabase = new(fileGeodatabaseConnectionPath); SchemaBuilder schemaBuilder = new(geodatabase); - // get Spatial Reference from the document + // get Spatial Reference from the Active CRS for Receive ACG.SpatialReference spatialRef = _contextStack.Current.Document.ActiveCRSoffsetRotation.SpatialReference; // create Fields From e8bfa581e79db2f5de7af8e064c857f800ddd727 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 14:29:52 +0100 Subject: [PATCH 10/17] minor comments --- .../Utils/CRSoffsetRotation.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 4aaedc6559..746f11e3a8 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -21,16 +21,15 @@ public SOG.Point OffsetRotateOnReceive(SOG.Point point) string originalUnits = point.units; point = ScalePoint(point, originalUnits, SpeckleUnitString); + // rotate coordinates NormalizeAngle(); double x2 = point.x * Math.Cos(TrueNorthRadians) - point.y * Math.Sin(TrueNorthRadians); double y2 = point.x * Math.Sin(TrueNorthRadians) + point.y * Math.Cos(TrueNorthRadians); + // offset coordinates x2 += LonOffset; y2 += LatOffset; SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); - // scale back to original units - // movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); - return movedPoint; } @@ -40,17 +39,15 @@ public SOG.Point OffsetRotateOnSend(SOG.Point point) string originalUnits = point.units; point = ScalePoint(point, originalUnits, SpeckleUnitString); - // rotate and move point + // rotate coordinates NormalizeAngle(); double x2 = point.x - LonOffset; double y2 = point.y - LatOffset; + // offset coordinates x2 = x2 * Math.Cos(TrueNorthRadians) + y2 * Math.Sin(TrueNorthRadians); y2 = -x2 * Math.Sin(TrueNorthRadians) + y2 * Math.Cos(TrueNorthRadians); SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); - // scale back to original units - // movedPoint = ScalePoint(movedPoint, SpeckleUnitString, originalUnits); - return movedPoint; } From 85442cd13e480ba642e2a84460dc88a48297aa0a Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 14:59:38 +0100 Subject: [PATCH 11/17] typo --- .../Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 746f11e3a8..55d0ab3d45 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -54,7 +54,7 @@ public SOG.Point OffsetRotateOnSend(SOG.Point point) private readonly SOG.Point ScalePoint(SOG.Point point, string fromUnit, string toUnit) { double scaleFactor = Units.GetConversionFactor(fromUnit, toUnit); - return new SOG.Point(point.x * scaleFactor, point.x * scaleFactor, point.z * scaleFactor, toUnit); + return new SOG.Point(point.x * scaleFactor, point.y * scaleFactor, point.z * scaleFactor, toUnit); } private readonly string GetSpeckleUnit(ACG.SpatialReference spatialReference) From 217879257218bab31944d1c26292860f81f7ac4a Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sat, 29 Jun 2024 16:12:18 +0100 Subject: [PATCH 12/17] weird fix --- .../Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 55d0ab3d45..b3fd534d8a 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -15,11 +15,11 @@ public struct CRSoffsetRotation public double LonOffset { get; set; } public double TrueNorthRadians { get; set; } - public SOG.Point OffsetRotateOnReceive(SOG.Point point) + public SOG.Point OffsetRotateOnReceive(SOG.Point pointOriginal) { // scale point to match units of the SpatialReference - string originalUnits = point.units; - point = ScalePoint(point, originalUnits, SpeckleUnitString); + string originalUnits = pointOriginal.units; + SOG.Point point = ScalePoint(pointOriginal, originalUnits, SpeckleUnitString); // rotate coordinates NormalizeAngle(); From faf81cb0e2306ebab763248c347e044120aa7597 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sun, 30 Jun 2024 02:48:00 +0100 Subject: [PATCH 13/17] comment --- .../Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index b3fd534d8a..0d5aa78d3c 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -6,6 +6,10 @@ namespace Speckle.Converters.ArcGIS3.Utils; /// /// Container with origin offsets and rotation angle for the specified SpatialReference +/// Offsets and rotation will modify geometry on Send, so non-GIS apps can receive it correctly +/// Receiving GIS geometry in GIS hostApp will "undo" the geometry modifications according to the offsets&rotation applied before +/// In the future, CAD/BIM objects will contain ProjectInfo data with CRS & offsets, so this object can be generated on Recieve +/// TODO: consider how to generate this object to receive non-GIS data already now, without it having ProjectInfo object /// public struct CRSoffsetRotation { From 7e4f4660d316ce71fcadd73770f7631427ac1fca Mon Sep 17 00:00:00 2001 From: KatKatKateryna <89912278+KatKatKateryna@users.noreply.github.com> Date: Sun, 30 Jun 2024 18:56:43 +0800 Subject: [PATCH 14/17] Update comment --- .../Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 0d5aa78d3c..51b15096bf 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -25,11 +25,11 @@ public SOG.Point OffsetRotateOnReceive(SOG.Point pointOriginal) string originalUnits = pointOriginal.units; SOG.Point point = ScalePoint(pointOriginal, originalUnits, SpeckleUnitString); - // rotate coordinates + // 1. rotate coordinates NormalizeAngle(); double x2 = point.x * Math.Cos(TrueNorthRadians) - point.y * Math.Sin(TrueNorthRadians); double y2 = point.x * Math.Sin(TrueNorthRadians) + point.y * Math.Cos(TrueNorthRadians); - // offset coordinates + // 2. offset coordinates x2 += LonOffset; y2 += LatOffset; SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); @@ -43,11 +43,11 @@ public SOG.Point OffsetRotateOnSend(SOG.Point point) string originalUnits = point.units; point = ScalePoint(point, originalUnits, SpeckleUnitString); - // rotate coordinates + // 1. offset coordinates NormalizeAngle(); double x2 = point.x - LonOffset; double y2 = point.y - LatOffset; - // offset coordinates + // 2. rotate coordinates x2 = x2 * Math.Cos(TrueNorthRadians) + y2 * Math.Sin(TrueNorthRadians); y2 = -x2 * Math.Sin(TrueNorthRadians) + y2 * Math.Cos(TrueNorthRadians); SOG.Point movedPoint = new(x2, y2, point.z, SpeckleUnitString); From 6545d193475b1156f24a9cf731fff86ac0dca0b6 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Tue, 2 Jul 2024 14:46:32 +0100 Subject: [PATCH 15/17] set offsets from GIS on receive --- .../Operations/Receive/HostObjectBuilder.cs | 2 +- .../ToHost/Raw/FeatureClassToHostConverter.cs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs index cab08a6402..7e29d65ee6 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs @@ -48,7 +48,7 @@ CancellationToken cancellationToken // get active CRS & offsets on Receive SpatialReference activeSpatialRef = _contextStack.Current.Document.Map.SpatialReference; // Browse for any trace of geolocation in non-GIS apps (e.g. Revit: implemented, Blender: todo on Blender side, Civil3d: ?) - // ATM, GIS commit CRS is stored per layer, but should be moved to the Root level too + // ATM, GIS commit CRS is stored per layer (in FeatureClass converter), but should be moved to the Root level too CRSorigin? dataOrigin = null; // e.g. CRSorigin.FromRevitData(rootObject); if (dataOrigin is CRSorigin crsOrigin) { diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToHost/Raw/FeatureClassToHostConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToHost/Raw/FeatureClassToHostConverter.cs index 0436928629..c87f27314c 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToHost/Raw/FeatureClassToHostConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToHost/Raw/FeatureClassToHostConverter.cs @@ -89,7 +89,22 @@ public FeatureClass Convert(VectorLayer target) } // 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); - _contextStack.Current.Document.ActiveCRSoffsetRotation = new CRSoffsetRotation(spatialRef); + + 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 fields = _fieldsUtils.GetFieldsFromSpeckleLayer(target); From 503bbbd3cbd9377093a8ed22347e5ce8ab1b4dea Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Tue, 2 Jul 2024 14:49:57 +0100 Subject: [PATCH 16/17] comment --- .../Operations/Send/ArcGISRootObjectBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs index ece09d44eb..7822498493 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Send/ArcGISRootObjectBuilder.cs @@ -41,7 +41,7 @@ public RootObjectBuilderResult Build( CancellationToken ct = default ) { - // set active CRS & offsets on Send + // set active CRS & offsets on Send, add offsets if we find a way to set them up double trueNorth = 0; double latOffset = 0; double lonOffset = 0; From d9326b594096dabbc1a8f465c359726d7ae06b48 Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Tue, 2 Jul 2024 15:05:31 +0100 Subject: [PATCH 17/17] xml; add offsets to layers data --- .../ToSpeckle/TopLevel/PointcloudLayerToSpeckleConverter.cs | 3 +++ .../ToSpeckle/TopLevel/RasterLayerToSpeckleConverter.cs | 3 +++ .../ToSpeckle/TopLevel/VectorLayerToSpeckleConverter.cs | 3 +++ .../Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs | 4 ++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/PointcloudLayerToSpeckleConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/PointcloudLayerToSpeckleConverter.cs index 2ad672dea9..4cd7b4caa9 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/PointcloudLayerToSpeckleConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/PointcloudLayerToSpeckleConverter.cs @@ -81,6 +81,9 @@ public SGIS.VectorLayer Convert(LasDatasetLayer target) { 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 = spatialRef.Unit.ToString(), }; diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/RasterLayerToSpeckleConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/RasterLayerToSpeckleConverter.cs index 22a93c52a9..5b0c8bb4dd 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/RasterLayerToSpeckleConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/RasterLayerToSpeckleConverter.cs @@ -38,6 +38,9 @@ public SGIS.RasterLayer Convert(RasterLayer target) { 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 = spatialRef.Unit.ToString(), }; diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/VectorLayerToSpeckleConverter.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/VectorLayerToSpeckleConverter.cs index b05cd86908..387f2a297f 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/VectorLayerToSpeckleConverter.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/ToSpeckle/TopLevel/VectorLayerToSpeckleConverter.cs @@ -60,6 +60,9 @@ public VectorLayer Convert(FeatureLayer target) { 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, }; diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs index 51b15096bf..741fc6aa78 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/Utils/CRSoffsetRotation.cs @@ -7,8 +7,8 @@ namespace Speckle.Converters.ArcGIS3.Utils; /// /// Container with origin offsets and rotation angle for the specified SpatialReference /// Offsets and rotation will modify geometry on Send, so non-GIS apps can receive it correctly -/// Receiving GIS geometry in GIS hostApp will "undo" the geometry modifications according to the offsets&rotation applied before -/// In the future, CAD/BIM objects will contain ProjectInfo data with CRS & offsets, so this object can be generated on Recieve +/// Receiving GIS geometry in GIS hostApp will "undo" the geometry modifications according to the offsets and rotation applied before +/// In the future, CAD/BIM objects will contain ProjectInfo data with CRS and offsets, so this object can be generated on Recieve /// TODO: consider how to generate this object to receive non-GIS data already now, without it having ProjectInfo object /// public struct CRSoffsetRotation