-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathArcGISConversionSettingsFactory.cs
166 lines (147 loc) · 5.5 KB
/
ArcGISConversionSettingsFactory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
using ArcGIS.Core.Data;
using ArcGIS.Core.Data.DDL;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Mapping;
using Speckle.Converters.ArcGIS3.Utils;
using Speckle.Converters.Common;
using Speckle.InterfaceGenerator;
using Speckle.Sdk.Logging;
namespace Speckle.Converters.ArcGIS3;
[GenerateAutoInterface]
public class ArcGISConversionSettingsFactory(IHostToSpeckleUnitConverter<ACG.Unit> unitConverter)
: IArcGISConversionSettingsFactory
{
public ArcGISConversionSettings Create(Project project, Map map, CRSoffsetRotation activeCRSoffsetRotation) =>
new(
project,
map,
EnsureOrAddSpeckleDatabase(),
activeCRSoffsetRotation,
unitConverter.ConvertOrThrow(activeCRSoffsetRotation.SpatialReference.Unit)
);
public Uri EnsureOrAddSpeckleDatabase()
{
return AddDatabaseToProject(GetDatabasePath());
}
private const string FGDB_NAME = "Speckle.gdb";
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);
Uri firstDatabasePath = new Uri($"{fGdbPath}/{FGDB_NAME}");
Uri databasePath = ValidateDatabasePath(firstDatabasePath);
return databasePath;
}
catch (Exception ex)
when (ex
is IOException
or UnauthorizedAccessException
or ArgumentException
or NotSupportedException
or System.Security.SecurityException
)
{
throw;
}
}
public Uri ValidateDatabasePath(Uri originalGatabasePath)
{
var fGdbName = originalGatabasePath.Segments[^1];
// Uri.AbsolutePath will return escaped string (replacing spaces), we need them back via .UnescapeDataString
var parentFolder = Uri.UnescapeDataString(
Path.GetDirectoryName(originalGatabasePath.AbsolutePath)
?? throw new ArgumentException($"Invalid path: {originalGatabasePath}")
);
Uri databasePath = originalGatabasePath;
Item folderToAdd = ItemFactory.Instance.Create(parentFolder);
if (folderToAdd is null)
{
// ArcGIS API doesn't show it as nullable, but it is
// Likely the project location is inaccessible with not enough permissions
// Store inside Speckle folder
string speckleFolder = SpecklePathProvider.UserSpeckleFolderPath; //Path.GetTempPath();
// create folder in Speckle repo
string speckleArcgisFolder = Path.Join(speckleFolder, $"ArcGIS_gdb");
bool existsArcgisFolder = Directory.Exists(speckleArcgisFolder);
if (!existsArcgisFolder)
{
Directory.CreateDirectory(speckleArcgisFolder);
}
// create a project-specific folder
string projectFolderName;
string? folderContainingProject = Path.GetDirectoryName(parentFolder);
if (folderContainingProject == null)
{
projectFolderName = "default";
}
else
{
projectFolderName = Path.GetRelativePath(folderContainingProject, parentFolder);
}
string tempParentFolder = Path.Join(speckleArcgisFolder, $"{projectFolderName}");
bool exists = Directory.Exists(tempParentFolder);
if (!exists)
{
Directory.CreateDirectory(tempParentFolder);
}
// repeat: try adding a folder item again
folderToAdd = ItemFactory.Instance.Create(tempParentFolder);
if (folderToAdd is null)
{
throw new ArgumentException(
$"Project path: '{parentFolder}' and Temp folder: '{tempParentFolder}' likely don't have write permissions."
);
}
databasePath = new Uri(Path.Join(tempParentFolder, fGdbName), UriKind.Absolute);
}
// 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
}
return databasePath;
}
public Uri AddDatabaseToProject(Uri databasePath)
{
// Add a folder connection to a project
// Uri.AbsolutePath will return escaped string (replacing spaces), we need them back via .UnescapeDataString
var parentFolder = Uri.UnescapeDataString(
Path.GetDirectoryName(databasePath.AbsolutePath) ?? throw new ArgumentException($"Invalid path: {databasePath}")
);
var fGdbName = databasePath.Segments[^1];
Item folderToAdd = ItemFactory.Instance.Create(parentFolder);
Project.Current.AddItem(folderToAdd as IProjectItem);
// Add a file geodatabase or a SQLite or enterprise database connection to a project
try
{
var gdbToAdd = folderToAdd
.GetItems()
.FirstOrDefault(folderItem => folderItem.Name.Equals(fGdbName, StringComparison.Ordinal));
if (gdbToAdd is not null)
{
var addedGeodatabase = Project.Current.AddItem(gdbToAdd as IProjectItem);
}
}
catch (NullReferenceException ex)
{
throw new InvalidOperationException(
"Make sure your ArcGIS Pro project folder has permissions to create a new database. E.g., project cannot be saved in a Google Drive folder.",
ex
);
}
return databasePath;
}
}