Skip to content

Commit

Permalink
Arcgis documentation kate jedd (#3459)
Browse files Browse the repository at this point in the history
* expanding context stack Document from Map to (Project, Map)

* move all database operations to context stack (it should only be called once per any operation and results (e.g. database path) accessible throughout converters)

* fix Uri format needed for adding layers

* Register ArcGISDocument

* database URI fix

---------

Co-authored-by: oguzhankoral <[email protected]>
  • Loading branch information
KatKatKateryna and oguzhankoral authored Jun 5, 2024
1 parent 53b9055 commit 3191365
Show file tree
Hide file tree
Showing 22 changed files with 171 additions and 201 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,27 @@
using ArcGIS.Core.Geometry;
using Objects.GIS;
using Speckle.Core.Models.GraphTraversal;
using Speckle.Converters.ArcGIS3;

namespace Speckle.Connectors.ArcGIS.Operations.Receive;

public class ArcGISHostObjectBuilder : IHostObjectBuilder
{
private readonly IRootToHostConverter _converter;
private readonly IArcGISProjectUtils _arcGISProjectUtils;
private readonly INonNativeFeaturesUtils _nonGisFeaturesUtils;

// POC: figure out the correct scope to only initialize on Receive
private readonly IConversionContextStack<Map, Unit> _contextStack;
private readonly IConversionContextStack<ArcGISDocument, Unit> _contextStack;
private readonly GraphTraversal _traverseFunction;

public ArcGISHostObjectBuilder(
IRootToHostConverter converter,
IArcGISProjectUtils arcGISProjectUtils,
IConversionContextStack<Map, Unit> contextStack,
IConversionContextStack<ArcGISDocument, Unit> contextStack,
INonNativeFeaturesUtils nonGisFeaturesUtils,
GraphTraversal traverseFunction
)
{
_converter = converter;
_arcGISProjectUtils = arcGISProjectUtils;
_contextStack = contextStack;
_nonGisFeaturesUtils = nonGisFeaturesUtils;
_traverseFunction = traverseFunction;
Expand Down Expand Up @@ -59,14 +57,16 @@ List<string> objectIds
return (objPath, converted);
}

public string AddDatasetsToMap((string, string) databaseObj, string databasePath)
public string AddDatasetsToMap((string, string) databaseObj)
{
try
{
return LayerFactory.Instance
.CreateLayer(
new Uri($"{databasePath}\\{databaseObj.Item2}"),
_contextStack.Current.Document,
new Uri(
$"{_contextStack.Current.Document.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{databaseObj.Item2}"
),
_contextStack.Current.Document.Map,
layerName: databaseObj.Item1
)
.URI;
Expand All @@ -75,8 +75,10 @@ public string AddDatasetsToMap((string, string) databaseObj, string databasePath
{
return StandaloneTableFactory.Instance
.CreateStandaloneTable(
new Uri($"{databasePath}\\{databaseObj.Item2}"),
_contextStack.Current.Document,
new Uri(
$"{_contextStack.Current.Document.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{databaseObj.Item2}"
),
_contextStack.Current.Document.Map,
tableName: databaseObj.Item1
)
.URI;
Expand Down Expand Up @@ -115,11 +117,6 @@ CancellationToken cancellationToken
// Prompt the UI conversion started. Progress bar will swoosh.
onOperationProgressed?.Invoke("Converting", null);

// create and add Geodatabase to a project

string databasePath = _arcGISProjectUtils.GetDatabasePath();
_arcGISProjectUtils.AddDatabaseToProject(databasePath);

// POC: This is where we will define our receive strategy, or maybe later somewhere else according to some setting pass from UI?
var objectsToConvert = _traverseFunction
.Traverse(rootObject)
Expand Down Expand Up @@ -193,7 +190,7 @@ CancellationToken cancellationToken
{
try
{
bakedLayersURIs.Add(AddDatasetsToMap(databaseObj, databasePath));
bakedLayersURIs.Add(AddDatasetsToMap(databaseObj));
}
catch (Exception e) when (!e.IsFatal())
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Mapping;
using Speckle.Autofac.DependencyInjection;
using Speckle.Converters.ArcGIS3.Utils;
using Speckle.Converters.Common;
Expand All @@ -17,12 +16,12 @@ public void Load(SpeckleContainerBuilder builder)
builder.AddScoped<IFeatureClassUtils, FeatureClassUtils>();
builder.AddScoped<IArcGISFieldUtils, ArcGISFieldUtils>();
builder.AddScoped<ICharacterCleaner, CharacterCleaner>();
builder.AddScoped<IArcGISProjectUtils, ArcGISProjectUtils>();
builder.AddScoped<INonNativeFeaturesUtils, NonNativeFeaturesUtils>();
builder.AddScoped<ArcGISDocument>();

builder.AddScoped<IHostToSpeckleUnitConverter<Unit>, ArcGISToSpeckleUnitConverter>();

// single stack per conversion
builder.AddScoped<IConversionContextStack<Map, Unit>, ArcGISConversionContextStack>();
builder.AddScoped<IConversionContextStack<ArcGISDocument, Unit>, ArcGISConversionContextStack>();
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,110 @@
using System.Diagnostics.CodeAnalysis;
using ArcGIS.Core.Geometry;
using ArcGIS.Core.Data.DDL;
using ArcGIS.Core.Data;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using Speckle.Converters.Common;

namespace Speckle.Converters.ArcGIS3;

public class ArcGISDocument
{
public Project Project { get; }
public Map Map { get; }
public Uri SpeckleDatabasePath { get; }

public ArcGISDocument()
{
Project = Project.Current;
Map = MapView.Active.Map;
SpeckleDatabasePath = EnsureOrAddSpeckleDatabase();
}

private const string FGDB_NAME = "Speckle.gdb";

public Uri EnsureOrAddSpeckleDatabase()
{
return AddDatabaseToProject(GetDatabasePath());
}

public Uri GetDatabasePath()
{
try
{
var parentDirectory = Directory.GetParent(Project.Current.URI);
if (parentDirectory == null)
{
throw new ArgumentException($"Project directory {Project.Current.URI} not found");
}
var fGdbPath = new Uri(parentDirectory.FullName);
return new Uri($"{fGdbPath}/{FGDB_NAME}");
}
catch (Exception ex)
when (ex
is IOException
or UnauthorizedAccessException
or ArgumentException
or NotSupportedException
or System.Security.SecurityException
)
{
throw;
}
}

public Uri AddDatabaseToProject(Uri databasePath)
{
// Create a FileGeodatabaseConnectionPath with the name of the file geodatabase you wish to create
FileGeodatabaseConnectionPath fileGeodatabaseConnectionPath = new(databasePath);
// Create actual database in the specified Path unless already exists
try
{
Geodatabase geodatabase = SchemaBuilder.CreateGeodatabase(fileGeodatabaseConnectionPath);
geodatabase.Dispose();
}
catch (ArcGIS.Core.Data.Exceptions.GeodatabaseWorkspaceException)
{
// geodatabase already exists, do nothing
}

// Add a folder connection to a project
var parentFolder = Path.GetDirectoryName(databasePath.AbsolutePath);
if (parentFolder == null)
{
// POC: customize the exception type
throw new ArgumentException($"Invalid path: {databasePath}");
}
var fGdbName = databasePath.Segments[^1];
Item folderToAdd = ItemFactory.Instance.Create(parentFolder);
// POC: QueuedTask
QueuedTask.Run(() => Project.Current.AddItem(folderToAdd as IProjectItem));

// Add a file geodatabase or a SQLite or enterprise database connection to a project
var gdbToAdd = folderToAdd
.GetItems()
.FirstOrDefault(folderItem => folderItem.Name.Equals(fGdbName, StringComparison.Ordinal));
if (gdbToAdd is not null)
{
// POC: QueuedTask
var addedGeodatabase = QueuedTask.Run(() => Project.Current.AddItem(gdbToAdd as IProjectItem));
}

return databasePath;
}
}

// POC: Suppressed naming warning for now, but we should evaluate if we should follow this or disable it.
[SuppressMessage(
"Naming",
"CA1711:Identifiers should not have incorrect suffix",
Justification = "Name ends in Stack but it is in fact a Stack, just not inheriting from `System.Collections.Stack`"
)]
public class ArcGISConversionContextStack : ConversionContextStack<Map, Unit>
public class ArcGISConversionContextStack : ConversionContextStack<ArcGISDocument, ACG.Unit>
{
public ArcGISConversionContextStack(IHostToSpeckleUnitConverter<Unit> unitConverter)
: base(MapView.Active.Map, MapView.Active.Map.SpatialReference.Unit, unitConverter) { }
public ArcGISConversionContextStack(
IHostToSpeckleUnitConverter<ACG.Unit> unitConverter,
ArcGISDocument arcGisDocument
)
: base(arcGisDocument, MapView.Active.Map.SpatialReference.Unit, unitConverter) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@
using Objects.GIS;
using ArcGIS.Core.Data.Raster;
using Speckle.Converters.Common;
using ArcGIS.Desktop.Mapping;
using ArcGIS.Core.Geometry;

namespace Speckle.Converters.ArcGIS3.Features;

public class GisRasterToSpeckleConverter : ITypedConverter<Raster, RasterElement>
{
private readonly ITypedConverter<ArcGIS.Core.Geometry.Geometry, IReadOnlyList<Base>> _geometryConverter;
private readonly IConversionContextStack<Map, Unit> _contextStack;
private readonly ITypedConverter<ACG.Geometry, IReadOnlyList<Base>> _geometryConverter;
private readonly IConversionContextStack<ArcGISDocument, ACG.Unit> _contextStack;

public GisRasterToSpeckleConverter(
ITypedConverter<ArcGIS.Core.Geometry.Geometry, IReadOnlyList<Base>> geometryConverter,
IConversionContextStack<Map, Unit> contextStack
IConversionContextStack<ArcGISDocument, ACG.Unit> contextStack
)
{
_geometryConverter = geometryConverter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
using Speckle.Converters.Common.Objects;
using Speckle.Converters.Common;
using ArcGIS.Desktop.Mapping;
using Speckle.Core.Models;
using Speckle.Converters.ArcGIS3.Geometry;

namespace Speckle.Converters.ArcGIS3.Features;

public class MultipatchFeatureToSpeckleConverter : ITypedConverter<ACG.Multipatch, IReadOnlyList<Base>>
{
private readonly IConversionContextStack<Map, ACG.Unit> _contextStack;
private readonly IConversionContextStack<ArcGISDocument, ACG.Unit> _contextStack;
private readonly ITypedConverter<ACG.MapPoint, SOG.Point> _pointConverter;

public MultipatchFeatureToSpeckleConverter(
IConversionContextStack<Map, ACG.Unit> contextStack,
IConversionContextStack<ArcGISDocument, ACG.Unit> contextStack,
ITypedConverter<ACG.MapPoint, SOG.Point> pointConverter
)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using Speckle.Converters.Common.Objects;
using Speckle.Core.Models;
using Speckle.Converters.Common;
using ArcGIS.Desktop.Mapping;

namespace Speckle.Converters.ArcGIS3.Features;

[NameAndRankValue(nameof(ACG.MapPoint), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK)]
public class PointFeatureToSpeckleConverter : IToSpeckleTopLevelConverter, ITypedConverter<ACG.MapPoint, Base>
{
private readonly IConversionContextStack<Map, ACG.Unit> _contextStack;
private readonly IConversionContextStack<ArcGISDocument, ACG.Unit> _contextStack;

public PointFeatureToSpeckleConverter(IConversionContextStack<Map, ACG.Unit> contextStack)
public PointFeatureToSpeckleConverter(IConversionContextStack<ArcGISDocument, ACG.Unit> contextStack)
{
_contextStack = contextStack;
}
Expand All @@ -20,12 +19,12 @@ public PointFeatureToSpeckleConverter(IConversionContextStack<Map, ACG.Unit> con
public Base Convert(ACG.MapPoint target)
{
if (
ACG.GeometryEngine.Instance.Project(target, _contextStack.Current.Document.SpatialReference)
ACG.GeometryEngine.Instance.Project(target, _contextStack.Current.Document.Map.SpatialReference)
is not ACG.MapPoint reprojectedPt
)
{
throw new SpeckleConversionException(
$"Conversion to Spatial Reference {_contextStack.Current.Document.SpatialReference} failed"
$"Conversion to Spatial Reference {_contextStack.Current.Document.Map.SpatialReference} failed"
);
}
List<Base> geometry =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using ArcGIS.Desktop.Mapping;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;

Expand All @@ -7,11 +6,11 @@ namespace Speckle.Converters.ArcGIS3.Features;
public class PolyineFeatureToSpeckleConverter : ITypedConverter<ACG.Polyline, IReadOnlyList<SOG.Polyline>>
{
private readonly ITypedConverter<ACG.ReadOnlySegmentCollection, SOG.Polyline> _segmentConverter;
private readonly IConversionContextStack<Map, ACG.Unit> _contextStack;
private readonly IConversionContextStack<ArcGISDocument, ACG.Unit> _contextStack;

public PolyineFeatureToSpeckleConverter(
ITypedConverter<ACG.ReadOnlySegmentCollection, SOG.Polyline> segmentConverter,
IConversionContextStack<Map, ACG.Unit> contextStack
IConversionContextStack<ArcGISDocument, ACG.Unit> contextStack
)
{
_segmentConverter = segmentConverter;
Expand All @@ -27,8 +26,8 @@ public PolyineFeatureToSpeckleConverter(
// segmentize the polylines with curves using precision value of the Map's Spatial Reference
if (target.HasCurves is true)
{
double tolerance = _contextStack.Current.Document.SpatialReference.XYTolerance;
double conversionFactorToMeter = _contextStack.Current.Document.SpatialReference.Unit.ConversionFactor;
double tolerance = _contextStack.Current.Document.Map.SpatialReference.XYTolerance;
double conversionFactorToMeter = _contextStack.Current.Document.Map.SpatialReference.Unit.ConversionFactor;
var densifiedPolyline = ACG.GeometryEngine.Instance.DensifyByDeviation(
target,
tolerance * conversionFactorToMeter
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
using ArcGIS.Core.Geometry;
using Speckle.Converters.Common.Objects;
using Speckle.Converters.Common;
using ArcGIS.Desktop.Mapping;
using Objects.Primitive;

namespace Speckle.Converters.ArcGIS3.Geometry;

public class EnvelopToSpeckleConverter : ITypedConverter<Envelope, SOG.Box>
{
private readonly IConversionContextStack<Map, Unit> _contextStack;
private readonly IConversionContextStack<ArcGISDocument, Unit> _contextStack;
private readonly ITypedConverter<MapPoint, SOG.Point> _pointConverter;

public EnvelopToSpeckleConverter(
IConversionContextStack<Map, Unit> contextStack,
IConversionContextStack<ArcGISDocument, Unit> contextStack,
ITypedConverter<MapPoint, SOG.Point> pointConverter
)
{
Expand All @@ -26,13 +25,13 @@ public SOG.Box Convert(Envelope target)
target.XMin,
target.YMin,
target.ZMin,
_contextStack.Current.Document.SpatialReference
_contextStack.Current.Document.Map.SpatialReference
).ToGeometry();
MapPoint pointMax = new MapPointBuilderEx(
target.XMax,
target.YMax,
target.ZMax,
_contextStack.Current.Document.SpatialReference
_contextStack.Current.Document.Map.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
@@ -1,4 +1,3 @@
using ArcGIS.Desktop.Mapping;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Core.Kits;
Expand All @@ -10,11 +9,11 @@ namespace Speckle.Converters.ArcGIS3.Geometry.ISpeckleObjectToHost;
public class CircleToHostConverter : IToHostTopLevelConverter, ITypedConverter<SOG.Circle, ACG.Polyline>
{
private readonly ITypedConverter<SOG.Point, ACG.MapPoint> _pointConverter;
private readonly IConversionContextStack<Map, ACG.Unit> _contextStack;
private readonly IConversionContextStack<ArcGISDocument, ACG.Unit> _contextStack;

public CircleToHostConverter(
ITypedConverter<SOG.Point, ACG.MapPoint> pointConverter,
IConversionContextStack<Map, ACG.Unit> contextStack
IConversionContextStack<ArcGISDocument, ACG.Unit> contextStack
)
{
_pointConverter = pointConverter;
Expand Down
Loading

0 comments on commit 3191365

Please sign in to comment.