From 38565575057cf350b942818268d8701e006f5f2c Mon Sep 17 00:00:00 2001 From: Christine White Date: Mon, 2 May 2016 11:16:08 -0700 Subject: [PATCH] Dev (#124) Dev - 10.4 release has been posted to ArcGIS Online; need to now sync up dev branch to master branch and tag master as 10.4 release --- .../OSMClassExtension.csproj | 22 +- .../OSMClassExtensionManager.cs | 2 +- .../OSMClassExtensionStrings.Designer.cs | 13 +- src/OSMClassExtension/OSMUtility.cs | 62 +- .../OpenStreetMapClassExtension.cs | 18 +- .../Properties/AssemblyInfo.cs | 2 +- src/OSMClassExtension/SqlFormatter.cs | 2 +- src/OSMClassExtension/osm_v0_6.cs | 2 +- src/OSMClassExtension64/ComReleaser.cs | 2 +- .../OSMClassExtension64.csproj | 39 +- src/OSMEditor/BasicAuthenticationCtrl.cs | 2 +- src/OSMEditor/Editor.csproj | 12 +- src/OSMEditor/LicenseAlertDialog.cs | 2 +- src/OSMEditor/OSMConflictEditor.cs | 2 +- src/OSMEditor/OSMConflictEditorUI.cs | 2 +- src/OSMEditor/OSMEditorExtension.cs | 2 +- src/OSMEditor/OSMEditorPropertyPage.cs | 2 +- src/OSMEditor/OSMEditorToolbar.cs | 2 +- src/OSMEditor/OSMEditorToolbarCmd.cs | 2 +- src/OSMEditor/OSMFeatureInspector.cs | 2 +- .../OSMFeatureInspectorStrings.Designer.cs | 133 +- src/OSMEditor/OSMFeaturesProperties.xml | 2 +- src/OSMEditor/Properties/AssemblyInfo.cs | 2 +- src/OSMEditor/packages.config | 2 +- .../AuthenticationDataTypeFactory.cs | 2 +- src/OSMGeoProcessing/GPCombineLayers.cs | 2 +- src/OSMGeoProcessing/GPCopyLayerExtensions.cs | 2 +- src/OSMGeoProcessing/GeoProcessing.csproj | 12 +- src/OSMGeoProcessing/HttpBasicDataType.cs | 2 +- src/OSMGeoProcessing/HttpBasicGPValue.cs | 2 +- src/OSMGeoProcessing/OSMGPAddExtension.cs | 2 +- .../OSMGPAttributeSelector.cs | 2 +- .../OSMGPCombineAttributes.cs | 2 +- .../OSMGPCreateNetworkDataset.cs | 2 +- src/OSMGeoProcessing/OSMGPDiffLoader.cs | 2 +- src/OSMGeoProcessing/OSMGPDownload.cs | 89 +- src/OSMGeoProcessing/OSMGPExport2OSM.cs | 2 +- src/OSMGeoProcessing/OSMGPFactory.cs | 81 +- .../OSMGPFeatureComparison.cs | 2 +- src/OSMGeoProcessing/OSMGPFileLoader.cs | 183 +- src/OSMGeoProcessing/OSMGPMultiLoader.cs | 1084 +++ src/OSMGeoProcessing/OSMGPNodeLoader.cs | 308 + src/OSMGeoProcessing/OSMGPRelationLoader.cs | 425 ++ src/OSMGeoProcessing/OSMGPRemoveExtension.cs | 2 +- src/OSMGeoProcessing/OSMGPSymbolizer.cs | 2 +- src/OSMGeoProcessing/OSMGPToolsStrings.resx | 156 + src/OSMGeoProcessing/OSMGPToolsStrings.txt | 55 +- src/OSMGeoProcessing/OSMGPUpload.cs | 8 +- src/OSMGeoProcessing/OSMGPWayLoader.cs | 383 ++ src/OSMGeoProcessing/OSMToolHelper.cs | 5911 +++++++++++++---- .../Properties/AssemblyInfo.cs | 2 +- .../gp_documentation/osmgpmultiloader.xml | 50 + .../gp_documentation/osmgpnodeloader.xml | 14 + .../gp_documentation/osmgprelationloader.xml | 24 + .../gp_documentation/osmgpwayloader.xml | 20 + .../OSMGeoprocessing64.csproj | 67 +- src/OSMUtilities/OSMUtilities.csproj | 5 +- src/OSMUtilities/Properties/AssemblyInfo.cs | 2 +- src/OSMUtilities/SyncState.cs | 2 +- src/OSMUtilities64/OSMUtilities64.csproj | 4 +- src/buildLanguages.bat | 2 +- src/data/OpenStreetMap Toolbox.tbx | Bin 52709888 -> 52715008 bytes src/data/download_using_xapi.py | 154 +- 63 files changed, 7674 insertions(+), 1728 deletions(-) create mode 100644 src/OSMGeoProcessing/OSMGPMultiLoader.cs create mode 100644 src/OSMGeoProcessing/OSMGPNodeLoader.cs create mode 100644 src/OSMGeoProcessing/OSMGPRelationLoader.cs create mode 100644 src/OSMGeoProcessing/OSMGPWayLoader.cs create mode 100644 src/OSMGeoProcessing/gp_documentation/osmgpmultiloader.xml create mode 100644 src/OSMGeoProcessing/gp_documentation/osmgpnodeloader.xml create mode 100644 src/OSMGeoProcessing/gp_documentation/osmgprelationloader.xml create mode 100644 src/OSMGeoProcessing/gp_documentation/osmgpwayloader.xml diff --git a/src/OSMClassExtension/OSMClassExtension.csproj b/src/OSMClassExtension/OSMClassExtension.csproj index 95e7e11..e74a73c 100644 --- a/src/OSMClassExtension/OSMClassExtension.csproj +++ b/src/OSMClassExtension/OSMClassExtension.csproj @@ -10,7 +10,7 @@ Properties ESRI.ArcGIS.OSM.OSMClassExtension OSMClassExtension - v3.5 + v4.5 512 @@ -52,6 +52,7 @@ AllRules.ruleset false x86 + false pdbonly @@ -62,43 +63,44 @@ 4 AllRules.ruleset false + false False - True + False False - True + False False - True + False False - True + False False - True + False False - True + False False - True + False False - True + False False - True + False False diff --git a/src/OSMClassExtension/OSMClassExtensionManager.cs b/src/OSMClassExtension/OSMClassExtensionManager.cs index 8af04c9..25050a3 100644 --- a/src/OSMClassExtension/OSMClassExtensionManager.cs +++ b/src/OSMClassExtension/OSMClassExtensionManager.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMClassExtension/OSMClassExtensionStrings.Designer.cs b/src/OSMClassExtension/OSMClassExtensionStrings.Designer.cs index e05913e..1a97c13 100644 --- a/src/OSMClassExtension/OSMClassExtensionStrings.Designer.cs +++ b/src/OSMClassExtension/OSMClassExtensionStrings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.237 +// Runtime Version:4.0.30319.18408 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -79,12 +79,21 @@ internal static string OSMClassExtension_FeatureInspector_pointnumber_exceeeded_ } /// - /// Looks up a localized string similar to Unable to get an exclusive schema lock due to an existing lock on [{0}] by user [{1}].. + /// Looks up a localized string similar to Unable to get an exclusive schema lock due to an existing lock on [{0}] by user [{1}]. . /// internal static string OSMClassExtensionManager_Exclusive_Lock_Exception { get { return ResourceManager.GetString("OSMClassExtensionManager_Exclusive_Lock_Exception", resourceCulture); } } + + /// + /// Looks up a localized string similar to Unable to acquire existing schema lock type.. + /// + internal static string OSMClassExtensionManager_Reading_Lock_Exception { + get { + return ResourceManager.GetString("OSMClassExtensionManager_Reading_Lock_Exception", resourceCulture); + } + } } } diff --git a/src/OSMClassExtension/OSMUtility.cs b/src/OSMClassExtension/OSMUtility.cs index eeda199..e372599 100644 --- a/src/OSMClassExtension/OSMUtility.cs +++ b/src/OSMClassExtension/OSMUtility.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. @@ -462,48 +462,52 @@ public tag[] retrieveOSMTags(IRow row, int osmTagFieldIndex, IWorkspace workspac } IEnumDomain enumDomain = workspaceDomains.Domains; - enumDomain.Reset(); - IDomain currentDomain = enumDomain.Next(); - while (currentDomain != null) + if (enumDomain != null) { - int extensionPosition = currentDomain.Name.IndexOf(extensionString); + enumDomain.Reset(); + IDomain currentDomain = enumDomain.Next(); - // only check the attributes that are relevant for the current geometry type - if (extensionPosition > 0) + while (currentDomain != null) { - string attributeName = currentDomain.Name.Substring(0, extensionPosition); - int attributefieldIndex = row.Fields.FindField(attributeName); + int extensionPosition = currentDomain.Name.IndexOf(extensionString); - if (attributefieldIndex > -1) + // only check the attributes that are relevant for the current geometry type + if (extensionPosition > 0) { - object attributeValue = row.get_Value(attributefieldIndex); + string attributeName = currentDomain.Name.Substring(0, extensionPosition); + int attributefieldIndex = row.Fields.FindField(attributeName); - if (attributeValue != DBNull.Value) + if (attributefieldIndex > -1) { - // check if the current attribute value is already in the tag listing - if (tagDictionary.ContainsKey(attributeName) == false) - { - // create a new tag to store - tag explicitAttributeTag = new tag(); - explicitAttributeTag.k = attributeName; - explicitAttributeTag.v = Convert.ToString(attributeValue); + object attributeValue = row.get_Value(attributefieldIndex); - if (String.IsNullOrEmpty(explicitAttributeTag.v) == false) + if (attributeValue != DBNull.Value) + { + // check if the current attribute value is already in the tag listing + if (tagDictionary.ContainsKey(attributeName) == false) { - tagDictionary.Add(attributeName, explicitAttributeTag); + // create a new tag to store + tag explicitAttributeTag = new tag(); + explicitAttributeTag.k = attributeName; + explicitAttributeTag.v = Convert.ToString(attributeValue); + + if (String.IsNullOrEmpty(explicitAttributeTag.v) == false) + { + tagDictionary.Add(attributeName, explicitAttributeTag); + } } } } } + + currentDomain = enumDomain.Next(); } - currentDomain = enumDomain.Next(); + // copy the values back into the array + retrievedTags = new tag[tagDictionary.Count]; + tagDictionary.Values.CopyTo(retrievedTags, 0); } - - // copy the values back into the array - retrievedTags = new tag[tagDictionary.Count]; - tagDictionary.Values.CopyTo(retrievedTags, 0); } return retrievedTags; } @@ -1387,6 +1391,12 @@ public bool DoesHaveKeys(way currentway) IList relevantTags = new List(); bool doesHaveKeys = false; + if (currentway == null) + throw new ArgumentNullException("currentway", "Unexpected value."); + + if (currentway.tag == null) + return doesHaveKeys; + try { string[] non_relevant = { "created_by", "source", "attribution", "note", "version", "type" }; diff --git a/src/OSMClassExtension/OpenStreetMapClassExtension.cs b/src/OSMClassExtension/OpenStreetMapClassExtension.cs index ee0b740..8627ad3 100644 --- a/src/OSMClassExtension/OpenStreetMapClassExtension.cs +++ b/src/OSMClassExtension/OpenStreetMapClassExtension.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. @@ -2994,6 +2994,22 @@ private IPointCollection checkAllPoints(IFeature newlyCreatedFeature, IFeatureCl foundFeature.Store(); } + else if (!comparison && action.ToLower(CultureInfo.InvariantCulture).Equals("create")) + { + // for split the new higher-order geometry contains the (existing) nodes but it will also + // be deleted later-on due to the split behavior + // update the ref count on the node + if (pointwayRefCountFieldIndex > -1) + { + int currentRefCount = Convert.ToInt32(foundFeature.get_Value(pointwayRefCountFieldIndex)); + + currentRefCount = currentRefCount + 1; + foundFeature.set_Value(pointwayRefCountFieldIndex, currentRefCount); + + foundFeature.Store(); + } + } + addVertexCounter = addVertexCounter + 1; } else diff --git a/src/OSMClassExtension/Properties/AssemblyInfo.cs b/src/OSMClassExtension/Properties/AssemblyInfo.cs index 42a8616..77c4202 100644 --- a/src/OSMClassExtension/Properties/AssemblyInfo.cs +++ b/src/OSMClassExtension/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ESRI")] [assembly: AssemblyProduct("ArcGIS Editor for OpenStreetMap")] -[assembly: AssemblyCopyright("Copyright © ESRI 2010 - 2012")] +[assembly: AssemblyCopyright("Copyright © ESRI 2010 - 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/OSMClassExtension/SqlFormatter.cs b/src/OSMClassExtension/SqlFormatter.cs index fe4a916..365ad5e 100644 --- a/src/OSMClassExtension/SqlFormatter.cs +++ b/src/OSMClassExtension/SqlFormatter.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMClassExtension/osm_v0_6.cs b/src/OSMClassExtension/osm_v0_6.cs index eaf7f78..17268d2 100644 --- a/src/OSMClassExtension/osm_v0_6.cs +++ b/src/OSMClassExtension/osm_v0_6.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMClassExtension64/ComReleaser.cs b/src/OSMClassExtension64/ComReleaser.cs index a896a60..7094eca 100644 --- a/src/OSMClassExtension64/ComReleaser.cs +++ b/src/OSMClassExtension64/ComReleaser.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMClassExtension64/OSMClassExtension64.csproj b/src/OSMClassExtension64/OSMClassExtension64.csproj index 3b10bf0..ff89bf5 100644 --- a/src/OSMClassExtension64/OSMClassExtension64.csproj +++ b/src/OSMClassExtension64/OSMClassExtension64.csproj @@ -10,7 +10,7 @@ Properties ESRI.ArcGIS.OSM.OSMClassExtension OSMClassExtension64 - v3.5 + v4.5 512 false @@ -21,6 +21,7 @@ + true @@ -32,6 +33,7 @@ 4 x64 false + false pdbonly @@ -40,49 +42,48 @@ TRACE prompt 4 + false - - False + True - False - + False - True + False False - + False - True + False False - + False - True + False False - + False - True + False False - + False - True + False False - + False - True + False False - + False - True + False False - + False False diff --git a/src/OSMEditor/BasicAuthenticationCtrl.cs b/src/OSMEditor/BasicAuthenticationCtrl.cs index 1437f13..f693de8 100644 --- a/src/OSMEditor/BasicAuthenticationCtrl.cs +++ b/src/OSMEditor/BasicAuthenticationCtrl.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/Editor.csproj b/src/OSMEditor/Editor.csproj index e0fc6d2..31311cf 100644 --- a/src/OSMEditor/Editor.csproj +++ b/src/OSMEditor/Editor.csproj @@ -10,7 +10,7 @@ Properties ESRI.ArcGIS.OSM.Editor OSMEditor - v3.5 + v4.5 512 @@ -56,6 +56,7 @@ x86 AllRules.ruleset Off + false pdbonly @@ -66,6 +67,7 @@ 4 true AllRules.ruleset + false @@ -91,7 +93,7 @@ False - True + False False @@ -126,11 +128,11 @@ False - True + False False - True + False False @@ -149,7 +151,7 @@ 3.0 - True + False diff --git a/src/OSMEditor/LicenseAlertDialog.cs b/src/OSMEditor/LicenseAlertDialog.cs index ea9f22b..04080ad 100644 --- a/src/OSMEditor/LicenseAlertDialog.cs +++ b/src/OSMEditor/LicenseAlertDialog.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMConflictEditor.cs b/src/OSMEditor/OSMConflictEditor.cs index 8844620..0bbc31a 100644 --- a/src/OSMEditor/OSMConflictEditor.cs +++ b/src/OSMEditor/OSMConflictEditor.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMConflictEditorUI.cs b/src/OSMEditor/OSMConflictEditorUI.cs index e252946..8f2ba00 100644 --- a/src/OSMEditor/OSMConflictEditorUI.cs +++ b/src/OSMEditor/OSMConflictEditorUI.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMEditorExtension.cs b/src/OSMEditor/OSMEditorExtension.cs index 7a3aa21..e28f290 100644 --- a/src/OSMEditor/OSMEditorExtension.cs +++ b/src/OSMEditor/OSMEditorExtension.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMEditorPropertyPage.cs b/src/OSMEditor/OSMEditorPropertyPage.cs index 52e76b8..e49ad77 100644 --- a/src/OSMEditor/OSMEditorPropertyPage.cs +++ b/src/OSMEditor/OSMEditorPropertyPage.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMEditorToolbar.cs b/src/OSMEditor/OSMEditorToolbar.cs index aa594aa..3c9fede 100644 --- a/src/OSMEditor/OSMEditorToolbar.cs +++ b/src/OSMEditor/OSMEditorToolbar.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMEditorToolbarCmd.cs b/src/OSMEditor/OSMEditorToolbarCmd.cs index b34929b..3b07d83 100644 --- a/src/OSMEditor/OSMEditorToolbarCmd.cs +++ b/src/OSMEditor/OSMEditorToolbarCmd.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMFeatureInspector.cs b/src/OSMEditor/OSMFeatureInspector.cs index c0abd21..9bef9ef 100644 --- a/src/OSMEditor/OSMFeatureInspector.cs +++ b/src/OSMEditor/OSMFeatureInspector.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMEditor/OSMFeatureInspectorStrings.Designer.cs b/src/OSMEditor/OSMFeatureInspectorStrings.Designer.cs index 8a79e54..f29d1e6 100644 --- a/src/OSMEditor/OSMFeatureInspectorStrings.Designer.cs +++ b/src/OSMEditor/OSMFeatureInspectorStrings.Designer.cs @@ -1,13 +1,4 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.431 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - + namespace ESRI.ArcGIS.OSM.Editor { using System; @@ -60,6 +51,24 @@ internal OSMFeatureInspectorStrings() { } } + /// + /// Looks up a localized string similar to Password. + /// + internal static string OSMEditor_Authentication_UI_labelpassword { + get { + return ResourceManager.GetString("OSMEditor_Authentication_UI_labelpassword", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User name. + /// + internal static string OSMEditor_Authentication_UI_labelusername { + get { + return ResourceManager.GetString("OSMEditor_Authentication_UI_labelusername", resourceCulture); + } + } + /// /// Looks up a localized string similar to OSM Conflict Editor. /// @@ -168,6 +177,24 @@ internal static string OSMEditor_ConflictEditor_formtitle { } } + /// + /// Looks up a localized string similar to Conflict Operation. + /// + internal static string OSMEditor_ConflictEditor_genericConflictOpMessage { + get { + return ResourceManager.GetString("OSMEditor_ConflictEditor_genericConflictOpMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Local OSM Feature. + /// + internal static string OSMEditor_ConflictEditor_localOSMFeature_header { + get { + return ResourceManager.GetString("OSMEditor_ConflictEditor_localOSMFeature_header", resourceCulture); + } + } + /// /// Looks up a localized string similar to Open the OpenStreetMap Conflict Editor. /// @@ -195,6 +222,15 @@ internal static string OSMEditor_ConflictEditor_norevisionTables_title { } } + /// + /// Looks up a localized string similar to OSM Attributes. + /// + internal static string OSMEditor_ConflictEditor_osmattributes_header { + get { + return ResourceManager.GetString("OSMEditor_ConflictEditor_osmattributes_header", resourceCulture); + } + } + /// /// Looks up a localized string similar to Line. /// @@ -249,6 +285,15 @@ internal static string OSMEditor_ConflictEditor_prepareCollectData { } } + /// + /// Looks up a localized string similar to Server OSM Feature. + /// + internal static string OSMEditor_ConflictEditor_serverOSMFeature_header { + get { + return ResourceManager.GetString("OSMEditor_ConflictEditor_serverOSMFeature_header", resourceCulture); + } + } + /// /// Looks up a localized string similar to Open the OpenStreetMap Conflict Editor. /// @@ -295,7 +340,7 @@ internal static string OSMEditor_FeatureInspector_multipart { } /// - /// Looks up a localized string similar to The feature (OSMID: {0}) you are attempting to change is a member of relation ({1}). Please change the corresponding top level geometry instead.. + /// Looks up a localized string similar to The feature (OSMID: {0}) you are attempting to change is a member of relation ({1}). This action is currently not supported and the edit operation is aborted.. /// internal static string OSMEditor_FeatureInspector_multipartchangeconflictmessage { get { @@ -304,7 +349,16 @@ internal static string OSMEditor_FeatureInspector_multipartchangeconflictmessage } /// - /// Looks up a localized string similar to The feature (OSMID: {0}) you are attempting to delete is a member of relation ({1}). Please change the corresponding top level geometry instead.. + /// Looks up a localized string similar to The feature (OSMID: {0}) you are attempting to change is a relation. This action is currently not supported and the edit operation is aborted.. + /// + internal static string OSMEditor_FeatureInspector_multipartchangeparentconflictmessage { + get { + return ResourceManager.GetString("OSMEditor_FeatureInspector_multipartchangeparentconflictmessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The feature (OSMID: {0}) you are attempting to delete is a member of relation ({1}). This action is currently not supported and the edit operation is aborted.. /// internal static string OSMEditor_FeatureInspector_multipartdeleteconflictmessage { get { @@ -313,7 +367,43 @@ internal static string OSMEditor_FeatureInspector_multipartdeleteconflictmessage } /// - /// Looks up a localized string similar to Point ID: . + /// Looks up a localized string similar to The feature (OSMID: {0}) you are attempting to delete is a relation. This action is currently not supported and the edit operation is aborted.. + /// + internal static string OSMEditor_FeatureInspector_multipartdeleteparentconflictmessage { + get { + return ResourceManager.GetString("OSMEditor_FeatureInspector_multipartdeleteparentconflictmessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OSM Attribute Change. + /// + internal static string OSMEditor_FeatureInspector_operationmenu { + get { + return ResourceManager.GetString("OSMEditor_FeatureInspector_operationmenu", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Edit operation in progress. + /// + internal static string OSMEditor_FeatureInspector_operationwarningcaption { + get { + return ResourceManager.GetString("OSMEditor_FeatureInspector_operationwarningcaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You need to finish the current operation first, before you can change any attributes. . + /// + internal static string OSMEditor_FeatureInspector_operationwarningtext { + get { + return ResourceManager.GetString("OSMEditor_FeatureInspector_operationwarningtext", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Point ID:. /// internal static string OSMEditor_FeatureInspector_pointidtext { get { @@ -321,6 +411,15 @@ internal static string OSMEditor_FeatureInspector_pointidtext { } } + /// + /// Looks up a localized string similar to You are attempting to delete a point that is referenced by a relation (OSMID: {0}). This action is currently not supported and the edit operation is aborted.. + /// + internal static string OSMEditor_FeatureInspector_pointmemberofrelation { + get { + return ResourceManager.GetString("OSMEditor_FeatureInspector_pointmemberofrelation", resourceCulture); + } + } + /// /// Looks up a localized string similar to The polygon geometry exceeds the number of allowed points ({0}) in geometry part {1}.. /// @@ -405,11 +504,9 @@ internal static string OSMEditor_LicenseAlertDialog_Cancel { /// /// Looks up a localized string similar to /// - ///You are about to edit data that is licensed under Creative Commons Attribution-ShareAlike 2.0 from OpenStreetMap. - /// - ///When you press the OK button you are agreeing that you are the original creator for the new data and that you have all the necessary permissions should you derive (copy/trace/duplicate/import) data from existing data sources. If in doubt, please press Cancel and obtain legal advice about data licensing or post a question at the OSM legal-talk list. + ///You are about to edit data that is licensed under the Open Database License 1.0 from OpenStreetMap - see http://www.osmfoundation.org/wiki/License/Contributor_Terms. /// - ///Selecting the OK button will start yo [rest of string was truncated]";. + ///When you press the OK button you are agreeing that you are the original creator for the new data and that you have all the necessary permissions should you derive (copy/trace/duplicate/import) data from existing data sources. If in doubt, please press Cancel and obtain legal advice about data licensing or post a question at the OSM lega [rest of string was truncated]";. /// internal static string OSMEditor_LicenseAlertDialog_LicenseAlert { get { @@ -418,7 +515,7 @@ internal static string OSMEditor_LicenseAlertDialog_LicenseAlert { } /// - /// Looks up a localized string similar to 53,44,http://creativecommons.org/licenses/by-sa/2.0/;103,13,http://www.openstreetmap.org;454,11,http://lists.openstreetmap.org/listinfo/legal-talk. + /// Looks up a localized string similar to 109,59,http://www.osmfoundation.org/wiki/License/Contributor_Terms;503,15,http://lists.openstreetmap.org/listinfo/legal-talk. /// internal static string OSMEditor_LicenseAlertDialog_LicenseAlertLink { get { diff --git a/src/OSMEditor/OSMFeaturesProperties.xml b/src/OSMEditor/OSMFeaturesProperties.xml index 108833f..9859687 100644 --- a/src/OSMEditor/OSMFeaturesProperties.xml +++ b/src/OSMEditor/OSMFeaturesProperties.xml @@ -1686,7 +1686,7 @@ - + diff --git a/src/OSMEditor/Properties/AssemblyInfo.cs b/src/OSMEditor/Properties/AssemblyInfo.cs index 8765a59..b727507 100644 --- a/src/OSMEditor/Properties/AssemblyInfo.cs +++ b/src/OSMEditor/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ESRI")] [assembly: AssemblyProduct("ArcGIS Editor for OpenStreetMap")] -[assembly: AssemblyCopyright("Copyright © ESRI 2010 - 2012")] +[assembly: AssemblyCopyright("Copyright © ESRI 2010 - 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/OSMEditor/packages.config b/src/OSMEditor/packages.config index 1be7e32..dbc27f5 100644 --- a/src/OSMEditor/packages.config +++ b/src/OSMEditor/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/OSMGeoProcessing/AuthenticationDataTypeFactory.cs b/src/OSMGeoProcessing/AuthenticationDataTypeFactory.cs index 04b63ac..d840f62 100644 --- a/src/OSMGeoProcessing/AuthenticationDataTypeFactory.cs +++ b/src/OSMGeoProcessing/AuthenticationDataTypeFactory.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/GPCombineLayers.cs b/src/OSMGeoProcessing/GPCombineLayers.cs index 119ab05..fc989af 100644 --- a/src/OSMGeoProcessing/GPCombineLayers.cs +++ b/src/OSMGeoProcessing/GPCombineLayers.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/GPCopyLayerExtensions.cs b/src/OSMGeoProcessing/GPCopyLayerExtensions.cs index 65f6054..d7456f2 100644 --- a/src/OSMGeoProcessing/GPCopyLayerExtensions.cs +++ b/src/OSMGeoProcessing/GPCopyLayerExtensions.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/GeoProcessing.csproj b/src/OSMGeoProcessing/GeoProcessing.csproj index 3b563fa..acf8c24 100644 --- a/src/OSMGeoProcessing/GeoProcessing.csproj +++ b/src/OSMGeoProcessing/GeoProcessing.csproj @@ -10,7 +10,7 @@ Properties ESRI.ArcGIS.OSM.GeoProcessing OSMGeoProcessing - v3.5 + v4.5 512 @@ -50,10 +50,11 @@ DEBUG;TRACE prompt 4 - false + true x86 false false + false pdbonly @@ -62,8 +63,9 @@ TRACE prompt 4 - false + true AllRules.ruleset + false @@ -147,11 +149,15 @@ + + + + diff --git a/src/OSMGeoProcessing/HttpBasicDataType.cs b/src/OSMGeoProcessing/HttpBasicDataType.cs index bb4fd2c..46e0b8c 100644 --- a/src/OSMGeoProcessing/HttpBasicDataType.cs +++ b/src/OSMGeoProcessing/HttpBasicDataType.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/HttpBasicGPValue.cs b/src/OSMGeoProcessing/HttpBasicGPValue.cs index d18d6c4..0f5dbda 100644 --- a/src/OSMGeoProcessing/HttpBasicGPValue.cs +++ b/src/OSMGeoProcessing/HttpBasicGPValue.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPAddExtension.cs b/src/OSMGeoProcessing/OSMGPAddExtension.cs index 7335d08..57a0a4f 100644 --- a/src/OSMGeoProcessing/OSMGPAddExtension.cs +++ b/src/OSMGeoProcessing/OSMGPAddExtension.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPAttributeSelector.cs b/src/OSMGeoProcessing/OSMGPAttributeSelector.cs index 0a08f54..5c73ae7 100644 --- a/src/OSMGeoProcessing/OSMGPAttributeSelector.cs +++ b/src/OSMGeoProcessing/OSMGPAttributeSelector.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPCombineAttributes.cs b/src/OSMGeoProcessing/OSMGPCombineAttributes.cs index e8d165e..1a41361 100644 --- a/src/OSMGeoProcessing/OSMGPCombineAttributes.cs +++ b/src/OSMGeoProcessing/OSMGPCombineAttributes.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPCreateNetworkDataset.cs b/src/OSMGeoProcessing/OSMGPCreateNetworkDataset.cs index 429ed7f..0dc25a0 100644 --- a/src/OSMGeoProcessing/OSMGPCreateNetworkDataset.cs +++ b/src/OSMGeoProcessing/OSMGPCreateNetworkDataset.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPDiffLoader.cs b/src/OSMGeoProcessing/OSMGPDiffLoader.cs index 2903c97..4c9f7bd 100644 --- a/src/OSMGeoProcessing/OSMGPDiffLoader.cs +++ b/src/OSMGeoProcessing/OSMGPDiffLoader.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPDownload.cs b/src/OSMGeoProcessing/OSMGPDownload.cs index c9e71db..29cd7b7 100644 --- a/src/OSMGeoProcessing/OSMGPDownload.cs +++ b/src/OSMGeoProcessing/OSMGPDownload.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. @@ -418,7 +418,7 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS } #endregion - IGPEnvironment configKeyword = getEnvironment(envMgr, "configKeyword"); + IGPEnvironment configKeyword = OSMToolHelper.getEnvironment(envMgr, "configKeyword"); IGPString gpString = null; if (configKeyword != null) gpString = configKeyword.Value as IGPString; @@ -1012,27 +1012,7 @@ private string retrieveAdditionalRelations(string osmID, ref ITrackCancel TrackC return osmDocumentLocation; } - public static IGPEnvironment getEnvironment(IGPEnvironmentManager environmentManager, string name) - { - IGPUtilities3 gpUtils = new GPUtilitiesClass(); - IGPEnvironment returnEnv = null; - try - { - if (environmentManager.GetLocalEnvironments().Count > 0) - returnEnv = gpUtils.GetEnvironment(environmentManager.GetLocalEnvironments(), name); - - if (returnEnv == null) - returnEnv = gpUtils.GetEnvironment(environmentManager.GetEnvironments(), name); - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(ex.Message); - System.Diagnostics.Debug.WriteLine(ex.StackTrace); - } - - return returnEnv; - } public ESRI.ArcGIS.esriSystem.IName FullName { @@ -1595,70 +1575,5 @@ private void parseOSMDocument(string osmFileLocation, ref IGPMessages message, r } } - - private void BuildSpatialIndex(IGPValue gpFeatureClass, Geoprocessor.Geoprocessor geoProcessor, IGPUtilities gpUtil, - ITrackCancel trackCancel, IGPMessages message) - { - if ((gpFeatureClass == null) || (geoProcessor == null) || (gpUtil == null)) - return; - - // Check if the feature class supports spatial index grids - IFeatureClass fc = gpUtil.OpenDataset(gpFeatureClass) as IFeatureClass; - if (fc == null) - return; - - int idxShapeField = fc.FindField(fc.ShapeFieldName); - if (idxShapeField >= 0) - { - IField shapeField = fc.Fields.get_Field(idxShapeField); - if (shapeField.GeometryDef.GridCount > 0) - { - if (shapeField.GeometryDef.get_GridSize(0) == -2.0) - return; - } - } - - // Create the new spatial index grid - bool storedOriginal = geoProcessor.AddOutputsToMap; - - try - { - geoProcessor.AddOutputsToMap = false; - - DataManagementTools.CalculateDefaultGridIndex calculateDefaultGridIndex = - new DataManagementTools.CalculateDefaultGridIndex(gpFeatureClass); - IGeoProcessorResult2 gpResults2 = - geoProcessor.Execute(calculateDefaultGridIndex, trackCancel) as IGeoProcessorResult2; - message.AddMessages(gpResults2.GetResultMessages()); - - if (gpResults2 != null) - { - DataManagementTools.RemoveSpatialIndex removeSpatialIndex = - new DataManagementTools.RemoveSpatialIndex(gpFeatureClass.GetAsText()); - removeSpatialIndex.out_feature_class = gpFeatureClass.GetAsText(); - gpResults2 = geoProcessor.Execute(removeSpatialIndex, trackCancel) as IGeoProcessorResult2; - message.AddMessages(gpResults2.GetResultMessages()); - - DataManagementTools.AddSpatialIndex addSpatialIndex = - new DataManagementTools.AddSpatialIndex(gpFeatureClass.GetAsText()); - addSpatialIndex.out_feature_class = gpFeatureClass.GetAsText(); - - addSpatialIndex.spatial_grid_1 = calculateDefaultGridIndex.grid_index1; - addSpatialIndex.spatial_grid_2 = calculateDefaultGridIndex.grid_index2; - addSpatialIndex.spatial_grid_3 = calculateDefaultGridIndex.grid_index3; - - gpResults2 = geoProcessor.Execute(addSpatialIndex, trackCancel) as IGeoProcessorResult2; - message.AddMessages(gpResults2.GetResultMessages()); - } - } - catch (Exception ex) - { - message.AddWarning(ex.Message); - } - finally - { - geoProcessor.AddOutputsToMap = storedOriginal; - } - } } } \ No newline at end of file diff --git a/src/OSMGeoProcessing/OSMGPExport2OSM.cs b/src/OSMGeoProcessing/OSMGPExport2OSM.cs index ccdd965..7f7604e 100644 --- a/src/OSMGeoProcessing/OSMGPExport2OSM.cs +++ b/src/OSMGeoProcessing/OSMGPExport2OSM.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPFactory.cs b/src/OSMGeoProcessing/OSMGPFactory.cs index 25fe956..8cfc872 100644 --- a/src/OSMGeoProcessing/OSMGPFactory.cs +++ b/src/OSMGeoProcessing/OSMGPFactory.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. @@ -99,6 +99,26 @@ public sealed class OSMGPFactory : ESRI.ArcGIS.Geoprocessing.IGPFunctionFactory string m_CreateNetworkDatasetCategory = "Data Management"; string m_CreateNetworkDatasetDescription = "Create a network dataset from a given OSM dataset."; + string m_MultiLoaderDisplayName = "OSM Multi Loader (Load only)"; + internal const string m_MultiLoaderName = "OSMGPMultiLoader"; + string m_MultiLoaderCategory = "Data Delivery"; + string m_MultiLoaderDescription = "Load OSM file without the metadata. Data loaded without tools cannot be uploaded back to the OSM server."; + + string m_NodeLoaderDisplayName = "OSM Node Loader"; + internal const string m_NodeLoaderName = "OSMGPNodeLoader"; + string m_NodeLoaderCategory = "Data Delivery"; + string m_NodeLoaderDescription = "Load OSM nodes."; + + string m_WayLoaderDisplayName = "OSM Way Loader"; + internal const string m_WayLoaderName = "OSMGPWayLoader"; + string m_WayLoaderCategory = "Data Delivery"; + string m_WayLoaderDescription = "Load OSM ways."; + + string m_RelationLoaderDisplayName = "OSM Relation Loader"; + internal const string m_RelationLoaderName = "OSMGPRelationLoader"; + string m_RelationLoaderCategory = "Data Delivery"; + string m_RelationLoaderDescription = "Load OSM relations."; + #region "Component Category Registration" [ComRegisterFunction()] [ComVisible(false)] @@ -202,6 +222,22 @@ public OSMGPFactory() m_CreateNetworkDatasetCategory = resourceManager.GetString("GPTools_OSMGPAttributeSelector_categoryName"); m_CreateNetworkDatasetDisplayName = resourceManager.GetString("GPTools_OSMGPCreateNetworkDataset_displayname"); m_CreateNetworkDatasetDescription = resourceManager.GetString("GPTools_OSMGPCreateNetworkDataset_desc"); + + m_MultiLoaderCategory = resourceManager.GetString("GPTools_OSMGPMultiLoader_categoryName"); + m_MultiLoaderDisplayName = resourceManager.GetString("GPTools_OSMGPMultiLoader_displayName"); + m_MultiLoaderDescription = resourceManager.GetString("GPTools_OSMGPMultiLoader_desc"); + + m_NodeLoaderCategory = resourceManager.GetString("GPTools_OSMGPNodeLoader_categoryName"); + m_NodeLoaderDisplayName = resourceManager.GetString("GPTools_OSMGPNodeLoader_displayName"); + m_NodeLoaderDescription = resourceManager.GetString("GPTools_OSMGPNodeLoader_desc"); + + m_WayLoaderCategory = resourceManager.GetString("GPTools_OSMGPWayLoader_categoryName"); + m_WayLoaderDisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_displayName"); + m_WayLoaderDescription = resourceManager.GetString("GPTools_OSMGPWayLoader_desc"); + + m_RelationLoaderCategory = resourceManager.GetString("GPTools_OSMGPRelationLoader_categoryName"); + m_RelationLoaderDisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_displayName"); + m_RelationLoaderDescription = resourceManager.GetString("GPTools_OSMGPRelationLoader_desc"); } catch (Exception ex) { @@ -275,6 +311,18 @@ public ESRI.ArcGIS.Geoprocessing.IGPFunction GetFunction(string Name) case m_CreateNetworkDatasetName: IGPFunction osmGPCreateNetworkDataset = new OSMGPCreateNetworkDataset() as IGPFunction; return osmGPCreateNetworkDataset; + case m_MultiLoaderName: + IGPFunction osmGPMultiLoader = new OSMGPMultiLoader() as IGPFunction; + return osmGPMultiLoader; + case m_NodeLoaderName: + IGPFunction osmGPNodeLoader = new OSMGPNodeLoader() as IGPFunction; + return osmGPNodeLoader; + case m_WayLoaderName: + IGPFunction osmGPWayLoader = new OSMGPWayLoader() as IGPFunction; + return osmGPWayLoader; + case m_RelationLoaderName: + IGPFunction osmGPRelationLoader = new OSMGPRelationLoader() as IGPFunction; + return osmGPRelationLoader; default: return null; } @@ -377,6 +425,30 @@ public ESRI.ArcGIS.Geodatabase.IGPName GetFunctionName(string Name) toolGPName.Category = m_CreateNetworkDatasetCategory; toolGPName.Description = m_CreateNetworkDatasetDescription; break; + case m_MultiLoaderName: + toolGPName.Name = m_MultiLoaderName; + toolGPName.DisplayName = m_MultiLoaderDisplayName; + toolGPName.Category = m_MultiLoaderCategory; + toolGPName.Description = m_MultiLoaderDescription; + break; + case m_NodeLoaderName: + toolGPName.Name = m_NodeLoaderName; + toolGPName.DisplayName = m_NodeLoaderDisplayName; + toolGPName.Category = m_NodeLoaderCategory; + toolGPName.Description = m_NodeLoaderDescription; + break; + case m_WayLoaderName: + toolGPName.Name = m_WayLoaderName; + toolGPName.DisplayName = m_WayLoaderDisplayName; + toolGPName.Category = m_WayLoaderCategory; + toolGPName.Description = m_WayLoaderDescription; + break; + case m_RelationLoaderName: + toolGPName.Name = m_RelationLoaderName; + toolGPName.DisplayName = m_RelationLoaderDisplayName; + toolGPName.Category = m_RelationLoaderCategory; + toolGPName.Description = m_RelationLoaderDescription; + break; default: return null; } @@ -401,6 +473,10 @@ public ESRI.ArcGIS.Geodatabase.IEnumGPName GetFunctionNames() allGPFunctionNames.Add(this.GetFunctionName(m_FeatureComparisonName)); allGPFunctionNames.Add(this.GetFunctionName(m_Export2OSMName)); allGPFunctionNames.Add(this.GetFunctionName(m_CreateNetworkDatasetName)); + allGPFunctionNames.Add(this.GetFunctionName(m_MultiLoaderName)); + allGPFunctionNames.Add(this.GetFunctionName(m_NodeLoaderName)); + allGPFunctionNames.Add(this.GetFunctionName(m_WayLoaderName)); + allGPFunctionNames.Add(this.GetFunctionName(m_RelationLoaderName)); return (IEnumGPName)allGPFunctionNames; } @@ -440,7 +516,6 @@ public static string GetArcGIS10InstallLocation() // Check for Desktop first foreach (RuntimeInfo item in installedRuntimes) { - if (String.Compare(item.Product.ToString(), "Desktop", true) == 0) installationDirectory = item.Path; } @@ -555,7 +630,7 @@ public static Dictionary ReadOSMEditorSettings() { if (File.Exists(executingAssembly.Directory.FullName + System.IO.Path.DirectorySeparatorChar + "OSMFeaturesProperties.xml")) { - configurationSettings.Add("osmfeatureporpertiesfilepath", executingAssembly.Directory.FullName + System.IO.Path.DirectorySeparatorChar + "OSMFeaturesProperties.xml"); + configurationSettings.Add("osmfeaturepropertiesfilepath", executingAssembly.Directory.FullName + System.IO.Path.DirectorySeparatorChar + "OSMFeaturesProperties.xml"); } } } diff --git a/src/OSMGeoProcessing/OSMGPFeatureComparison.cs b/src/OSMGeoProcessing/OSMGPFeatureComparison.cs index fa6834e..629afb2 100644 --- a/src/OSMGeoProcessing/OSMGPFeatureComparison.cs +++ b/src/OSMGeoProcessing/OSMGPFeatureComparison.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPFileLoader.cs b/src/OSMGeoProcessing/OSMGPFileLoader.cs index a5ced43..1e7e990 100644 --- a/src/OSMGeoProcessing/OSMGPFileLoader.cs +++ b/src/OSMGeoProcessing/OSMGPFileLoader.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. @@ -168,6 +168,7 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS { // the count should be zero if we encountered the "ALL" keyword // in this case count the features and create a list of unique tags + // this is a slow process process - be patient for large files attributeTags = osmToolHelper.countOSMCapacityAndTags(osmFileLocationString.GetAsText(), ref nodeCapacity, ref wayCapacity, ref relationCapacity, ref TrackCancel); } } @@ -353,12 +354,16 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory; ISpatialReference wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference; - ISpatialReference downloadSpatialReference = gpUtilities3.GetGPSpRefEnv(envMgr, wgs84, null, 0, 0, 0, 0, null); + IEnvelope storageEnvelope = new EnvelopeClass(); + storageEnvelope.SpatialReference = wgs84; + storageEnvelope.PutCoords(-180.0, -90.0, 180.0, 90.0); + + ISpatialReference downloadSpatialReference = gpUtilities3.GetGPSpRefEnv(envMgr, wgs84, storageEnvelope, 0, 0, 0, 0, null); Marshal.ReleaseComObject(wgs84); Marshal.ReleaseComObject(spatialReferenceFactory); - IGPEnvironment configKeyword = OSMGPDownload.getEnvironment(envMgr, "configKeyword"); + IGPEnvironment configKeyword = OSMToolHelper.getEnvironment(envMgr, "configKeyword"); IGPString gpString = configKeyword.Value as IGPString; string storageKeyword = String.Empty; @@ -597,114 +602,11 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS bool fastLoad = false; - //// check for user interruption - //if (TrackCancel.Continue() == false) - //{ - // message.AddAbort(resourceManager.GetString("GPTools_toolabort")); - // return; - //} - - //IFeatureCursor deleteCursor = null; - //using (ComReleaser comReleaser = new ComReleaser()) - //{ - // // let's make sure that we clean out any old data that might have existed in the feature classes - // deleteCursor = osmPointFeatureClass.Update(null, false); - // comReleaser.ManageLifetime(deleteCursor); - - // for (IFeature feature = deleteCursor.NextFeature(); feature != null; feature = deleteCursor.NextFeature()) - // { - // feature.Delete(); - - // // check for user interruption - // if (TrackCancel.Continue() == false) - // { - // message.AddAbort(resourceManager.GetString("GPTools_toolabort")); - // return; - // } - - // } - //} - - //using (ComReleaser comReleaser = new ComReleaser()) - //{ - // deleteCursor = osmLineFeatureClass.Update(null, false); - // comReleaser.ManageLifetime(deleteCursor); - - // for (IFeature feature = deleteCursor.NextFeature(); feature != null; feature = deleteCursor.NextFeature()) - // { - // feature.Delete(); - - // // check for user interruption - // if (TrackCancel.Continue() == false) - // { - // message.AddAbort(resourceManager.GetString("GPTools_toolabort")); - // return; - // } - // } - //} - - //using (ComReleaser comReleaser = new ComReleaser()) - //{ - // deleteCursor = osmPolygonFeatureClass.Update(null, false); - // comReleaser.ManageLifetime(deleteCursor); - - // for (IFeature feature = deleteCursor.NextFeature(); feature != null; feature = deleteCursor.NextFeature()) - // { - // feature.Delete(); - - // // check for user interruption - // if (TrackCancel.Continue() == false) - // { - // message.AddAbort(resourceManager.GetString("GPTools_toolabort")); - // return; - // } - // } - //} - - //ICursor tableCursor = null; - //using (ComReleaser comReleaser = new ComReleaser()) - //{ - // tableCursor = relationTable.Update(null, false); - // comReleaser.ManageLifetime(tableCursor); - - // for (IRow row = tableCursor.NextRow(); row != null; row = tableCursor.NextRow()) - // { - // row.Delete(); - - // // check for user interruption - // if (TrackCancel.Continue() == false) - // { - // message.AddAbort(resourceManager.GetString("GPTools_toolabort")); - // return; - // } - // } - //} - - //using (ComReleaser comReleaser = new ComReleaser()) - //{ - // tableCursor = revisionTable.Update(null, false); - // comReleaser.ManageLifetime(tableCursor); - - // for (IRow row = tableCursor.NextRow(); row != null; row = tableCursor.NextRow()) - // { - // row.Delete(); - - // // check for user interruption - // if (TrackCancel.Continue() == false) - // { - // message.AddAbort(resourceManager.GetString("GPTools_toolabort")); - // return; - // } - // } - //} - - // define variables helping to invoke core tools for data management - IGeoProcessorResult2 gpResults2 = null; - - IGeoProcessor2 geoProcessor = new GeoProcessorClass(); - #region load points - osmToolHelper.loadOSMNodes(osmFileLocationString.GetAsText(), ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, conserveMemoryGPValue.Value, fastLoad, Convert.ToInt32(nodeCapacity), ref osmNodeDictionary, featureWorkspace, downloadSpatialReference, availableDomains, false); + // hardcoded the value for conserving memory - TE, 11/2015 + // the reasoning here is that the speed is difference is only about 20% for smaller datasets and it shouldn't be used for larger datasets + // due to the 32bit memory limit + osmToolHelper.loadOSMNodes(osmFileLocationString.GetAsText(), ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, true, fastLoad, Convert.ToInt32(nodeCapacity), ref osmNodeDictionary, featureWorkspace, downloadSpatialReference, availableDomains, false); #endregion @@ -714,14 +616,20 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS } #region load ways - List missingWays = osmToolHelper.loadOSMWays(osmFileLocationString.GetAsText(), ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, osmLineFeatureClass, osmPolygonFeatureClass, conserveMemoryGPValue.Value, fastLoad, Convert.ToInt32(wayCapacity), ref osmNodeDictionary, featureWorkspace, downloadSpatialReference, availableDomains, false); + List missingWays = osmToolHelper.loadOSMWays(osmFileLocationString.GetAsText(), ref TrackCancel, ref message, targetDatasetGPValue, osmPointFeatureClass, osmLineFeatureClass, osmPolygonFeatureClass, true, fastLoad, Convert.ToInt32(wayCapacity), ref osmNodeDictionary, featureWorkspace, downloadSpatialReference, availableDomains, false); #endregion if (downloadSpatialReference != null) Marshal.ReleaseComObject(downloadSpatialReference); + #region for local geodatabases enforce spatial integrity + // define variables helping to invoke core tools for data management + IGeoProcessorResult2 gpResults2 = null; + + IGeoProcessor2 geoProcessor = new GeoProcessorClass(); + bool storedOriginalLocal = geoProcessor.AddOutputsToMap; geoProcessor.AddOutputsToMap = false; @@ -734,7 +642,7 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS IGPParameter outLinesParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter; IGPValue lineFeatureClass = gpUtilities3.UnpackGPValue(outLinesParameter); - DataManagementTools.RepairGeometry repairlineGeometry = new DataManagementTools.RepairGeometry(osmLineFeatureClass); + DataManagementTools.RepairGeometry repairlineGeometry = new DataManagementTools.RepairGeometry(); IVariantArray repairGeometryParameterArray = new VarArrayClass(); repairGeometryParameterArray.Add(lineFeatureClass.GetAsText()); @@ -743,6 +651,12 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS gpResults2 = geoProcessor.Execute(repairlineGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2; message.AddMessages(gpResults2.GetResultMessages()); + IVariantArray removeSpatialIndexArray = new VarArrayClass(); + removeSpatialIndexArray.Add(lineFeatureClass.GetAsText()); + + gpResults2 = geoProcessor.Execute("RemoveSpatialIndex_management", removeSpatialIndexArray, TrackCancel) as IGeoProcessorResult2; + message.AddMessages(gpResults2.GetResultMessages()); + ComReleaser.ReleaseCOMObject(gpUtilities3); } } @@ -756,7 +670,7 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS IGPParameter outPolygonParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter; IGPValue polygonFeatureClass = gpUtilities3.UnpackGPValue(outPolygonParameter); - DataManagementTools.RepairGeometry repairpolygonGeometry = new DataManagementTools.RepairGeometry(osmPolygonFeatureClass); + DataManagementTools.RepairGeometry repairpolygonGeometry = new DataManagementTools.RepairGeometry(); IVariantArray repairGeometryParameterArray = new VarArrayClass(); repairGeometryParameterArray.Add(polygonFeatureClass.GetAsText()); @@ -765,6 +679,12 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS gpResults2 = geoProcessor.Execute(repairpolygonGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2; message.AddMessages(gpResults2.GetResultMessages()); + IVariantArray removeSpatialIndexArray = new VarArrayClass(); + removeSpatialIndexArray.Add(polygonFeatureClass.GetAsText()); + + gpResults2 = geoProcessor.Execute("RemoveSpatialIndex_management", removeSpatialIndexArray, TrackCancel) as IGeoProcessorResult2; + message.AddMessages(gpResults2.GetResultMessages()); + ComReleaser.ReleaseCOMObject(gpUtilities3); } } @@ -789,29 +709,6 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS return; } - //storedOriginalLocal = geoProcessor.AddOutputsToMap; - //try - //{ - // geoProcessor.AddOutputsToMap = false; - - // // add indexes for revisions - // //IGPValue revisionTableGPValue = gpUtilities3.MakeGPValueFromObject(revisionTable); - // string revisionTableString = targetDatasetGPValue.GetAsText() + System.IO.Path.DirectorySeparatorChar + ((IDataset)revisionTable).BrowseName; - // IVariantArray parameterArrary2 = osmToolHelper.CreateAddIndexParameterArray(revisionTableString, "osmoldid;osmnewid", "osmID_IDX", "", ""); - // gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary2, TrackCancel) as IGeoProcessorResult2; - - // message.AddMessages(gpResults2.GetResultMessages()); - //} - //catch (Exception ex) - //{ - // message.AddWarning(ex.Message); - //} - //finally - //{ - // geoProcessor.AddOutputsToMap = storedOriginalLocal; - //} - - #region update the references counts and member lists for nodes message.AddMessage(resourceManager.GetString("GPTools_OSMGPFileReader_updatereferences")); @@ -1238,7 +1135,8 @@ public void UpdateMessages(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGI } } - // check one of the output feature classes for version compatibility + + //// check one of the output feature classes for version compatibility IGPParameter pointFeatureClassParameter = paramvalues.get_Element(out_osmPointsNumber) as IGPParameter; IDEFeatureClass pointDEFeatureClass = gpUtilities3.UnpackGPValue(pointFeatureClassParameter) as IDEFeatureClass; @@ -1251,12 +1149,15 @@ public void UpdateMessages(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGI IFeatureClass ptfc = gpUtilities3.Open(gpUtilities3.UnpackGPValue(pointFeatureClassParameter)) as IFeatureClass; IPropertySet osmExtensionPropertySet = ptfc.ExtensionProperties; + // TE - 01/22/2016 + // skip the anticipation of a propertyset off a feature class + // with the change from last year not to apply the extension automatically this check is confusing users more than benefitting them if (osmExtensionPropertySet == null) { - Messages.ReplaceError(out_targetDatasetNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); - Messages.ReplaceError(out_osmPointsNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); - Messages.ReplaceError(out_osmLinesNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); - Messages.ReplaceError(out_osmPolygonsNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); + // Messages.ReplaceError(out_targetDatasetNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); + // Messages.ReplaceError(out_osmPointsNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); + // Messages.ReplaceError(out_osmLinesNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); + // Messages.ReplaceError(out_osmPolygonsNumber, -5, string.Format(resourceManager.GetString("GPTools_IncompatibleExtensionVersion"), 1, OSMClassExtensionManager.Version)); } else { diff --git a/src/OSMGeoProcessing/OSMGPMultiLoader.cs b/src/OSMGeoProcessing/OSMGPMultiLoader.cs new file mode 100644 index 0000000..797f387 --- /dev/null +++ b/src/OSMGeoProcessing/OSMGPMultiLoader.cs @@ -0,0 +1,1084 @@ +// (c) Copyright Esri, 2010 - 2016 +// This source is subject to the Apache 2.0 License. +// Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. +// All other rights reserved. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Resources; +using ESRI.ArcGIS.esriSystem; +using ESRI.ArcGIS.Geoprocessing; +using ESRI.ArcGIS.DataSourcesFile; +using ESRI.ArcGIS.Geodatabase; +using ESRI.ArcGIS.OSM.OSMClassExtension; +using ESRI.ArcGIS.Display; +using System.Text.RegularExpressions; + +namespace ESRI.ArcGIS.OSM.GeoProcessing +{ + [Guid("ce7a2734-2414-4893-b4b2-88a78dde5527")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("OSMEditor.OSMGPMultiLoader")] + public class OSMGPMultiLoader : ESRI.ArcGIS.Geoprocessing.IGPFunction2 + { + string m_DisplayName = String.Empty; + ResourceManager resourceManager = null; + OSMGPFactory osmGPFactory = null; + + + int in_osmFileNumber, out_osmPointsNumber, out_osmLinesNumber, out_osmPolygonsNumber, + in_deleteSupportNodesNumber, in_deleteOSMSourceFileNumber, in_pointFieldNamesNumber, + in_lineFieldNamesNumber, in_polygonFieldNamesNumber; + Dictionary m_editorConfigurationSettings = null; + + + public OSMGPMultiLoader() + { + osmGPFactory = new OSMGPFactory(); + resourceManager = new ResourceManager("ESRI.ArcGIS.OSM.GeoProcessing.OSMGPToolsStrings", this.GetType().Assembly); + + m_editorConfigurationSettings = OSMGPFactory.ReadOSMEditorSettings(); + } + + #region "IGPFunction2 Implementations" + public ESRI.ArcGIS.esriSystem.UID DialogCLSID + { + get + { + return default(ESRI.ArcGIS.esriSystem.UID); + } + } + + public string DisplayName + { + get + { + if (String.IsNullOrEmpty(m_DisplayName)) + { + m_DisplayName = osmGPFactory.GetFunctionName(OSMGPFactory.m_MultiLoaderName).DisplayName; + } + + return m_DisplayName; + } + } + + public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message) + { + IFeatureClass osmPointFeatureClass = null; + IFeatureClass osmLineFeatureClass = null; + IFeatureClass osmPolygonFeatureClass = null; + OSMToolHelper osmToolHelper = null; + + try + { + DateTime syncTime = DateTime.Now; + + IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + osmToolHelper = new OSMToolHelper(); + + if (TrackCancel == null) + { + TrackCancel = new CancelTrackerClass(); + } + + IGPParameter osmFileParameter = paramvalues.get_Element(in_osmFileNumber) as IGPParameter; + IGPValue osmFileLocationString = gpUtilities3.UnpackGPValue(osmFileParameter) as IGPValue; + + // ensure that the specified file does exist + bool osmFileExists = false; + + try + { + osmFileExists = System.IO.File.Exists(osmFileLocationString.GetAsText()); + } + catch (Exception ex) + { + message.AddError(120029, String.Format(resourceManager.GetString("GPTools_OSMGPMultiLoader_problemaccessingfile"), ex.Message)); + return; + } + + if (osmFileExists == false) + { + message.AddError(120030, String.Format(resourceManager.GetString("GPTools_OSMGPFileReader_osmfiledoesnotexist"), osmFileLocationString.GetAsText())); + return; + } + + long nodeCapacity = 0; + long wayCapacity = 0; + long relationCapacity = 0; + + // this assume a clean, tidy XML file - if this is not the case, there will by sync issues later on + osmToolHelper.countOSMStuffFast(osmFileLocationString.GetAsText(), ref nodeCapacity, ref wayCapacity, ref relationCapacity, ref TrackCancel); + + if (nodeCapacity == 0 && wayCapacity == 0 && relationCapacity == 0) + { + return; + } + + message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPMultiLoader_countedElements"), nodeCapacity, wayCapacity, relationCapacity)); + + + // determine the number of threads to be used + IGPEnvironment parallelProcessingFactorEnvironment = OSMToolHelper.getEnvironment(envMgr, "parallelProcessingFactor"); + IGPString parallelProcessingFactorString = parallelProcessingFactorEnvironment.Value as IGPString; + + // the default value is to use half the cores for additional threads - I am aware that we are comparing apples and oranges but I need a number + int numberOfThreads = Convert.ToInt32(System.Environment.ProcessorCount / 2); + + if (!(parallelProcessingFactorEnvironment.Value.IsEmpty())) + { + if (!Int32.TryParse(parallelProcessingFactorString.Value, out numberOfThreads)) + { + // this case we have a percent string + string resultString = Regex.Match(parallelProcessingFactorString.Value, @"\d+").Value; + numberOfThreads = Convert.ToInt32(Int32.Parse(resultString) / 100 * System.Environment.ProcessorCount); + } + } + + // tread the special case of 0 + if (numberOfThreads <= 0) + numberOfThreads = 1; + + IGPEnvironment configKeyword = OSMToolHelper.getEnvironment(envMgr, "configKeyword"); + IGPString gpString = configKeyword.Value as IGPString; + + string storageKeyword = String.Empty; + + if (gpString != null) + { + storageKeyword = gpString.Value; + } + + // determine the temp folder to be use for the intermediate files + IGPEnvironment scratchWorkspaceEnvironment = OSMToolHelper.getEnvironment(envMgr, "scratchWorkspace"); + IDEWorkspace deWorkspace = scratchWorkspaceEnvironment.Value as IDEWorkspace; + String scratchWorkspaceFolder = String.Empty; + + if (deWorkspace != null) + { + if (scratchWorkspaceEnvironment.Value.IsEmpty()) + { + scratchWorkspaceFolder = (new System.IO.FileInfo(osmFileLocationString.GetAsText())).DirectoryName; + } + else + { + if (deWorkspace.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace) + { + scratchWorkspaceFolder = System.IO.Path.GetTempPath(); + } + else if (deWorkspace.WorkspaceType == esriWorkspaceType.esriFileSystemWorkspace) + { + scratchWorkspaceFolder = ((IDataElement)deWorkspace).CatalogPath; + } + else + { + scratchWorkspaceFolder = (new System.IO.FileInfo(((IDataElement)deWorkspace).CatalogPath)).DirectoryName; + } + } + } + else + { + scratchWorkspaceFolder = (new System.IO.FileInfo(osmFileLocationString.GetAsText())).DirectoryName; + } + + string metadataAbstract = resourceManager.GetString("GPTools_OSMGPFileReader_metadata_abstract"); + string metadataPurpose = resourceManager.GetString("GPTools_OSMGPFileReader_metadata_purpose"); + + IGPParameter osmPointsFeatureClassParameter = paramvalues.get_Element(out_osmPointsNumber) as IGPParameter; + IGPValue osmPointsFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmPointsFeatureClassParameter) as IGPValue; + + IName workspaceName = gpUtilities3.CreateParentFromCatalogPath(osmPointsFeatureClassGPValue.GetAsText()); + IWorkspace2 pointFeatureWorkspace = workspaceName.Open() as IWorkspace2; + + string[] pointFCNameElements = osmPointsFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + + IGPParameter tagPointCollectionParameter = paramvalues.get_Element(in_pointFieldNamesNumber) as IGPParameter; + IGPMultiValue tagPointCollectionGPValue = gpUtilities3.UnpackGPValue(tagPointCollectionParameter) as IGPMultiValue; + + List pointTagstoExtract = null; + + if (tagPointCollectionGPValue.Count > 0) + { + pointTagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagPointCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagPointCollectionGPValue.get_Value(valueIndex).GetAsText(); + + pointTagstoExtract.Add(nameOfTag); + } + } + else + { + pointTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + + // points + try + { + osmPointFeatureClass = osmToolHelper.CreateSmallPointFeatureClass(pointFeatureWorkspace, + pointFCNameElements[pointFCNameElements.Length - 1], storageKeyword, metadataAbstract, + metadataPurpose, pointTagstoExtract); + } + catch (Exception ex) + { + message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message)); + return; + } + + if (osmPointFeatureClass == null) + { + return; + } + + int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID"); + Dictionary mainPointAttributeFieldIndices = new Dictionary(); + + foreach (string fieldName in OSMToolHelper.OSMSmallFeatureClassFields()) + { + int currentFieldIndex = osmPointFeatureClass.FindField(fieldName); + + if (currentFieldIndex != -1) + { + mainPointAttributeFieldIndices.Add(fieldName, currentFieldIndex); + } + } + + int tagCollectionPointFieldIndex = osmPointFeatureClass.FindField("osmTags"); + int osmSupportingElementPointFieldIndex = osmPointFeatureClass.FindField("osmSupportingElement"); + + + IGPParameter osmLineFeatureClassParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter; + IGPValue osmLineFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmLineFeatureClassParameter) as IGPValue; + + IName lineWorkspaceName = gpUtilities3.CreateParentFromCatalogPath(osmLineFeatureClassGPValue.GetAsText()); + IWorkspace2 lineFeatureWorkspace = lineWorkspaceName.Open() as IWorkspace2; + + string[] lineFCNameElements = osmLineFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + + IGPParameter tagLineCollectionParameter = paramvalues.get_Element(in_lineFieldNamesNumber) as IGPParameter; + IGPMultiValue tagLineCollectionGPValue = gpUtilities3.UnpackGPValue(tagLineCollectionParameter) as IGPMultiValue; + + List lineTagstoExtract = null; + + if (tagLineCollectionGPValue.Count > 0) + { + lineTagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagLineCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagLineCollectionGPValue.get_Value(valueIndex).GetAsText(); + + lineTagstoExtract.Add(nameOfTag); + } + } + else + { + lineTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + + // lines + try + { + osmLineFeatureClass = osmToolHelper.CreateSmallLineFeatureClass(lineFeatureWorkspace, lineFCNameElements[lineFCNameElements.Length -1], + storageKeyword, metadataAbstract, metadataPurpose, lineTagstoExtract); + } + catch (Exception ex) + { + message.AddError(120036, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nulllinefeatureclass"), ex.Message)); + return; + } + + if (osmLineFeatureClass == null) + { + return; + } + + int osmLineIDFieldIndex = osmLineFeatureClass.FindField("OSMID"); + + Dictionary mainLineAttributeFieldIndices = new Dictionary(); + foreach (string fieldName in OSMToolHelper.OSMSmallFeatureClassFields()) + { + int currentFieldIndex = osmLineFeatureClass.FindField(fieldName); + + if (currentFieldIndex != -1) + { + mainLineAttributeFieldIndices.Add(fieldName, currentFieldIndex); + } + } + + int tagCollectionPolylineFieldIndex = osmLineFeatureClass.FindField("osmTags"); + int osmSupportingElementPolylineFieldIndex = osmLineFeatureClass.FindField("osmSupportingElement"); + + IGPParameter osmPolygonFeatureClassParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter; + IGPValue osmPolygonFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmPolygonFeatureClassParameter) as IGPValue; + + IName polygonWorkspaceName = gpUtilities3.CreateParentFromCatalogPath(osmPolygonFeatureClassGPValue.GetAsText()); + IWorkspace2 polygonFeatureWorkspace = polygonWorkspaceName.Open() as IWorkspace2; + + string[] polygonFCNameElements = osmPolygonFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + IGPParameter tagPolygonCollectionParameter = paramvalues.get_Element(in_polygonFieldNamesNumber) as IGPParameter; + IGPMultiValue tagPolygonCollectionGPValue = gpUtilities3.UnpackGPValue(tagPolygonCollectionParameter) as IGPMultiValue; + + List polygonTagstoExtract = null; + + if (tagPolygonCollectionGPValue.Count > 0) + { + polygonTagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagPolygonCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagPolygonCollectionGPValue.get_Value(valueIndex).GetAsText(); + + polygonTagstoExtract.Add(nameOfTag); + } + } + else + { + polygonTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + + // polygons + try + { + osmPolygonFeatureClass = osmToolHelper.CreateSmallPolygonFeatureClass(polygonFeatureWorkspace, + polygonFCNameElements[polygonFCNameElements.Length -1], storageKeyword, metadataAbstract, + metadataPurpose, polygonTagstoExtract); + } + catch (Exception ex) + { + message.AddError(120037, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpolygonfeatureclass"), ex.Message)); + return; + } + + if (osmPolygonFeatureClass == null) + { + return; + } + + int osmPolygonIDFieldIndex = osmPolygonFeatureClass.FindField("OSMID"); + + Dictionary mainPolygonAttributeFieldIndices = new Dictionary(); + foreach (var fieldName in OSMToolHelper.OSMSmallFeatureClassFields()) + { + int currentFieldIndex = osmPolygonFeatureClass.FindField(fieldName); + + if (currentFieldIndex != -1) + { + mainPolygonAttributeFieldIndices.Add(fieldName, currentFieldIndex); + } + } + + int tagCollectionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmTags"); + int osmSupportingElementPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmSupportingElement"); + + ComReleaser.ReleaseCOMObject(osmPointFeatureClass); + osmPointFeatureClass = null; + + ComReleaser.ReleaseCOMObject(osmLineFeatureClass); + osmLineFeatureClass = null; + + ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass); + osmPolygonFeatureClass = null; + + + List nodeOSMFileNames = new List(numberOfThreads); + List nodeGDBFileNames = new List(numberOfThreads); + + List wayOSMFileNames = new List(numberOfThreads); + List wayGDBFileNames = new List(numberOfThreads); + + List relationOSMFileNames = new List(numberOfThreads); + List relationGDBFileNames = new List(numberOfThreads); + + if (TrackCancel.Continue() == false) + { + return; + } + + // split the original OSM xml file into smaller pieces for the python processes + osmToolHelper.splitOSMFile(osmFileLocationString.GetAsText(), scratchWorkspaceFolder, nodeCapacity, wayCapacity, relationCapacity, numberOfThreads, + out nodeOSMFileNames, out nodeGDBFileNames, out wayOSMFileNames, out wayGDBFileNames, out relationOSMFileNames, out relationGDBFileNames); + + IGPParameter deleteSourceOSMFileParameter = paramvalues.get_Element(in_deleteOSMSourceFileNumber) as IGPParameter; + IGPBoolean deleteSourceOSMFileGPValue = gpUtilities3.UnpackGPValue(deleteSourceOSMFileParameter) as IGPBoolean; + + if (deleteSourceOSMFileGPValue.Value) + { + try + { + System.IO.File.Delete(osmFileLocationString.GetAsText()); + } + catch (Exception ex) + { + message.AddWarning(ex.Message); + } + } + + if (TrackCancel.Continue() == false) + { + return; + } + + if (nodeOSMFileNames.Count == 0) + { + nodeOSMFileNames.Add(osmFileLocationString.GetAsText()); + nodeGDBFileNames.Add(osmPointsFeatureClassGPValue.GetAsText()); + + wayOSMFileNames.Add(osmFileLocationString.GetAsText()); + wayGDBFileNames.Add(osmLineFeatureClassGPValue.GetAsText()); + + relationOSMFileNames.Add(osmFileLocationString.GetAsText()); + relationGDBFileNames.Add(osmPolygonFeatureClassGPValue.GetAsText()); + } + else + { + // for the nodes let's load one of the parts directly into the target file geodatabase + nodeGDBFileNames[0] = ((IWorkspace)pointFeatureWorkspace).PathName; + } + + // define variables helping to invoke core tools for data management + IGeoProcessorResult2 gpResults2 = null; + IGeoProcessor2 geoProcessor = new GeoProcessorClass(); + + IGPParameter deleteSupportingNodesParameter = paramvalues.get_Element(in_deleteSupportNodesNumber) as IGPParameter; + IGPBoolean deleteSupportingNodesGPValue = gpUtilities3.UnpackGPValue(deleteSupportingNodesParameter) as IGPBoolean; + + #region load points + osmToolHelper.loadOSMNodes(nodeOSMFileNames, nodeGDBFileNames, pointFCNameElements[pointFCNameElements.Length - 1], osmPointsFeatureClassGPValue.GetAsText(), pointTagstoExtract, deleteSupportingNodesGPValue.Value, ref message, ref TrackCancel); + #endregion + + if (TrackCancel.Continue() == false) + { + return; + } + + #region load ways + osmToolHelper.loadOSMWays(wayOSMFileNames, osmPointsFeatureClassGPValue.GetAsText(), wayGDBFileNames, lineFCNameElements[lineFCNameElements.Length - 1], polygonFCNameElements[polygonFCNameElements.Length - 1], lineTagstoExtract, polygonTagstoExtract, ref message, ref TrackCancel); + #endregion + + #region for local geodatabases enforce spatial integrity + + bool storedOriginalLocal = geoProcessor.AddOutputsToMap; + geoProcessor.AddOutputsToMap = false; + + try + { + osmLineFeatureClass = ((IFeatureWorkspace)lineFeatureWorkspace).OpenFeatureClass(lineFCNameElements[lineFCNameElements.Length - 1]); + + if (osmLineFeatureClass != null) + { + + if (((IDataset)osmLineFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace) + { + gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3; + + IGPParameter outLinesParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter; + IGPValue lineFeatureClass = gpUtilities3.UnpackGPValue(outLinesParameter); + + DataManagementTools.RepairGeometry repairlineGeometry = new DataManagementTools.RepairGeometry(osmLineFeatureClass); + + IVariantArray repairGeometryParameterArray = new VarArrayClass(); + repairGeometryParameterArray.Add(lineFeatureClass.GetAsText()); + repairGeometryParameterArray.Add("DELETE_NULL"); + + gpResults2 = geoProcessor.Execute(repairlineGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2; + message.AddMessages(gpResults2.GetResultMessages()); + + ComReleaser.ReleaseCOMObject(gpUtilities3); + } + } + } + catch { } + finally + { + ComReleaser.ReleaseCOMObject(osmLineFeatureClass); + } + + + try + { + osmPolygonFeatureClass = ((IFeatureWorkspace)polygonFeatureWorkspace).OpenFeatureClass(polygonFCNameElements[polygonFCNameElements.Length - 1]); + + if (osmPolygonFeatureClass != null) + { + if (((IDataset)osmPolygonFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace) + { + gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3; + + IGPParameter outPolygonParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter; + IGPValue polygonFeatureClass = gpUtilities3.UnpackGPValue(outPolygonParameter); + + DataManagementTools.RepairGeometry repairpolygonGeometry = new DataManagementTools.RepairGeometry(osmPolygonFeatureClass); + + IVariantArray repairGeometryParameterArray = new VarArrayClass(); + repairGeometryParameterArray.Add(polygonFeatureClass.GetAsText()); + repairGeometryParameterArray.Add("DELETE_NULL"); + + gpResults2 = geoProcessor.Execute(repairpolygonGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2; + message.AddMessages(gpResults2.GetResultMessages()); + + ComReleaser.ReleaseCOMObject(gpUtilities3); + } + } + } + catch { } + finally + { + ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass); + } + + geoProcessor.AddOutputsToMap = storedOriginalLocal; + + #endregion + + if (TrackCancel.Continue() == false) + { + return; + } + + #region load relations + osmToolHelper.loadOSMRelations(relationOSMFileNames, osmLineFeatureClassGPValue.GetAsText(), osmPolygonFeatureClassGPValue.GetAsText(), relationGDBFileNames, lineTagstoExtract, polygonTagstoExtract, ref TrackCancel, ref message); + #endregion + + // check for user interruption + if (TrackCancel.Continue() == false) + { + return; + } + + #region for local geodatabases enforce spatial integrity + //storedOriginalLocal = geoProcessor.AddOutputsToMap; + //geoProcessor.AddOutputsToMap = false; + + //try + //{ + // osmLineFeatureClass = ((IFeatureWorkspace)lineFeatureWorkspace).OpenFeatureClass(lineFCNameElements[lineFCNameElements.Length - 1]); + + // if (osmLineFeatureClass != null) + // { + + // if (((IDataset)osmLineFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace) + // { + // gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3; + + // IGPParameter outLinesParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter; + // IGPValue lineFeatureClass = gpUtilities3.UnpackGPValue(outLinesParameter); + + // DataManagementTools.RepairGeometry repairlineGeometry = new DataManagementTools.RepairGeometry(osmLineFeatureClass); + + // IVariantArray repairGeometryParameterArray = new VarArrayClass(); + // repairGeometryParameterArray.Add(lineFeatureClass.GetAsText()); + // repairGeometryParameterArray.Add("DELETE_NULL"); + + // gpResults2 = geoProcessor.Execute(repairlineGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2; + // message.AddMessages(gpResults2.GetResultMessages()); + + // ComReleaser.ReleaseCOMObject(gpUtilities3); + // } + // } + //} + //catch { } + //finally + //{ + // ComReleaser.ReleaseCOMObject(osmLineFeatureClass); + //} + + + //try + //{ + // osmPolygonFeatureClass = ((IFeatureWorkspace)polygonFeatureWorkspace).OpenFeatureClass(polygonFCNameElements[polygonFCNameElements.Length - 1]); + + // if (osmPolygonFeatureClass != null) + // { + // if (((IDataset)osmPolygonFeatureClass).Workspace.Type == esriWorkspaceType.esriLocalDatabaseWorkspace) + // { + // gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3; + + // IGPParameter outPolygonParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter; + // IGPValue polygonFeatureClass = gpUtilities3.UnpackGPValue(outPolygonParameter); + + // DataManagementTools.RepairGeometry repairpolygonGeometry = new DataManagementTools.RepairGeometry(osmPolygonFeatureClass); + + // IVariantArray repairGeometryParameterArray = new VarArrayClass(); + // repairGeometryParameterArray.Add(polygonFeatureClass.GetAsText()); + // repairGeometryParameterArray.Add("DELETE_NULL"); + + // gpResults2 = geoProcessor.Execute(repairpolygonGeometry.ToolName, repairGeometryParameterArray, TrackCancel) as IGeoProcessorResult2; + // message.AddMessages(gpResults2.GetResultMessages()); + + // ComReleaser.ReleaseCOMObject(gpUtilities3); + // } + // } + //} + //catch { } + //finally + //{ + // ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass); + //} + + //geoProcessor.AddOutputsToMap = storedOriginalLocal; + + #endregion + + if (TrackCancel.Continue() == false) + { + return; + } + + + if (deleteSupportingNodesGPValue.Value) + { + message.AddMessage(String.Format(resourceManager.GetString("GPTools_OSMGPMultiLoader_remove_supportNodes"))); + + storedOriginalLocal = geoProcessor.AddOutputsToMap; + geoProcessor.AddOutputsToMap = false; + + // create a layer file to select the points that have attributes + osmPointFeatureClass = ((IFeatureWorkspace)pointFeatureWorkspace).OpenFeatureClass(pointFCNameElements[pointFCNameElements.Length - 1]); + + IVariantArray makeFeatureLayerParameterArray = new VarArrayClass(); + makeFeatureLayerParameterArray.Add(osmPointsFeatureClassGPValue.GetAsText()); + + string tempLayerFile = System.IO.Path.GetTempFileName(); + makeFeatureLayerParameterArray.Add(tempLayerFile); + makeFeatureLayerParameterArray.Add(String.Format("{0} = 'no'", osmPointFeatureClass.SqlIdentifier("osmSupportingElement"))); + + geoProcessor.Execute("MakeFeatureLayer_management", makeFeatureLayerParameterArray, TrackCancel); + + // copy the features into its own feature class + IVariantArray copyFeatureParametersArray = new VarArrayClass(); + copyFeatureParametersArray.Add(tempLayerFile); + + string tempFeatureClass = String.Join("\\", new string[] { + ((IWorkspace)pointFeatureWorkspace).PathName, "t_" + pointFCNameElements[pointFCNameElements.Length - 1] }); + copyFeatureParametersArray.Add(tempFeatureClass); + + geoProcessor.Execute("CopyFeatures_management", copyFeatureParametersArray, TrackCancel); + + // delete the temp file + System.IO.File.Delete(tempLayerFile); + + // delete the original feature class + IVariantArray deleteParameterArray = new VarArrayClass(); + deleteParameterArray.Add(osmPointsFeatureClassGPValue.GetAsText()); + + geoProcessor.Execute("Delete_management", deleteParameterArray, TrackCancel); + + // rename the temp feature class back to the original + IVariantArray renameParameterArray = new VarArrayClass(); + renameParameterArray.Add(tempFeatureClass); + renameParameterArray.Add(osmPointsFeatureClassGPValue.GetAsText()); + + geoProcessor.Execute("Rename_management", renameParameterArray, TrackCancel); + + geoProcessor.AddOutputsToMap = storedOriginalLocal; + + ComReleaser.ReleaseCOMObject(osmPointFeatureClass); + ComReleaser.ReleaseCOMObject(geoProcessor); + } + + gpUtilities3 = new GPUtilitiesClass() as IGPUtilities3; + + // repackage the feature class into their respective gp values + IGPParameter pointFeatureClassParameter = paramvalues.get_Element(out_osmPointsNumber) as IGPParameter; + IGPValue pointFeatureClassGPValue = gpUtilities3.UnpackGPValue(pointFeatureClassParameter); + gpUtilities3.PackGPValue(pointFeatureClassGPValue, pointFeatureClassParameter); + + IGPParameter lineFeatureClassParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter; + IGPValue line1FeatureClassGPValue = gpUtilities3.UnpackGPValue(lineFeatureClassParameter); + gpUtilities3.PackGPValue(line1FeatureClassGPValue, lineFeatureClassParameter); + + IGPParameter polygonFeatureClassParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter; + IGPValue polygon1FeatureClassGPValue = gpUtilities3.UnpackGPValue(polygonFeatureClassParameter); + gpUtilities3.PackGPValue(polygon1FeatureClassGPValue, polygonFeatureClassParameter); + + ComReleaser.ReleaseCOMObject(osmFileLocationString); + + gpUtilities3.ReleaseInternals(); + ComReleaser.ReleaseCOMObject(gpUtilities3); + } + catch (Exception ex) + { + message.AddError(120055, ex.Message); + message.AddError(120055, ex.StackTrace); + } + finally + { + try + { + osmToolHelper = null; + + System.GC.Collect(); + System.GC.WaitForPendingFinalizers(); + } + catch (Exception ex) + { + message.AddError(120056, ex.ToString()); + } + } + } + + public ESRI.ArcGIS.esriSystem.IName FullName + { + get + { + IName fullName = null; + + if (osmGPFactory != null) + { + fullName = osmGPFactory.GetFunctionName(OSMGPFactory.m_MultiLoaderName) as IName; + } + + return fullName; + } + } + + public object GetRenderer(ESRI.ArcGIS.Geoprocessing.IGPParameter pParam) + { + return default(object); + } + + public int HelpContext + { + get + { + return default(int); + } + } + + public string HelpFile + { + get + { + return default(string); + } + } + + public bool IsLicensed() + { + return true; + } + + public string MetadataFile + { + get + { + string metadafile = "osmgpmultiloader.xml"; + + try + { + string[] languageid = System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Split("-".ToCharArray()); + + string ArcGISInstallationLocation = OSMGPFactory.GetArcGIS10InstallLocation(); + string localizedMetaDataFileShort = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + languageid[0] + ".xml"; + string localizedMetaDataFileLong = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + System.Threading.Thread.CurrentThread.CurrentUICulture.Name + ".xml"; + + if (System.IO.File.Exists(localizedMetaDataFileShort)) + { + metadafile = localizedMetaDataFileShort; + } + else if (System.IO.File.Exists(localizedMetaDataFileLong)) + { + metadafile = localizedMetaDataFileLong; + } + } + catch { } + + return metadafile; + } + } + + public string Name + { + get + { + return OSMGPFactory.m_MultiLoaderName; + } + } + + public ESRI.ArcGIS.esriSystem.IArray ParameterInfo + { + get + { + // + IArray parameterArray = new ArrayClass(); + + // osm file to load (required) + IGPParameterEdit3 osmLoadFile = new GPParameterClass() as IGPParameterEdit3; + osmLoadFile.DataType = new DEFileTypeClass(); + osmLoadFile.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + osmLoadFile.DisplayName = resourceManager.GetString("GPTools_OSMGPMultiLoader_osmfile_desc"); + osmLoadFile.Name = "in_osmFile"; + osmLoadFile.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + + IGPParameterEdit3 osmPoints = new GPParameterClass() as IGPParameterEdit3; + osmPoints.DataType = new DEFeatureClassTypeClass(); + osmPoints.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmPoints.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmPoints.DisplayName = resourceManager.GetString("GPTools_OSMGPMultiLoader_osmPoints_desc"); + osmPoints.Name = "out_osmPoints"; + + IGPFeatureClassDomain osmPointFeatureClassDomain = new GPFeatureClassDomainClass(); + osmPointFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmPointFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint); + osmPoints.Domain = osmPointFeatureClassDomain as IGPDomain; + + IGPParameterEdit3 osmLines = new GPParameterClass() as IGPParameterEdit3; + osmLines.DataType = new DEFeatureClassTypeClass(); + osmLines.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmLines.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmLines.DisplayName = resourceManager.GetString("GPTools_OSMGPMultiLoader_osmLine_desc"); + osmLines.Name = "out_osmLines"; + + IGPFeatureClassDomain osmPolylineFeatureClassDomain = new GPFeatureClassDomainClass(); + osmPolylineFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmPolylineFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline); + osmLines.Domain = osmPolylineFeatureClassDomain as IGPDomain; + + IGPParameterEdit3 osmPolygons = new GPParameterClass() as IGPParameterEdit3; + osmPolygons.DataType = new DEFeatureClassTypeClass(); + osmPolygons.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmPolygons.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmPolygons.DisplayName = resourceManager.GetString("GPTools_OSMGPMultiLoader_osmPolygon_desc"); + osmPolygons.Name = "out_osmPolygons"; + + IGPFeatureClassDomain osmPolygonFeatureClassDomain = new GPFeatureClassDomainClass(); + osmPolygonFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmPolygonFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon); + osmPolygons.Domain = osmPolygonFeatureClassDomain as IGPDomain; + + IGPParameterEdit3 deleteOSMSourceFileParameter = new GPParameterClass() as IGPParameterEdit3; + IGPCodedValueDomain deleteOSMSourceFileDomain = new GPCodedValueDomainClass(); + + IGPBoolean deleteOSMSourceFileTrue = new GPBooleanClass(); + deleteOSMSourceFileTrue.Value = true; + IGPBoolean deleteOSMSourceFileFalse = new GPBooleanClass(); + deleteOSMSourceFileFalse.Value = false; + + deleteOSMSourceFileDomain.AddCode((IGPValue)deleteOSMSourceFileTrue, "DELETE_OSM_FILE"); + deleteOSMSourceFileDomain.AddCode((IGPValue)deleteOSMSourceFileFalse, "DO_NOT_DELETE_OSM_FILE"); + deleteOSMSourceFileParameter.Domain = (IGPDomain)deleteOSMSourceFileDomain; + deleteOSMSourceFileParameter.Value = (IGPValue)deleteOSMSourceFileFalse; + + deleteOSMSourceFileParameter.DataType = new GPBooleanTypeClass(); + deleteOSMSourceFileParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + deleteOSMSourceFileParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + deleteOSMSourceFileParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPMultiLoader_deleteOSMSource_desc"); + deleteOSMSourceFileParameter.Name = "in_deleteOSMSourceFile"; + + + IGPParameterEdit3 deleteSupportNodesParameter = new GPParameterClass() as IGPParameterEdit3; + IGPCodedValueDomain deleteSupportNodesDomain = new GPCodedValueDomainClass(); + + IGPBoolean deleteSupportNodesTrue = new GPBooleanClass(); + deleteSupportNodesTrue.Value = true; + IGPBoolean deleteSupportNodesFalse = new GPBooleanClass(); + deleteSupportNodesFalse.Value = false; + + deleteSupportNodesDomain.AddCode((IGPValue)deleteSupportNodesTrue, "DELETE_NODES"); + deleteSupportNodesDomain.AddCode((IGPValue)deleteSupportNodesFalse, "DO_NOT_DELETE_NODES"); + deleteSupportNodesParameter.Domain = (IGPDomain)deleteSupportNodesDomain; + deleteSupportNodesParameter.Value = (IGPValue)deleteSupportNodesFalse; + + deleteSupportNodesParameter.DataType = new GPBooleanTypeClass(); + deleteSupportNodesParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + deleteSupportNodesParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + deleteSupportNodesParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPMultiLoader_deleteNodes_desc"); + deleteSupportNodesParameter.Name = "in_deleteSupportNodes"; + + // field multi parameter + IGPParameterEdit3 loadLineFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + + IGPDataType fieldNameDataType = new GPStringTypeClass(); + IGPMultiValue fieldNameMultiValue = new GPMultiValueClass(); + fieldNameMultiValue.MemberDataType = fieldNameDataType; + + IGPMultiValueType fieldNameDataType2 = new GPMultiValueTypeClass(); + fieldNameDataType2.MemberDataType = fieldNameDataType; + + loadLineFieldsParameter.Name = "in_polyline_fieldNames"; + loadLineFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_lineFieldNames_desc"); + loadLineFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadLineFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadLineFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadLineFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadLineFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + IGPParameterEdit3 loadPolygonFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + loadPolygonFieldsParameter.Name = "in_polygon_fieldNames"; + loadPolygonFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_polygonFieldNames_desc"); + loadPolygonFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadPolygonFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadPolygonFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadPolygonFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadPolygonFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + IGPParameterEdit3 loadPointFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + loadPointFieldsParameter.Name = "in_point_fieldNames"; + loadPointFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPNodeLoader_fieldNames_desc"); + loadPointFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadPointFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadPointFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadPointFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadPointFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + parameterArray.Add(osmLoadFile); + in_osmFileNumber = 0; + + parameterArray.Add(loadPointFieldsParameter); + in_pointFieldNamesNumber = 1; + + parameterArray.Add(loadLineFieldsParameter); + in_lineFieldNamesNumber = 2; + + parameterArray.Add(loadPolygonFieldsParameter); + in_polygonFieldNamesNumber = 3; + + parameterArray.Add(deleteSupportNodesParameter); + in_deleteSupportNodesNumber = 4; + + parameterArray.Add(deleteOSMSourceFileParameter); + in_deleteOSMSourceFileNumber = 5; + + parameterArray.Add(osmPoints); + out_osmPointsNumber = 6; + + parameterArray.Add(osmLines); + out_osmLinesNumber = 7; + + parameterArray.Add(osmPolygons); + out_osmPolygonsNumber = 8; + + return parameterArray; + } + } + + public void UpdateMessages(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr, ESRI.ArcGIS.Geodatabase.IGPMessages Messages) + { + //IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + + //IGPParameter targetDatasetParameter = paramvalues.get_Element(out_targetDatasetNumber) as IGPParameter; + //try + //{ + // gpUtilities3.QualifyOutputDataElement(gpUtilities3.UnpackGPValue(targetDatasetParameter)); + //} + //catch + //{ + // Messages.ReplaceError(out_targetDatasetNumber, -2, resourceManager.GetString("GPTools_OSMGPFileReader_targetDataset_notexist")); + //} + + //// check for valid geodatabase path + //// if the user is pointing to a valid directory on disk, flag it as an error + //IGPValue targetDatasetGPValue = gpUtilities3.UnpackGPValue(targetDatasetParameter); + + //if (targetDatasetGPValue.IsEmpty() == false) + //{ + // if (System.IO.Directory.Exists(targetDatasetGPValue.GetAsText())) + // { + // Messages.ReplaceError(out_targetDatasetNumber, -4, resourceManager.GetString("GPTools_OSMGPDownload_directory_is_not_target_dataset")); + // } + //} + + //gpUtilities3.ReleaseInternals(); + + //if (gpUtilities3 != null) + // ComReleaser.ReleaseCOMObject(gpUtilities3); + + } + + public void UpdateParameters(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr) + { + //IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + + //IGPParameter targetDatasetParameter = paramvalues.get_Element(out_targetDatasetNumber) as IGPParameter; + //IGPValue targetDatasetGPValue = gpUtilities3.UnpackGPValue(targetDatasetParameter); + + //IDEFeatureDataset targetDEFeatureDataset = targetDatasetGPValue as IDEFeatureDataset; + + //IGPParameter3 outPointsFeatureClassParameter = null; + //IGPValue outPointsFeatureClass = null; + //string outpointsPath = String.Empty; + + //IGPParameter3 outLinesFeatureClassParameter = null; + //IGPValue outLinesFeatureClass = null; + //string outlinesPath = String.Empty; + + //IGPParameter3 outPolygonFeatureClassParameter = null; + //IGPValue outPolygonFeatureClass = null; + //string outpolygonsPath = String.Empty; + + //if (((IGPValue)targetDEFeatureDataset).GetAsText().Length != 0) + //{ + // IDataElement dataElement = targetDEFeatureDataset as IDataElement; + // try + // { + // gpUtilities3.QualifyOutputDataElement(gpUtilities3.UnpackGPValue(targetDatasetParameter)); + // } + // catch + // { + // return; + // } + + // string nameOfPointFeatureClass = dataElement.GetBaseName() + "_osm_pt"; + // string nameOfLineFeatureClass = dataElement.GetBaseName() + "_osm_ln"; + // string nameOfPolygonFeatureClass = dataElement.GetBaseName() + "_osm_ply"; + + + // try + // { + // outpointsPath = dataElement.CatalogPath + System.IO.Path.DirectorySeparatorChar + nameOfPointFeatureClass; + // } + // catch (Exception ex) + // { + // System.Diagnostics.Debug.WriteLine(ex.Message); + // } + // outPointsFeatureClassParameter = paramvalues.get_Element(out_osmPointsNumber) as IGPParameter3; + // outPointsFeatureClass = gpUtilities3.UnpackGPValue(outPointsFeatureClassParameter); + + // outlinesPath = dataElement.CatalogPath + System.IO.Path.DirectorySeparatorChar + nameOfLineFeatureClass; + // outLinesFeatureClassParameter = paramvalues.get_Element(out_osmLinesNumber) as IGPParameter3; + // outLinesFeatureClass = gpUtilities3.UnpackGPValue(outLinesFeatureClassParameter); + + // outpolygonsPath = dataElement.CatalogPath + System.IO.Path.DirectorySeparatorChar + nameOfPolygonFeatureClass; + // outPolygonFeatureClassParameter = paramvalues.get_Element(out_osmPolygonsNumber) as IGPParameter3; + // outPolygonFeatureClass = gpUtilities3.UnpackGPValue(outPolygonFeatureClassParameter); + //} + + //if (outPointsFeatureClassParameter != null) + //{ + // outPointsFeatureClass.SetAsText(outpointsPath); + // gpUtilities3.PackGPValue(outPointsFeatureClass, outPointsFeatureClassParameter); + //} + + //if (outLinesFeatureClassParameter != null) + //{ + // outLinesFeatureClass.SetAsText(outlinesPath); + // gpUtilities3.PackGPValue(outLinesFeatureClass, outLinesFeatureClassParameter); + //} + + //if (outPolygonFeatureClassParameter != null) + //{ + // outPolygonFeatureClass.SetAsText(outpolygonsPath); + // gpUtilities3.PackGPValue(outPolygonFeatureClass, outPolygonFeatureClassParameter); + //} + + //gpUtilities3.ReleaseInternals(); + + //if (gpUtilities3 != null) + // ComReleaser.ReleaseCOMObject(gpUtilities3); + } + + public ESRI.ArcGIS.Geodatabase.IGPMessages Validate(ESRI.ArcGIS.esriSystem.IArray paramvalues, bool updateValues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr) + { + return default(ESRI.ArcGIS.Geodatabase.IGPMessages); + } + #endregion + + } +} diff --git a/src/OSMGeoProcessing/OSMGPNodeLoader.cs b/src/OSMGeoProcessing/OSMGPNodeLoader.cs new file mode 100644 index 0000000..76da208 --- /dev/null +++ b/src/OSMGeoProcessing/OSMGPNodeLoader.cs @@ -0,0 +1,308 @@ +// (c) Copyright Esri, 2010 - 2016 +// This source is subject to the Apache 2.0 License. +// Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. +// All other rights reserved. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Resources; +using ESRI.ArcGIS.esriSystem; +using ESRI.ArcGIS.Geoprocessing; +using ESRI.ArcGIS.DataSourcesFile; +using ESRI.ArcGIS.Geodatabase; +using ESRI.ArcGIS.Display; + +namespace ESRI.ArcGIS.OSM.GeoProcessing +{ + [Guid("a89bdb78-8abf-45c7-9a44-c4b876fa5d6d")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("OSMEditor.OSMGPPointLoader")] + public class OSMGPNodeLoader : ESRI.ArcGIS.Geoprocessing.IGPFunction2 + { + string m_DisplayName = String.Empty; + ResourceManager resourceManager = null; + OSMGPFactory osmGPFactory = null; + + public OSMGPNodeLoader() + { + resourceManager = new ResourceManager("ESRI.ArcGIS.OSM.GeoProcessing.OSMGPToolsStrings", this.GetType().Assembly); + + osmGPFactory = new OSMGPFactory(); + } + + #region "IGPFunction2 Implementations" + public ESRI.ArcGIS.esriSystem.UID DialogCLSID + { + get + { + return default(ESRI.ArcGIS.esriSystem.UID); + } + } + + public string DisplayName + { + get + { + if (String.IsNullOrEmpty(m_DisplayName)) + { + m_DisplayName = osmGPFactory.GetFunctionName(OSMGPFactory.m_NodeLoaderName).DisplayName; + } + + return m_DisplayName; + } + } + + public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message) + { + IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + OSMToolHelper osmToolHelper = new OSMToolHelper(); + + if (TrackCancel == null) + { + TrackCancel = new CancelTrackerClass(); + } + + IGPEnvironment configKeyword = OSMToolHelper.getEnvironment(envMgr, "configKeyword"); + IGPString gpString = configKeyword.Value as IGPString; + + string storageKeyword = String.Empty; + + if (gpString != null) + { + storageKeyword = gpString.Value; + } + + IGPParameter osmFileParameter = paramvalues.get_Element(0) as IGPParameter; + IGPValue osmFileLocationString = gpUtilities3.UnpackGPValue(osmFileParameter) as IGPValue; + + + IGPParameter tagCollectionParameter = paramvalues.get_Element(1) as IGPParameter; + IGPMultiValue tagCollectionGPValue = gpUtilities3.UnpackGPValue(tagCollectionParameter) as IGPMultiValue; + + List tagstoExtract = null; + + if (tagCollectionGPValue.Count > 0) + { + tagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagCollectionGPValue.get_Value(valueIndex).GetAsText(); + + tagstoExtract.Add(nameOfTag); + } + } + else + { + tagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + + IGPParameter useFeatureBufferParameter = paramvalues.get_Element(2) as IGPParameter; + IGPBoolean useFeatureBufferGPValue = gpUtilities3.UnpackGPValue(useFeatureBufferParameter) as IGPBoolean; + + IGPParameter osmPointsFeatureClassParameter = paramvalues.get_Element(3) as IGPParameter; + IGPValue osmPointsFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmPointsFeatureClassParameter) as IGPValue; + + IName workspaceName = gpUtilities3.CreateParentFromCatalogPath(osmPointsFeatureClassGPValue.GetAsText()); + IWorkspace2 pointFeatureWorkspace = workspaceName.Open() as IWorkspace2; + + string[] pointFCNameElements = osmPointsFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + IFeatureClass osmPointFeatureClass = null; + + // points + try + { + osmPointFeatureClass = osmToolHelper.CreateSmallPointFeatureClass(pointFeatureWorkspace, pointFCNameElements[pointFCNameElements.Length - 1], storageKeyword, "", "", tagstoExtract); + } + catch (Exception ex) + { + message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message)); + return; + } + + if (osmPointFeatureClass == null) + { + return; + } + + string[] gdbComponents = new string[pointFCNameElements.Length - 1]; + System.Array.Copy(pointFCNameElements, gdbComponents, pointFCNameElements.Length - 1); + string fileGDBLocation = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), gdbComponents); + osmToolHelper.smallLoadOSMNode(osmFileLocationString.GetAsText(), fileGDBLocation, pointFCNameElements[pointFCNameElements.Length - 1], tagstoExtract, useFeatureBufferGPValue.Value); + + } + + public ESRI.ArcGIS.esriSystem.IName FullName + { + get + { + IName fullName = null; + + if (osmGPFactory != null) + { + fullName = osmGPFactory.GetFunctionName(OSMGPFactory.m_NodeLoaderName) as IName; + } + + return fullName; + } + } + + public object GetRenderer(ESRI.ArcGIS.Geoprocessing.IGPParameter pParam) + { + return null; + } + + public int HelpContext + { + get + { + return 0; + } + } + + public string HelpFile + { + get + { + return String.Empty; + } + } + + public bool IsLicensed() + { + return true; + } + + public string MetadataFile + { + get + { + string metadafile = "osmgpnodeloader.xml"; + + try + { + string[] languageid = System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Split("-".ToCharArray()); + + string ArcGISInstallationLocation = OSMGPFactory.GetArcGIS10InstallLocation(); + string localizedMetaDataFileShort = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + languageid[0] + ".xml"; + string localizedMetaDataFileLong = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + System.Threading.Thread.CurrentThread.CurrentUICulture.Name + ".xml"; + + if (System.IO.File.Exists(localizedMetaDataFileShort)) + { + metadafile = localizedMetaDataFileShort; + } + else if (System.IO.File.Exists(localizedMetaDataFileLong)) + { + metadafile = localizedMetaDataFileLong; + } + } + catch { } + + return metadafile; + } + } + + public string Name + { + get + { + return OSMGPFactory.m_NodeLoaderName; + } + } + + public ESRI.ArcGIS.esriSystem.IArray ParameterInfo + { + get + { + IArray parameters = new ArrayClass(); + + // input osm file containing the nodes + IGPParameterEdit3 osmNodeFile = new GPParameterClass() as IGPParameterEdit3; + osmNodeFile.DataType = new DEFileTypeClass(); + osmNodeFile.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + osmNodeFile.DisplayName = resourceManager.GetString("GPTools_OSMGPNodeLoader_osmfile_desc"); + osmNodeFile.Name = "in_osmNodeFile"; + osmNodeFile.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + + // field multi parameter + IGPParameterEdit3 loadFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + + IGPDataType fieldNameDataType = new GPStringTypeClass(); + IGPMultiValue fieldNameMultiValue = new GPMultiValueClass(); + fieldNameMultiValue.MemberDataType = fieldNameDataType; + + IGPMultiValueType fieldNameDataType2 = new GPMultiValueTypeClass(); + fieldNameDataType2.MemberDataType = fieldNameDataType; + + loadFieldsParameter.Name = "in_fieldNames"; + loadFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPNodeLoader_fieldNames_desc"); + loadFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + // use buffer paranmeter + IGPParameterEdit3 useFeatureBufferParameter = new GPParameterClass() as IGPParameterEdit3; + IGPCodedValueDomain useFeatureBufferDomain = new GPCodedValueDomainClass(); + + IGPBoolean useFeatureBufferTrue = new GPBooleanClass(); + useFeatureBufferTrue.Value = true; + IGPBoolean useFeatureBufferFalse = new GPBooleanClass(); + useFeatureBufferFalse.Value = false; + + useFeatureBufferDomain.AddCode((IGPValue)useFeatureBufferTrue, "USE_CACHE"); + useFeatureBufferDomain.AddCode((IGPValue)useFeatureBufferFalse, "DO_NOT_USE_CACHE"); + useFeatureBufferParameter.Domain = (IGPDomain)useFeatureBufferDomain; + useFeatureBufferParameter.Value = (IGPValue)useFeatureBufferFalse; + + useFeatureBufferParameter.DataType = new GPBooleanTypeClass(); + useFeatureBufferParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + useFeatureBufferParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + useFeatureBufferParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPNodeLoader_useCache_desc"); + useFeatureBufferParameter.Name = "in_useFeatureCache"; + + + IGPParameterEdit3 osmPoints = new GPParameterClass() as IGPParameterEdit3; + osmPoints.DataType = new DEFeatureClassTypeClass(); + osmPoints.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmPoints.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmPoints.DisplayName = resourceManager.GetString("GPTools_OSMGPNodeLoader_osmPoints_desc"); + osmPoints.Name = "out_osmNodePoints"; + + IGPFeatureClassDomain osmPointFeatureClassDomain = new GPFeatureClassDomainClass(); + osmPointFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmPointFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint); + osmPoints.Domain = osmPointFeatureClassDomain as IGPDomain; + + parameters.Add(osmNodeFile); + + parameters.Add(loadFieldsParameter); + + parameters.Add(useFeatureBufferParameter); + + parameters.Add(osmPoints); + + return parameters; + } + } + + public void UpdateMessages(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr, ESRI.ArcGIS.Geodatabase.IGPMessages Messages) + { + } + + public void UpdateParameters(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr) + { + } + + public ESRI.ArcGIS.Geodatabase.IGPMessages Validate(ESRI.ArcGIS.esriSystem.IArray paramvalues, bool updateValues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr) + { + return default(ESRI.ArcGIS.Geodatabase.IGPMessages); + } + #endregion + + } +} diff --git a/src/OSMGeoProcessing/OSMGPRelationLoader.cs b/src/OSMGeoProcessing/OSMGPRelationLoader.cs new file mode 100644 index 0000000..1329c65 --- /dev/null +++ b/src/OSMGeoProcessing/OSMGPRelationLoader.cs @@ -0,0 +1,425 @@ +// (c) Copyright Esri, 2010 - 2016 +// This source is subject to the Apache 2.0 License. +// Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. +// All other rights reserved. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using ESRI.ArcGIS.esriSystem; +using ESRI.ArcGIS.Geoprocessing; +using ESRI.ArcGIS.DataSourcesFile; +using System.Resources; +using ESRI.ArcGIS.Geodatabase; +using ESRI.ArcGIS.OSM.OSMClassExtension; +using ESRI.ArcGIS.Display; + +namespace ESRI.ArcGIS.OSM.GeoProcessing +{ + [Guid("1fdcb9ab-54b1-4592-ad00-e5a19e425ce8")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("OSMEditor.OSMGPRelationLoader")] + public class OSMGPRelationLoader : ESRI.ArcGIS.Geoprocessing.IGPFunction2 + { + + + string m_DisplayName = String.Empty; + ResourceManager resourceManager = null; + OSMGPFactory osmGPFactory = null; + + public OSMGPRelationLoader() + { + resourceManager = new ResourceManager("ESRI.ArcGIS.OSM.GeoProcessing.OSMGPToolsStrings", this.GetType().Assembly); + osmGPFactory = new OSMGPFactory(); + } + + #region "IGPFunction2 Implementations" + public ESRI.ArcGIS.esriSystem.UID DialogCLSID + { + get + { + return default(ESRI.ArcGIS.esriSystem.UID); + } + } + + public string DisplayName + { + get + { + if (String.IsNullOrEmpty(m_DisplayName)) + { + m_DisplayName = osmGPFactory.GetFunctionName(OSMGPFactory.m_RelationLoaderName).DisplayName; + } + + return m_DisplayName; + } + } + + public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message) + { + IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + OSMToolHelper osmToolHelper = new OSMToolHelper(); + + if (TrackCancel == null) + { + TrackCancel = new CancelTrackerClass(); + } + + IGPEnvironment configKeyword = OSMToolHelper.getEnvironment(envMgr, "configKeyword"); + IGPString gpString = configKeyword.Value as IGPString; + + string storageKeyword = String.Empty; + + if (gpString != null) + { + storageKeyword = gpString.Value; + } + + IGPParameter osmFileParameter = paramvalues.get_Element(0) as IGPParameter; + IGPValue osmFileLocationString = gpUtilities3.UnpackGPValue(osmFileParameter) as IGPValue; + + IGPParameter loadSuperRelationParameter = paramvalues.get_Element(1) as IGPParameter; + IGPBoolean loadSuperRelationGPValue = gpUtilities3.UnpackGPValue(loadSuperRelationParameter) as IGPBoolean; + + IGPParameter osmSourceLineFeatureClassParameter = paramvalues.get_Element(2) as IGPParameter; + IGPValue osmSourceLineFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmSourceLineFeatureClassParameter) as IGPValue; + + IGPParameter osmSourcePolygonFeatureClassParameter = paramvalues.get_Element(3) as IGPParameter; + IGPValue osmSourcePolygonFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmSourcePolygonFeatureClassParameter) as IGPValue; + + + IGPParameter osmTargetLineFeatureClassParameter = paramvalues.get_Element(6) as IGPParameter; + IGPValue osmTargetLineFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmTargetLineFeatureClassParameter) as IGPValue; + + IName workspaceName = gpUtilities3.CreateParentFromCatalogPath(osmTargetLineFeatureClassGPValue.GetAsText()); + IWorkspace2 lineFeatureWorkspace = workspaceName.Open() as IWorkspace2; + + string[] lineFCNameElements = osmTargetLineFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + IFeatureClass osmLineFeatureClass = null; + + IGPParameter tagLineCollectionParameter = paramvalues.get_Element(4) as IGPParameter; + IGPMultiValue tagLineCollectionGPValue = gpUtilities3.UnpackGPValue(tagLineCollectionParameter) as IGPMultiValue; + + List lineTagstoExtract = null; + + if (tagLineCollectionGPValue.Count > 0) + { + lineTagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagLineCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagLineCollectionGPValue.get_Value(valueIndex).GetAsText(); + + lineTagstoExtract.Add(nameOfTag); + } + } + else + { + lineTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + + // lines + try + { + osmLineFeatureClass = osmToolHelper.CreateSmallLineFeatureClass(lineFeatureWorkspace, + lineFCNameElements[lineFCNameElements.Length - 1], storageKeyword, "", "", lineTagstoExtract); + } + catch (Exception ex) + { + message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message)); + return; + } + + if (osmLineFeatureClass == null) + { + return; + } + + + IGPParameter osmTargetPolygonFeatureClassParameter = paramvalues.get_Element(7) as IGPParameter; + IGPValue osmTargetPolygonFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmTargetPolygonFeatureClassParameter) as IGPValue; + + workspaceName = gpUtilities3.CreateParentFromCatalogPath(osmTargetPolygonFeatureClassGPValue.GetAsText()); + IWorkspace2 polygonFeatureWorkspace = workspaceName.Open() as IWorkspace2; + + string[] polygonFCNameElements = osmTargetPolygonFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + IFeatureClass osmPolygonFeatureClass = null; + + IGPParameter tagPolygonCollectionParameter = paramvalues.get_Element(5) as IGPParameter; + IGPMultiValue tagPolygonCollectionGPValue = gpUtilities3.UnpackGPValue(tagPolygonCollectionParameter) as IGPMultiValue; + + List polygonTagstoExtract = null; + + if (tagPolygonCollectionGPValue.Count > 0) + { + polygonTagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagPolygonCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagPolygonCollectionGPValue.get_Value(valueIndex).GetAsText(); + + polygonTagstoExtract.Add(nameOfTag); + } + } + else + { + polygonTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + // polygons + try + { + osmPolygonFeatureClass = osmToolHelper.CreateSmallPolygonFeatureClass(polygonFeatureWorkspace, + polygonFCNameElements[polygonFCNameElements.Length - 1], storageKeyword, "", "", polygonTagstoExtract); + } + catch (Exception ex) + { + message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message)); + return; + } + + if (osmPolygonFeatureClass == null) + { + return; + } + + ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass); + ComReleaser.ReleaseCOMObject(osmLineFeatureClass); + + + string[] gdbComponents = new string[polygonFCNameElements.Length - 1]; + System.Array.Copy(lineFCNameElements, gdbComponents, lineFCNameElements.Length - 1); + string fileGDBLocation = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), gdbComponents); + + osmToolHelper.smallLoadOSMRelations(osmFileLocationString.GetAsText(), + osmSourceLineFeatureClassGPValue.GetAsText(), + osmSourcePolygonFeatureClassGPValue.GetAsText(), + osmTargetLineFeatureClassGPValue.GetAsText(), + osmTargetPolygonFeatureClassGPValue.GetAsText(), + lineTagstoExtract, polygonTagstoExtract, loadSuperRelationGPValue.Value); + + + } + + public ESRI.ArcGIS.esriSystem.IName FullName + { + get + { + IName fullName = null; + + if (osmGPFactory != null) + { + fullName = osmGPFactory.GetFunctionName(OSMGPFactory.m_RelationLoaderName) as IName; + } + + return fullName; + } + } + + public object GetRenderer(ESRI.ArcGIS.Geoprocessing.IGPParameter pParam) + { + return null; + } + + public int HelpContext + { + get + { + return 0; + } + } + + public string HelpFile + { + get + { + return String.Empty; + } + } + + public bool IsLicensed() + { + return true; + } + + public string MetadataFile + { + get + { + string metadafile = "osmgprelationloader.xml"; + + try + { + string[] languageid = System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Split("-".ToCharArray()); + + string ArcGISInstallationLocation = OSMGPFactory.GetArcGIS10InstallLocation(); + string localizedMetaDataFileShort = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + languageid[0] + ".xml"; + string localizedMetaDataFileLong = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + System.Threading.Thread.CurrentThread.CurrentUICulture.Name + ".xml"; + + if (System.IO.File.Exists(localizedMetaDataFileShort)) + { + metadafile = localizedMetaDataFileShort; + } + else if (System.IO.File.Exists(localizedMetaDataFileLong)) + { + metadafile = localizedMetaDataFileLong; + } + } + catch { } + + return metadafile; + } + } + + public string Name + { + get + { + return OSMGPFactory.m_RelationLoaderName; + } + } + + public ESRI.ArcGIS.esriSystem.IArray ParameterInfo + { + get + { + IArray parameters = new ArrayClass(); + + // input osm file containing the relations + IGPParameterEdit3 osmRelationFileParameter = new GPParameterClass() as IGPParameterEdit3; + osmRelationFileParameter.DataType = new DEFileTypeClass(); + osmRelationFileParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + osmRelationFileParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_osmfile_desc"); + osmRelationFileParameter.Name = "in_osmRelationFile"; + osmRelationFileParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + + // load super-relation parameter + IGPParameterEdit3 loadSuperRelationParameter = new GPParameterClass() as IGPParameterEdit3; + IGPCodedValueDomain loadSuperRelationDomain = new GPCodedValueDomainClass(); + + IGPBoolean loadSuperRelationTrue = new GPBooleanClass(); + loadSuperRelationTrue.Value = true; + IGPBoolean loadSuperRelationFalse = new GPBooleanClass(); + loadSuperRelationFalse.Value = false; + + loadSuperRelationDomain.AddCode((IGPValue)loadSuperRelationTrue, "LOAD_SUPER_RELATION"); + loadSuperRelationDomain.AddCode((IGPValue)loadSuperRelationFalse, "DO_NOT_LOAD_SUPER_RELATION"); + loadSuperRelationParameter.Domain = (IGPDomain)loadSuperRelationDomain; + loadSuperRelationParameter.Value = (IGPValue)loadSuperRelationFalse; + + loadSuperRelationParameter.DataType = new GPBooleanTypeClass(); + loadSuperRelationParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadSuperRelationParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadSuperRelationParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_loadSuperRelations_desc"); + loadSuperRelationParameter.Name = "in_loadSuperRelation"; + + + IGPParameterEdit3 osmLinesParameter = new GPParameterClass() as IGPParameterEdit3; + osmLinesParameter.DataType = new DEFeatureClassTypeClass(); + osmLinesParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + osmLinesParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmLinesParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_osmLines_desc"); + osmLinesParameter.Name = "in_SourceOSMLines"; + + IGPFeatureClassDomain osmLineFeatureClassDomain = new GPFeatureClassDomainClass(); + osmLineFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmLineFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline); + osmLinesParameter.Domain = osmLineFeatureClassDomain as IGPDomain; + + IGPParameterEdit3 osmPolygonsParameter = new GPParameterClass() as IGPParameterEdit3; + osmPolygonsParameter.DataType = new DEFeatureClassTypeClass(); + osmPolygonsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + osmPolygonsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmPolygonsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_osmPolygons_desc"); + osmPolygonsParameter.Name = "in_SourceOSMPolygons"; + + // field multi parameter + IGPParameterEdit3 loadLineFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + + IGPDataType fieldNameDataType = new GPStringTypeClass(); + IGPMultiValue fieldNameMultiValue = new GPMultiValueClass(); + fieldNameMultiValue.MemberDataType = fieldNameDataType; + + IGPMultiValueType fieldNameDataType2 = new GPMultiValueTypeClass(); + fieldNameDataType2.MemberDataType = fieldNameDataType; + + loadLineFieldsParameter.Name = "in_polyline_fieldNames"; + loadLineFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_lineFieldNames_desc"); + loadLineFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadLineFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadLineFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadLineFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadLineFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + IGPParameterEdit3 loadPolygonFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + loadPolygonFieldsParameter.Name = "in_polygon_fieldNames"; + loadPolygonFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_polygonFieldNames_desc"); + loadPolygonFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadPolygonFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadPolygonFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadPolygonFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadPolygonFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + IGPFeatureClassDomain osmPolygonFeatureClassDomain = new GPFeatureClassDomainClass(); + osmPolygonFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmPolygonFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon); + osmPolygonsParameter.Domain = osmPolygonFeatureClassDomain as IGPDomain; + + IGPParameterEdit3 osmOutLinesParameter = new GPParameterClass() as IGPParameterEdit3; + osmOutLinesParameter.DataType = new DEFeatureClassTypeClass(); + osmOutLinesParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmOutLinesParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmOutLinesParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_osmOutLines_desc"); + osmOutLinesParameter.Name = "out_osmLines"; + + IGPFeatureClassDomain osmOutLinesFeatureClassDomain = new GPFeatureClassDomainClass(); + osmOutLinesFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmOutLinesFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline); + osmOutLinesParameter.Domain = osmOutLinesFeatureClassDomain as IGPDomain; + + + IGPParameterEdit3 osmOutPolygonsParameter = new GPParameterClass() as IGPParameterEdit3; + osmOutPolygonsParameter.DataType = new DEFeatureClassTypeClass(); + osmOutPolygonsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmOutPolygonsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmOutPolygonsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPRelationLoader_osmOutPolygons_desc"); + osmOutPolygonsParameter.Name = "out_osmPolygons"; + + IGPFeatureClassDomain osmOutPolygonFeatureClassDomain = new GPFeatureClassDomainClass(); + osmOutPolygonFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmOutPolygonFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon); + osmOutPolygonsParameter.Domain = osmOutPolygonFeatureClassDomain as IGPDomain; + + // add all the parameters into the info array + parameters.Add(osmRelationFileParameter); + parameters.Add(loadSuperRelationParameter); + parameters.Add(osmLinesParameter); + parameters.Add(osmPolygonsParameter); + parameters.Add(loadLineFieldsParameter); + parameters.Add(loadPolygonFieldsParameter); + parameters.Add(osmOutLinesParameter); + parameters.Add(osmOutPolygonsParameter); + + return parameters; + + } + } + + public void UpdateMessages(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr, ESRI.ArcGIS.Geodatabase.IGPMessages Messages) + { + } + + public void UpdateParameters(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr) + { + } + + public ESRI.ArcGIS.Geodatabase.IGPMessages Validate(ESRI.ArcGIS.esriSystem.IArray paramvalues, bool updateValues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr) + { + return default(ESRI.ArcGIS.Geodatabase.IGPMessages); + } + #endregion + + } +} diff --git a/src/OSMGeoProcessing/OSMGPRemoveExtension.cs b/src/OSMGeoProcessing/OSMGPRemoveExtension.cs index 07cadd6..0518e19 100644 --- a/src/OSMGeoProcessing/OSMGPRemoveExtension.cs +++ b/src/OSMGeoProcessing/OSMGPRemoveExtension.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPSymbolizer.cs b/src/OSMGeoProcessing/OSMGPSymbolizer.cs index a9e4ba1..dc3f56e 100644 --- a/src/OSMGeoProcessing/OSMGPSymbolizer.cs +++ b/src/OSMGeoProcessing/OSMGPSymbolizer.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMGeoProcessing/OSMGPToolsStrings.resx b/src/OSMGeoProcessing/OSMGPToolsStrings.resx index bee9c1d..9bb5dda 100644 --- a/src/OSMGeoProcessing/OSMGPToolsStrings.resx +++ b/src/OSMGeoProcessing/OSMGPToolsStrings.resx @@ -867,4 +867,160 @@ Add OSM tag keys to schema + + Data Delivery + + + OSM File Loader (Load only) + + + Load OSM file without the metadata. Data loaded without the metadata cannot be uploaded back to the OSM server. + + + OSM File + + + Target feature dataset + + + OpenStreetMap feature classes + + + OpenStreetMap point features + + + OpenStreetMap line features + + + OpenStreetMap polygon features + + + Delete supporting nodes + + + Delete OSM source file + + + Problem accessing the OSM file ({0}). + + + The specified OSM file ({0}) does not exist. + + + Counted {0} nodes, {1} ways, and {2} relations. + + + Loading nodes... + + + Done loading nodes (Elapsed Time: {0} hours {1} minutes {2} seconds). + + + Loading ways... + + + Done loading ways (Elapsed Time: {0} hours {1} minutes {2} seconds). + + + Loading relations... + + + Done loading relations (Elapsed Time: {0} hours {1} minutes {2} seconds). + + + Loading super relations... + + + Done loading super relations (Elapsed Time: {0} hours {1} minutes {2} seconds). + + + Removing support nodes... + + + Schema information + + + Data Delivery + + + OSM Node Loader + + + Loads OSM Nodes. + + + OSM File + + + OpenStreetMap point features + + + Node tag keys to load for point features + + + Use feature cache + + + Data Delivery + + + OSM Way Loader + + + Loads OSM ways. + + + OSM File + + + OpenStreetMap line features + + + OpenStreetMap polygon features + + + Way tag keys to load for line features + + + Way tag keys to load for polygon features + + + Source OpenStreetMap point features + + + Data Delivery + + + OSM Relation Loader + + + Loads OSM relations. + + + OSM File + + + Source OpenStreetMap line features + + + Source OpenStreetMap polygon features + + + Loaded OpenStreetMap Point/Node features + + + OpenStreetMap line features + + + OpenStreetMap polygon features + + + Relation tag keys to load for line features + + + Relation tag keys to load for polygon features + + + Load super relations + \ No newline at end of file diff --git a/src/OSMGeoProcessing/OSMGPToolsStrings.txt b/src/OSMGeoProcessing/OSMGPToolsStrings.txt index afae2da..d2b8890 100644 --- a/src/OSMGeoProcessing/OSMGPToolsStrings.txt +++ b/src/OSMGeoProcessing/OSMGPToolsStrings.txt @@ -251,4 +251,57 @@ GPTools_OSM_relations=relations GPTools_OSM_superrelations=super-relations GPTools_OSMGPDiffLoader_loadtime_message=The diff loaded in {0} minutes. GPTools_OSMFileLoader_schemaCategory=Adjust input schema -GPTools_OSMFileLoader_attributeSchemaSelection=Add OSM tag keys to schema \ No newline at end of file +GPTools_OSMFileLoader_attributeSchemaSelection=Add OSM tag keys to schema +# 2.4 +GPTools_OSMGPMultiLoader_categoryName=Data Delivery +GPTools_OSMGPMultiLoader_displayName=OSM File Loader (Load only) +GPTools_OSMGPMultiLoader_desc=Load OSM file without the metadata. Data loaded without the metadata cannot be uploaded back to the OSM server. +GPTools_OSMGPMultiLoader_osmfile_desc=OSM File +GPTools_OSMGPMultiLoader_targetDataset_desc=Target feature dataset +GPTools_OSMGPMultiLoader_outputCategory=OpenStreetMap feature classes +GPTools_OSMGPMultiLoader_osmPoints_desc=OpenStreetMap point features +GPTools_OSMGPMultiLoader_osmLine_desc=OpenStreetMap line features +GPTools_OSMGPMultiLoader_osmPolygon_desc=OpenStreetMap polygon features +GPTools_OSMGPMultiLoader_deleteNodes_desc=Delete supporting nodes +GPTools_OSMGPMultiLoader_deleteOSMSource_desc=Delete OSM source file +GPTools_OSMGPMultiLoader_problemaccessingfile=Problem accessing the OSM file ({0}). +GPTools_OSMGPMultiLoader_osmfiledoesnotexist=The specified OSM file ({0}) does not exist. +GPTools_OSMGPMultiLoader_countedElements=Counted {0} nodes, {1} ways, and {2} relations. +GPTools_OSMGPMultiLoader_loading_nodes=Loading nodes... +GPTools_OSMGPMultiLoader_doneloading_nodes=Done loading nodes (Elapsed Time: {0} hours {1} minutes {2} seconds). +GPTools_OSMGPMultiLoader_loading_ways=Loading ways... +GPTools_OSMGPMultiLoader_doneloading_ways=Done loading ways (Elapsed Time: {0} hours {1} minutes {2} seconds). +GPTools_OSMGPMultiLoader_loading_relations=Loading relations... +GPTools_OSMGPMultiLoader_doneloading_relations=Done loading relations (Elapsed Time: {0} hours {1} minutes {2} seconds). +GPTools_OSMGPMultiLoader_loading_super_relations=Loading super relations... +GPTools_OSMGPMultiLoader_doneloading_super_relations=Done loading super relations (Elapsed Time: {0} hours {1} minutes {2} seconds). +GPTools_OSMGPMultiLoader_remove_supportNodes=Removing support nodes... +GPTools_OSMGPMultiLoader_schemaCategory_desc=Schema information +GPTools_OSMGPNodeLoader_categoryName=Data Delivery +GPTools_OSMGPNodeLoader_displayName=OSM Node Loader +GPTools_OSMGPNodeLoader_desc=Loads OSM Nodes. +GPTools_OSMGPNodeLoader_osmfile_desc=OSM File +GPTools_OSMGPNodeLoader_osmPoints_desc=OpenStreetMap point features +GPTools_OSMGPNodeLoader_fieldNames_desc=Node tag keys to load for point features +GPTools_OSMGPNodeLoader_useCache_desc=Use feature cache +GPTools_OSMGPWayLoader_categoryName=Data Delivery +GPTools_OSMGPWayLoader_displayName=OSM Way Loader +GPTools_OSMGPWayLoader_desc=Loads OSM ways. +GPTools_OSMGPWayLoader_osmfile_desc=OSM File +GPTools_OSMGPWayLoader_osmLines_desc=OpenStreetMap line features +GPTools_OSMGPWayLoader_osmPolygons_desc=OpenStreetMap polygon features +GPTools_OSMGPWayLoader_lineFieldNames_desc=Way tag keys to load for line features +GPTools_OSMGPWayLoader_polygonFieldNames_desc=Way tag keys to load for polygon features +GPTools_OSMGPWayLoader_osmpointFeatureClass_desc=Source OpenStreetMap point features +GPTools_OSMGPRelationLoader_categoryName=Data Delivery +GPTools_OSMGPRelationLoader_displayName=OSM Relation Loader +GPTools_OSMGPRelationLoader_desc=Loads OSM relations. +GPTools_OSMGPRelationLoader_osmfile_desc=OSM File +GPTools_OSMGPRelationLoader_osmLines_desc=Source OpenStreetMap line features +GPTools_OSMGPRelationLoader_osmPolygons_desc=Source OpenStreetMap polygon features +GPTools_OSMGPRelationLoader_osmpointFeatureClass_desc=Loaded OpenStreetMap Point/Node features +GPTools_OSMGPRelationLoader_osmOutLines_desc=OpenStreetMap line features +GPTools_OSMGPRelationLoader_osmOutPolygons_desc=OpenStreetMap polygon features +GPTools_OSMGPRelationLoader_lineFieldNames_desc=Relation tag keys to load for line features +GPTools_OSMGPRelationLoader_polygonFieldNames_desc=Relation tag keys to load for polygon features +GPTools_OSMGPRelationLoader_loadSuperRelations_desc=Load super relations \ No newline at end of file diff --git a/src/OSMGeoProcessing/OSMGPUpload.cs b/src/OSMGeoProcessing/OSMGPUpload.cs index 913aa23..ab956b2 100644 --- a/src/OSMGeoProcessing/OSMGPUpload.cs +++ b/src/OSMGeoProcessing/OSMGPUpload.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. @@ -191,7 +191,7 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS tag createdByTag = new tag(); createdByTag.k = "created_by"; - createdByTag.v = "ArcGIS Editor for OpenStreetMap (10.2)"; + createdByTag.v = "ArcGIS Editor for OpenStreetMap"; changeSetTags.Add(createdByTag); tag commentTag = new tag(); @@ -277,7 +277,7 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS IGPParameter revisionTableParameter = paramvalues.get_Element(in_changesTablesNumber) as IGPParameter; - int featureUpdateCounter = 1; + int featureUpdateCounter = 0; IQueryFilter revisionTableQueryFilter = null; @@ -520,7 +520,7 @@ public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriS // if the overall number of uploaded elements is too big for a single changeset we do need to split it up // into multiple sets - if ((featureUpdateCounter % maxElementsinChangeSet) == 0) + if (featureUpdateCounter > 0 & (featureUpdateCounter % maxElementsinChangeSet) == 0) { // add any outstanding creations to the changeset items if (listOfCreates != null && uploadCreates != null) diff --git a/src/OSMGeoProcessing/OSMGPWayLoader.cs b/src/OSMGeoProcessing/OSMGPWayLoader.cs new file mode 100644 index 0000000..8fa9752 --- /dev/null +++ b/src/OSMGeoProcessing/OSMGPWayLoader.cs @@ -0,0 +1,383 @@ +// (c) Copyright Esri, 2010 - 2016 +// This source is subject to the Apache 2.0 License. +// Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. +// All other rights reserved. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Resources; +using ESRI.ArcGIS.esriSystem; +using ESRI.ArcGIS.Geoprocessing; +using ESRI.ArcGIS.DataSourcesFile; +using ESRI.ArcGIS.Geodatabase; +using ESRI.ArcGIS.Display; +using ESRI.ArcGIS.OSM.OSMClassExtension; + +namespace ESRI.ArcGIS.OSM.GeoProcessing +{ + [Guid("f1c4f01d-bf2c-4f2b-b8fa-8b9b701ee160")] + [ClassInterface(ClassInterfaceType.None)] + [ProgId("OSMEditor.OSMGPWayLoader")] + public class OSMGPWayLoader : ESRI.ArcGIS.Geoprocessing.IGPFunction2 + { + + string m_DisplayName = String.Empty; + ResourceManager resourceManager = null; + OSMGPFactory osmGPFactory = null; + + public OSMGPWayLoader() + { + resourceManager = new ResourceManager("ESRI.ArcGIS.OSM.GeoProcessing.OSMGPToolsStrings", this.GetType().Assembly); + osmGPFactory = new OSMGPFactory(); + + } + + #region "IGPFunction2 Implementations" + public ESRI.ArcGIS.esriSystem.UID DialogCLSID + { + get + { + return default(ESRI.ArcGIS.esriSystem.UID); + } + } + + public string DisplayName + { + get + { + if (String.IsNullOrEmpty(m_DisplayName)) + { + m_DisplayName = osmGPFactory.GetFunctionName(OSMGPFactory.m_WayLoaderName).DisplayName; + } + + return m_DisplayName; + } + } + + public void Execute(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.esriSystem.ITrackCancel TrackCancel, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr, ESRI.ArcGIS.Geodatabase.IGPMessages message) + { + IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + OSMToolHelper osmToolHelper = new OSMToolHelper(); + + if (TrackCancel == null) + { + TrackCancel = new CancelTrackerClass(); + } + + IGPEnvironment configKeyword = OSMToolHelper.getEnvironment(envMgr, "configKeyword"); + IGPString gpString = configKeyword.Value as IGPString; + + string storageKeyword = String.Empty; + + if (gpString != null) + { + storageKeyword = gpString.Value; + } + + IGPParameter osmFileParameter = paramvalues.get_Element(0) as IGPParameter; + IGPValue osmFileLocationString = gpUtilities3.UnpackGPValue(osmFileParameter) as IGPValue; + + IGPParameter osmLineFeatureClassParameter = paramvalues.get_Element(4) as IGPParameter; + IGPValue osmLineFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmLineFeatureClassParameter) as IGPValue; + + IName workspaceName = gpUtilities3.CreateParentFromCatalogPath(osmLineFeatureClassGPValue.GetAsText()); + IWorkspace2 lineFeatureWorkspace = workspaceName.Open() as IWorkspace2; + + string[] lineFCNameElements = osmLineFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + IFeatureClass osmLineFeatureClass = null; + + + IGPParameter tagLineCollectionParameter = paramvalues.get_Element(2) as IGPParameter; + IGPMultiValue tagLineCollectionGPValue = gpUtilities3.UnpackGPValue(tagLineCollectionParameter) as IGPMultiValue; + + List lineTagstoExtract = null; + + if (tagLineCollectionGPValue.Count > 0) + { + lineTagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagLineCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagLineCollectionGPValue.get_Value(valueIndex).GetAsText(); + + lineTagstoExtract.Add(nameOfTag); + } + } + else + { + lineTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + + + // lines + try + { + osmLineFeatureClass = osmToolHelper.CreateSmallLineFeatureClass(lineFeatureWorkspace, lineFCNameElements[lineFCNameElements.Length - 1], storageKeyword, "", "", lineTagstoExtract); + } + catch (Exception ex) + { + message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message)); + return; + } + + if (osmLineFeatureClass == null) + { + return; + } + + + IGPParameter osmPolygonFeatureClassParameter = paramvalues.get_Element(5) as IGPParameter; + IGPValue osmPolygonFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmPolygonFeatureClassParameter) as IGPValue; + + workspaceName = gpUtilities3.CreateParentFromCatalogPath(osmPolygonFeatureClassGPValue.GetAsText()); + IWorkspace2 polygonFeatureWorkspace = workspaceName.Open() as IWorkspace2; + + string[] polygonFCNameElements = osmPolygonFeatureClassGPValue.GetAsText().Split(System.IO.Path.DirectorySeparatorChar); + + IFeatureClass osmPolygonFeatureClass = null; + + IGPParameter tagPolygonCollectionParameter = paramvalues.get_Element(3) as IGPParameter; + IGPMultiValue tagPolygonCollectionGPValue = gpUtilities3.UnpackGPValue(tagPolygonCollectionParameter) as IGPMultiValue; + + List polygonTagstoExtract = null; + + if (tagPolygonCollectionGPValue.Count > 0) + { + polygonTagstoExtract = new List(); + + for (int valueIndex = 0; valueIndex < tagPolygonCollectionGPValue.Count; valueIndex++) + { + string nameOfTag = tagPolygonCollectionGPValue.get_Value(valueIndex).GetAsText(); + + polygonTagstoExtract.Add(nameOfTag); + } + } + else + { + polygonTagstoExtract = OSMToolHelper.OSMSmallFeatureClassFields(); + } + + + // polygons + try + { + osmPolygonFeatureClass = osmToolHelper.CreateSmallPolygonFeatureClass(polygonFeatureWorkspace, polygonFCNameElements[polygonFCNameElements.Length - 1], storageKeyword, "", "", polygonTagstoExtract); + } + catch (Exception ex) + { + message.AddError(120035, String.Format(resourceManager.GetString("GPTools_OSMGPDownload_nullpointfeatureclass"), ex.Message)); + return; + } + + if (osmPolygonFeatureClass == null) + { + return; + } + + ComReleaser.ReleaseCOMObject(osmPolygonFeatureClass); + ComReleaser.ReleaseCOMObject(osmLineFeatureClass); + + IGPParameter osmPointFeatureClassParameter = paramvalues.get_Element(1) as IGPParameter; + IGPValue osmPointFeatureClassGPValue = gpUtilities3.UnpackGPValue(osmPointFeatureClassParameter) as IGPValue; + + string[] gdbComponents = new string[polygonFCNameElements.Length - 1]; + System.Array.Copy(lineFCNameElements, gdbComponents, lineFCNameElements.Length - 1); + string fileGDBLocation = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), gdbComponents); + + osmToolHelper.smallLoadOSMWay(osmFileLocationString.GetAsText(), osmPointFeatureClassGPValue.GetAsText(), fileGDBLocation, lineFCNameElements[lineFCNameElements.Length - 1], polygonFCNameElements[polygonFCNameElements.Length - 1], lineTagstoExtract, polygonTagstoExtract); + } + + public ESRI.ArcGIS.esriSystem.IName FullName + { + get + { + IName fullName = null; + + if (osmGPFactory != null) + { + fullName = osmGPFactory.GetFunctionName(OSMGPFactory.m_WayLoaderName) as IName; + } + + return fullName; + } + } + + public object GetRenderer(ESRI.ArcGIS.Geoprocessing.IGPParameter pParam) + { + return null; + } + + public int HelpContext + { + get + { + return 0; + } + } + + public string HelpFile + { + get + { + return String.Empty; + } + } + + public bool IsLicensed() + { + return true; + } + + public string MetadataFile + { + get + { + string metadafile = "osmgpwayloader.xml"; + + try + { + string[] languageid = System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Split("-".ToCharArray()); + + string ArcGISInstallationLocation = OSMGPFactory.GetArcGIS10InstallLocation(); + string localizedMetaDataFileShort = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + languageid[0] + ".xml"; + string localizedMetaDataFileLong = ArcGISInstallationLocation + System.IO.Path.DirectorySeparatorChar.ToString() + "help" + System.IO.Path.DirectorySeparatorChar.ToString() + "gp" + System.IO.Path.DirectorySeparatorChar.ToString() + "osmgpfileloader_" + System.Threading.Thread.CurrentThread.CurrentUICulture.Name + ".xml"; + + if (System.IO.File.Exists(localizedMetaDataFileShort)) + { + metadafile = localizedMetaDataFileShort; + } + else if (System.IO.File.Exists(localizedMetaDataFileLong)) + { + metadafile = localizedMetaDataFileLong; + } + } + catch { } + + return metadafile; + } + } + + public string Name + { + get + { + return OSMGPFactory.m_WayLoaderName; + } + } + + public ESRI.ArcGIS.esriSystem.IArray ParameterInfo + { + get + { + IArray parameters = new ArrayClass(); + + // input osm file containing the ways + IGPParameterEdit3 osmWayFileParameter = new GPParameterClass() as IGPParameterEdit3; + osmWayFileParameter.DataType = new DEFileTypeClass(); + osmWayFileParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + osmWayFileParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_osmfile_desc"); + osmWayFileParameter.Name = "in_osmWayFile"; + osmWayFileParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + + // input feature class containing the points + IGPParameterEdit3 osmPointFeatureClassParameter = new GPParameterClass() as IGPParameterEdit3; + osmPointFeatureClassParameter.DataType = new DEFeatureClassTypeClass(); + osmPointFeatureClassParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + osmPointFeatureClassParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_osmpointFeatureClass_desc"); + osmPointFeatureClassParameter.Name = "in_osmPointFC"; + osmPointFeatureClassParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + + + IGPFeatureClassDomain osmPointFeatureClassDomain = new GPFeatureClassDomainClass(); + osmPointFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmPointFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint); + osmPointFeatureClassParameter.Domain = osmPointFeatureClassDomain as IGPDomain; + + + // field multi parameter + IGPParameterEdit3 loadLineFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + + IGPDataType fieldNameDataType = new GPStringTypeClass(); + IGPMultiValue fieldNameMultiValue = new GPMultiValueClass(); + fieldNameMultiValue.MemberDataType = fieldNameDataType; + + IGPMultiValueType fieldNameDataType2 = new GPMultiValueTypeClass(); + fieldNameDataType2.MemberDataType = fieldNameDataType; + + loadLineFieldsParameter.Name = "in_polyline_fieldNames"; + loadLineFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_lineFieldNames_desc"); + loadLineFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadLineFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadLineFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadLineFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadLineFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + IGPParameterEdit3 loadPolygonFieldsParameter = new GPParameterClass() as IGPParameterEdit3; + loadPolygonFieldsParameter.Name = "in_polygon_fieldNames"; + loadPolygonFieldsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_polygonFieldNames_desc"); + loadPolygonFieldsParameter.Category = resourceManager.GetString("GPTools_OSMGPMultiLoader_schemaCategory_desc"); + loadPolygonFieldsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeOptional; + loadPolygonFieldsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionInput; + loadPolygonFieldsParameter.DataType = (IGPDataType)fieldNameDataType2; + loadPolygonFieldsParameter.Value = (IGPValue)fieldNameMultiValue; + + + IGPParameterEdit3 osmLinesParameter = new GPParameterClass() as IGPParameterEdit3; + osmLinesParameter.DataType = new DEFeatureClassTypeClass(); + osmLinesParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmLinesParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmLinesParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_osmLines_desc"); + osmLinesParameter.Name = "out_osmWayLines"; + + IGPFeatureClassDomain osmLineFeatureClassDomain = new GPFeatureClassDomainClass(); + osmLineFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmLineFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline); + osmLinesParameter.Domain = osmLineFeatureClassDomain as IGPDomain; + + IGPParameterEdit3 osmPolygonsParameter = new GPParameterClass() as IGPParameterEdit3; + osmPolygonsParameter.DataType = new DEFeatureClassTypeClass(); + osmPolygonsParameter.Direction = esriGPParameterDirection.esriGPParameterDirectionOutput; + osmPolygonsParameter.ParameterType = esriGPParameterType.esriGPParameterTypeRequired; + osmPolygonsParameter.DisplayName = resourceManager.GetString("GPTools_OSMGPWayLoader_osmPolygons_desc"); + osmPolygonsParameter.Name = "out_osmWayPolygons"; + + IGPFeatureClassDomain osmPolygonFeatureClassDomain = new GPFeatureClassDomainClass(); + osmPolygonFeatureClassDomain.AddFeatureType(esriFeatureType.esriFTSimple); + osmPolygonFeatureClassDomain.AddType(ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon); + osmPolygonsParameter.Domain = osmPolygonFeatureClassDomain as IGPDomain; + + parameters.Add(osmWayFileParameter); + + parameters.Add(osmPointFeatureClassParameter); + + parameters.Add(loadLineFieldsParameter); + + parameters.Add(loadPolygonFieldsParameter); + + parameters.Add(osmLinesParameter); + + parameters.Add(osmPolygonsParameter); + + return parameters; + } + } + + public void UpdateMessages(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr, ESRI.ArcGIS.Geodatabase.IGPMessages Messages) + { + } + + public void UpdateParameters(ESRI.ArcGIS.esriSystem.IArray paramvalues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager pEnvMgr) + { + } + + public ESRI.ArcGIS.Geodatabase.IGPMessages Validate(ESRI.ArcGIS.esriSystem.IArray paramvalues, bool updateValues, ESRI.ArcGIS.Geoprocessing.IGPEnvironmentManager envMgr) + { + return default(ESRI.ArcGIS.Geodatabase.IGPMessages); + } + #endregion + + } +} diff --git a/src/OSMGeoProcessing/OSMToolHelper.cs b/src/OSMGeoProcessing/OSMToolHelper.cs index 6028af9..d01c766 100644 --- a/src/OSMGeoProcessing/OSMToolHelper.cs +++ b/src/OSMGeoProcessing/OSMToolHelper.cs @@ -17,6 +17,12 @@ using ESRI.ArcGIS.Geoprocessing; using System.Text; using System.Text.RegularExpressions; +using ESRI.ArcGIS.DataSourcesGDB; +using System.Xml.Linq; +using System.Threading; +using ESRI.ArcGIS.DataSourcesFile; +using System.Collections; +using System.Diagnostics; namespace ESRI.ArcGIS.OSM.GeoProcessing @@ -29,6 +35,9 @@ public class OSMToolHelper { ResourceManager _resourceManager = null; OSMUtility _osmUtility = null; + private static Semaphore _pool; + private static ManualResetEvent _manualResetEvent; + private static int _numberOfThreads = 0; [ComVisible(false)] public class OSMNodeFeature @@ -137,13 +146,18 @@ public OSMToolHelper() _osmUtility = null; } + public static List OSMSmallFeatureClassFields() + { + return new List(){"name", "highway", "building", "natural", "waterway", "amenity", "landuse", "place", "railway", "boundary", "power", "leisure", + "man_made", "shop", "tourism", "route", "barrier", "surface", "type", "service", "sport"}; + } + #region"Create OSM Point FeatureClass" internal IFeatureClass CreatePointFeatureClass(ESRI.ArcGIS.Geodatabase.IWorkspace2 workspace, ESRI.ArcGIS.Geodatabase.IFeatureDataset featureDataset, System.String featureClassName, ESRI.ArcGIS.Geodatabase.IFields fields, ESRI.ArcGIS.esriSystem.UID CLSID, ESRI.ArcGIS.esriSystem.UID CLSEXT, System.String strConfigKeyword, OSMDomains osmDomains, string metadataAbstract, string metadataPurpose) { return CreatePointFeatureClass(workspace, featureDataset, featureClassName, fields, CLSID, CLSEXT, strConfigKeyword, osmDomains, metadataAbstract, metadataPurpose, null); } - ///Simple helper to create a featureclass in a geodatabase. /// ///An IWorkspace2 interface @@ -235,8 +249,10 @@ internal IFeatureClass CreatePointFeatureClass(ESRI.ArcGIS.Geodatabase.IWorkspac } catch (Exception ex) { +#if DEBUG System.Diagnostics.Debug.WriteLine(ex.Message); System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif } fieldsEdit.AddField((IField)domainField); @@ -384,8 +400,8 @@ internal IFeatureClass CreatePointFeatureClass(ESRI.ArcGIS.Geodatabase.IWorkspac geometryDef.GeometryType_2 = esriGeometryType.esriGeometryPoint; geometryDef.HasZ_2 = false; geometryDef.HasM_2 = false; - geometryDef.GridCount_2 = 1; - geometryDef.set_GridSize(0, 0); + //geometryDef.GridCount_2 = 1; + //geometryDef.set_GridSize(0, 0); geometryDef.SpatialReference_2 = ((IGeoDataset)featureDataset).SpatialReference; @@ -450,8 +466,170 @@ internal IFeatureClass CreatePointFeatureClass(ESRI.ArcGIS.Geodatabase.IWorkspac } catch (Exception ex) { +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + throw; + } + + return featureClass; + } + + ///Simple helper to create a featureclass in a geodatabase. + /// + ///An IWorkspace2 interface + ///A System.String that contains the name of the feature class to open or create. Example: "states" + ///An empty System.String or RDBMS table string for ArcSDE. Example: "myTable" or "" + /// + ///An IFeatureClass interface or a Nothing + /// + /// + /// (1) If a 'featureClassName' already exists in the workspace a reference to that feature class + /// object will be returned. + /// + internal IFeatureClass CreateSmallPointFeatureClass(ESRI.ArcGIS.Geodatabase.IWorkspace2 workspace, System.String featureClassName, System.String strConfigKeyword, string metadataAbstract, string metadataPurpose, List additionalTagFields) + { + if (featureClassName == "") return null; // name was not passed in + + ESRI.ArcGIS.Geodatabase.IFeatureClass featureClass = null; + + try + { + ESRI.ArcGIS.Geodatabase.IFeatureWorkspace featureWorkspace = (ESRI.ArcGIS.Geodatabase.IFeatureWorkspace)workspace; // Explicit Cast + + if (workspace.get_NameExists(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTFeatureClass, featureClassName)) //feature class with that name already exists + { + // if a feature class with the same name already exists delete it.... + featureClass = featureWorkspace.OpenFeatureClass(featureClassName); + + if (!DeleteDataset((IDataset)featureClass)) + { + return featureClass; + } + } + + String illegalCharacters = String.Empty; + + ISQLSyntax sqlSyntax = workspace as ISQLSyntax; + if (sqlSyntax != null) + { + illegalCharacters = sqlSyntax.GetInvalidCharacters(); + } + + // assign the class id value if not assigned + UID CLSID = new ESRI.ArcGIS.esriSystem.UIDClass(); + CLSID.Value = "esriGeoDatabase.Feature"; + + ESRI.ArcGIS.Geodatabase.IObjectClassDescription objectClassDescription = new ESRI.ArcGIS.Geodatabase.FeatureClassDescriptionClass(); + + // create the fields using the required fields method + IFields fields = objectClassDescription.RequiredFields; + ESRI.ArcGIS.Geodatabase.IFieldsEdit fieldsEdit = (ESRI.ArcGIS.Geodatabase.IFieldsEdit)fields; // Explicit Cast + + // add the OSM ID field + IFieldEdit osmIDField = new FieldClass() as IFieldEdit; + osmIDField.Name_2 = "OSMID"; + osmIDField.Required_2 = true; + osmIDField.Type_2 = esriFieldType.esriFieldTypeString; + osmIDField.Length_2 = 20; + fieldsEdit.AddField((IField)osmIDField); + + // add the field for the tag cloud for all other tag/value pairs + IFieldEdit osmXmlTagsField = new FieldClass() as IFieldEdit; + osmXmlTagsField.Name_2 = "osmTags"; + osmXmlTagsField.Required_2 = true; + osmXmlTagsField.Type_2 = esriFieldType.esriFieldTypeBlob; + fieldsEdit.AddField((IField)osmXmlTagsField); + + + IFieldEdit osmSupportingElementField = new FieldClass() as IFieldEdit; + osmSupportingElementField.Name_2 = "osmSupportingElement"; + osmSupportingElementField.Required_2 = true; + osmSupportingElementField.Type_2 = esriFieldType.esriFieldTypeString; + osmSupportingElementField.Length_2 = 5; + osmSupportingElementField.DefaultValue_2 = "no"; + fieldsEdit.AddField((IField)osmSupportingElementField); + + if (additionalTagFields != null) + { + foreach (string nameOfTag in additionalTagFields) + { + IFieldEdit osmTagAttributeField = new FieldClass() as IFieldEdit; + osmTagAttributeField.Name_2 = OSMToolHelper.convert2AttributeFieldName(nameOfTag, illegalCharacters); + osmTagAttributeField.AliasName_2 = nameOfTag + _resourceManager.GetString("GPTools_OSMGPAttributeSelector_aliasaddition"); + osmTagAttributeField.Type_2 = esriFieldType.esriFieldTypeString; + osmTagAttributeField.Length_2 = 100; + osmTagAttributeField.Required_2 = false; + + fieldsEdit.AddField((IField)osmTagAttributeField); + } + } + + fields = (ESRI.ArcGIS.Geodatabase.IFields)fieldsEdit; // Explicit Cast + + System.String strShapeField = ""; + + ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory; + ISpatialReference wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference; + + // locate the shape field + for (int j = 0; j < fields.FieldCount; j++) + { + if (fields.get_Field(j).Type == ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeGeometry) + { + strShapeField = fields.get_Field(j).Name; + + // redefine geometry type + + IFieldEdit shapeField = fields.get_Field(j) as IFieldEdit; + IGeometryDefEdit geometryDef = new GeometryDefClass() as IGeometryDefEdit; + geometryDef.GeometryType_2 = esriGeometryType.esriGeometryPoint; + geometryDef.HasZ_2 = false; + geometryDef.HasM_2 = false; + //geometryDef.GridCount_2 = 1; + //geometryDef.set_GridSize(0, 0); + + geometryDef.SpatialReference_2 = wgs84; + + shapeField.GeometryDef_2 = (IGeometryDef)geometryDef; + + break; + } + } + + // Use IFieldChecker to create a validated fields collection. + ESRI.ArcGIS.Geodatabase.IFieldChecker fieldChecker = new ESRI.ArcGIS.Geodatabase.FieldCheckerClass(); + ESRI.ArcGIS.Geodatabase.IEnumFieldError enumFieldError = null; + ESRI.ArcGIS.Geodatabase.IFields validatedFields = null; + fieldChecker.ValidateWorkspace = (ESRI.ArcGIS.Geodatabase.IWorkspace)workspace; + fieldChecker.Validate(fields, out enumFieldError, out validatedFields); + + // The enumFieldError enumerator can be inspected at this point to determine + // which fields were modified during validation. + + + // finally create and return the feature class + try + { + featureClass = featureWorkspace.CreateFeatureClass(featureClassName, validatedFields, CLSID, null, ESRI.ArcGIS.Geodatabase.esriFeatureType.esriFTSimple, strShapeField, strConfigKeyword); + } + catch + { + throw; + } + + // create the openstreetmap specific metadata + _osmUtility.CreateOSMMetadata((IDataset)featureClass, metadataAbstract, metadataPurpose); + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(((IWorkspace)workspace).PathName); + System.Diagnostics.Debug.WriteLine(featureClassName); System.Diagnostics.Debug.WriteLine(ex.Message); System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif throw; } @@ -524,10 +702,10 @@ internal ESRI.ArcGIS.Geodatabase.ITable CreateRelationTable(ESRI.ArcGIS.Geodatab // if a table with the same name already exists delete it.... table = featureWorkspace.OpenTable(tableName); - if (!DeleteDataset((IDataset)table)) - { + //if (!DeleteDataset((IDataset)table)) + //{ return table; - } + //} } uid.Value = "esriGeoDatabase.Object"; @@ -909,8 +1087,10 @@ internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreateLineFeatureClass(ESRI.ArcGI } catch (Exception ex) { +#if DEBUG System.Diagnostics.Debug.WriteLine(ex.Message); System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif } fieldsEdit.AddField((IField)domainField); @@ -1064,8 +1244,8 @@ internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreateLineFeatureClass(ESRI.ArcGI geometryDef.GeometryType_2 = esriGeometryType.esriGeometryPolyline; geometryDef.HasZ_2 = false; geometryDef.HasM_2 = false; - geometryDef.GridCount_2 = 1; - geometryDef.set_GridSize(0, 0); + //geometryDef.GridCount_2 = 1; + //geometryDef.set_GridSize(0, 0); geometryDef.SpatialReference_2 = ((IGeoDataset)featureDataset).SpatialReference; @@ -1119,6 +1299,153 @@ internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreateLineFeatureClass(ESRI.ArcGI return featureClass; } + + + ///Simple helper to create a the small OSM featureclass in a geodatabase. + /// + ///An IWorkspace2 interface + ///A System.String that contains the name of the feature class to open or create. Example: "states" + ///An empty System.String or RDBMS table string for ArcSDE. Example: "myTable" or "" + /// + ///An IFeatureClass interface or a Nothing + /// + /// + /// (1) If a 'featureClassName' already exists in the workspace a reference to that feature class + /// object will be returned. + /// + internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreateSmallLineFeatureClass(ESRI.ArcGIS.Geodatabase.IWorkspace2 workspace, System.String featureClassName, System.String strConfigKeyword, string metadataAbstract, string metadataPurpose, List additionalTagFields) + { + if (featureClassName == "") return null; // name was not passed in + + ESRI.ArcGIS.Geodatabase.IFeatureClass featureClass = null; + + try + { + ESRI.ArcGIS.Geodatabase.IFeatureWorkspace featureWorkspace = (ESRI.ArcGIS.Geodatabase.IFeatureWorkspace)workspace; // Explicit Cast + + if (workspace.get_NameExists(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTFeatureClass, featureClassName)) //feature class with that name already exists + { + // if a feature class with the same name already exists delete it.... + featureClass = featureWorkspace.OpenFeatureClass(featureClassName); + + if (!DeleteDataset((IDataset)featureClass)) + { + return featureClass; + } + } + + String illegalCharacters = String.Empty; + + ISQLSyntax sqlSyntax = workspace as ISQLSyntax; + if (sqlSyntax != null) + { + illegalCharacters = sqlSyntax.GetInvalidCharacters(); + } + + // assign the class id value if not assigned + UID CLSID = new ESRI.ArcGIS.esriSystem.UIDClass(); + CLSID.Value = "esriGeoDatabase.Feature"; + + ESRI.ArcGIS.Geodatabase.IObjectClassDescription objectClassDescription = new ESRI.ArcGIS.Geodatabase.FeatureClassDescriptionClass(); + + // create the fields using the required fields method + IFields fields = objectClassDescription.RequiredFields; + ESRI.ArcGIS.Geodatabase.IFieldsEdit fieldsEdit = (ESRI.ArcGIS.Geodatabase.IFieldsEdit)fields; // Explicit Cast + + // add the OSM ID field + IFieldEdit osmIDField = new FieldClass() as IFieldEdit; + osmIDField.Name_2 = "OSMID"; + osmIDField.Required_2 = true; + osmIDField.Type_2 = esriFieldType.esriFieldTypeString; + osmIDField.Length_2 = 20; + fieldsEdit.AddField((IField)osmIDField); + + // add the field for the tag cloud for all other tag/value pairs + IFieldEdit osmXmlTagsField = new FieldClass() as IFieldEdit; + osmXmlTagsField.Name_2 = "osmTags"; + osmXmlTagsField.Required_2 = true; + //if (((IWorkspace)workspace).Type == esriWorkspaceType.esriLocalDatabaseWorkspace) + //{ + osmXmlTagsField.Type_2 = esriFieldType.esriFieldTypeBlob; + //} + //else + //{ + // osmXmlTagsField.Type_2 = esriFieldType.esriFieldTypeXML; + //} + fieldsEdit.AddField((IField)osmXmlTagsField); + + if (additionalTagFields != null) + { + foreach (string nameOfTag in additionalTagFields) + { + IFieldEdit osmTagAttributeField = new FieldClass() as IFieldEdit; + osmTagAttributeField.Name_2 = OSMToolHelper.convert2AttributeFieldName(nameOfTag, illegalCharacters); + osmTagAttributeField.AliasName_2 = nameOfTag + _resourceManager.GetString("GPTools_OSMGPAttributeSelector_aliasaddition"); + osmTagAttributeField.Type_2 = esriFieldType.esriFieldTypeString; + osmTagAttributeField.Length_2 = 100; + osmTagAttributeField.Required_2 = false; + + fieldsEdit.AddField((IField)osmTagAttributeField); + } + } + + fields = (ESRI.ArcGIS.Geodatabase.IFields)fieldsEdit; // Explicit Cast + + System.String strShapeField = ""; + + // locate the shape field + for (int j = 0; j < fields.FieldCount; j++) + { + if (fields.get_Field(j).Type == ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeGeometry) + { + strShapeField = fields.get_Field(j).Name; + + // redefine geometry type + + IFieldEdit shapeField = fields.get_Field(j) as IFieldEdit; + IGeometryDefEdit geometryDef = new GeometryDefClass() as IGeometryDefEdit; + geometryDef.GeometryType_2 = esriGeometryType.esriGeometryPolyline; + geometryDef.HasZ_2 = false; + geometryDef.HasM_2 = false; + //geometryDef.GridCount_2 = 1; + //geometryDef.set_GridSize(0, 0); + + ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory; + ISpatialReference wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference; + + geometryDef.SpatialReference_2 = wgs84; + + shapeField.GeometryDef_2 = (IGeometryDef)geometryDef; + + break; + } + } + + // Use IFieldChecker to create a validated fields collection. + ESRI.ArcGIS.Geodatabase.IFieldChecker fieldChecker = new ESRI.ArcGIS.Geodatabase.FieldCheckerClass(); + ESRI.ArcGIS.Geodatabase.IEnumFieldError enumFieldError = null; + ESRI.ArcGIS.Geodatabase.IFields validatedFields = null; + fieldChecker.ValidateWorkspace = (ESRI.ArcGIS.Geodatabase.IWorkspace)workspace; + fieldChecker.Validate(fields, out enumFieldError, out validatedFields); + + // The enumFieldError enumerator can be inspected at this point to determine + // which fields were modified during validation. + + + // finally create and return the feature class + featureClass = featureWorkspace.CreateFeatureClass(featureClassName, validatedFields, CLSID, null, ESRI.ArcGIS.Geodatabase.esriFeatureType.esriFTSimple, strShapeField, strConfigKeyword); + + // create the openstreetmap spcific metadata + _osmUtility.CreateOSMMetadata((IDataset)featureClass, metadataAbstract, metadataPurpose); + } + catch + { + throw; + } + + return featureClass; + } + #endregion #region"Create OSM Polygon FeatureClass" @@ -1220,8 +1547,10 @@ internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreatePolygonFeatureClass(ESRI.Ar } catch (Exception ex) { +#if DEBUG System.Diagnostics.Debug.WriteLine(ex.Message); System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif } fieldsEdit.AddField((IField)domainField); @@ -1374,8 +1703,8 @@ internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreatePolygonFeatureClass(ESRI.Ar geometryDef.GeometryType_2 = esriGeometryType.esriGeometryPolygon; geometryDef.HasZ_2 = false; geometryDef.HasM_2 = false; - geometryDef.GridCount_2 = 1; - geometryDef.set_GridSize(0, 0); + //geometryDef.GridCount_2 = 1; + //geometryDef.set_GridSize(0, 0); geometryDef.SpatialReference_2 = ((IGeoDataset)featureDataset).SpatialReference; @@ -1432,11 +1761,153 @@ internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreatePolygonFeatureClass(ESRI.Ar return featureClass; } - #endregion - #region Utility Methods - /// - /// Deletes the dataset if possible + ///Simple helper to create a featureclass in a geodatabase. + /// + ///An IWorkspace2 interface + ///A System.String that contains the name of the feature class to open or create. Example: "states" + ///An IFields interface + ///An empty System.String or RDBMS table string for ArcSDE. Example: "myTable" or "" + /// + ///An IFeatureClass interface or a Nothing + /// + /// + /// (1) If a 'featureClassName' already exists in the workspace a reference to that feature class + /// object will be returned. + /// + internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreateSmallPolygonFeatureClass(ESRI.ArcGIS.Geodatabase.IWorkspace2 workspace, System.String featureClassName, System.String strConfigKeyword, string metadataAbstract, string metadataPurpose, List additionalTagFields) + { + if (featureClassName == "") return null; // name was not passed in + + ESRI.ArcGIS.Geodatabase.IFeatureClass featureClass = null; + + try + { + + ESRI.ArcGIS.Geodatabase.IFeatureWorkspace featureWorkspace = (ESRI.ArcGIS.Geodatabase.IFeatureWorkspace)workspace; // Explicit Cast + + if (workspace.get_NameExists(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTFeatureClass, featureClassName)) //feature class with that name already exists + { + // if a feature class with the same name already exists delete it.... + featureClass = featureWorkspace.OpenFeatureClass(featureClassName); + + if (!DeleteDataset((IDataset)featureClass)) + { + return featureClass; + } + } + + + String illegalCharacters = String.Empty; + + ISQLSyntax sqlSyntax = workspace as ISQLSyntax; + if (sqlSyntax != null) + { + illegalCharacters = sqlSyntax.GetInvalidCharacters(); + } + + // assign the class id value if not assigned + UID CLSID = new ESRI.ArcGIS.esriSystem.UIDClass(); + CLSID.Value = "esriGeoDatabase.Feature"; + + ESRI.ArcGIS.Geodatabase.IObjectClassDescription objectClassDescription = new ESRI.ArcGIS.Geodatabase.FeatureClassDescriptionClass(); + + // if a fields collection is not passed in then supply our own + // create the fields using the required fields method + IFields fields = objectClassDescription.RequiredFields; + ESRI.ArcGIS.Geodatabase.IFieldsEdit fieldsEdit = (ESRI.ArcGIS.Geodatabase.IFieldsEdit)fields; // Explicit Cast + + // add the OSM ID field + IFieldEdit osmIDField = new FieldClass() as IFieldEdit; + osmIDField.Name_2 = "OSMID"; + osmIDField.Type_2 = esriFieldType.esriFieldTypeString; + osmIDField.Length_2 = 20; + osmIDField.Required_2 = true; + fieldsEdit.AddField((IField)osmIDField); + + // add the field for the tag cloud for all other tag/value pairs + IFieldEdit osmXmlTagsField = new FieldClass() as IFieldEdit; + osmXmlTagsField.Name_2 = "osmTags"; + osmXmlTagsField.Required_2 = true; + osmXmlTagsField.Type_2 = esriFieldType.esriFieldTypeBlob; + fieldsEdit.AddField((IField)osmXmlTagsField); + + if (additionalTagFields != null) + { + foreach (string nameOfTag in additionalTagFields) + { + IFieldEdit osmTagAttributeField = new FieldClass() as IFieldEdit; + osmTagAttributeField.Name_2 = OSMToolHelper.convert2AttributeFieldName(nameOfTag, illegalCharacters); + osmTagAttributeField.AliasName_2 = nameOfTag + _resourceManager.GetString("GPTools_OSMGPAttributeSelector_aliasaddition"); + osmTagAttributeField.Type_2 = esriFieldType.esriFieldTypeString; + osmTagAttributeField.Length_2 = 120; + osmTagAttributeField.Required_2 = false; + + fieldsEdit.AddField((IField)osmTagAttributeField); + } + } + + fields = (ESRI.ArcGIS.Geodatabase.IFields)fieldsEdit; // Explicit Cast + + System.String strShapeField = ""; + + // locate the shape field + for (int j = 0; j < fields.FieldCount; j++) + { + if (fields.get_Field(j).Type == ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeGeometry) + { + strShapeField = fields.get_Field(j).Name; + + // redefine geometry type + + IFieldEdit shapeField = fields.get_Field(j) as IFieldEdit; + IGeometryDefEdit geometryDef = new GeometryDefClass() as IGeometryDefEdit; + geometryDef.GeometryType_2 = esriGeometryType.esriGeometryPolygon; + geometryDef.HasZ_2 = false; + geometryDef.HasM_2 = false; + //geometryDef.GridCount_2 = 1; + //geometryDef.set_GridSize(0, 0); + + ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory; + ISpatialReference wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference; + + geometryDef.SpatialReference_2 = wgs84; + + shapeField.GeometryDef_2 = (IGeometryDef)geometryDef; + + break; + } + } + + // Use IFieldChecker to create a validated fields collection. + ESRI.ArcGIS.Geodatabase.IFieldChecker fieldChecker = new ESRI.ArcGIS.Geodatabase.FieldCheckerClass(); + ESRI.ArcGIS.Geodatabase.IEnumFieldError enumFieldError = null; + ESRI.ArcGIS.Geodatabase.IFields validatedFields = null; + fieldChecker.ValidateWorkspace = (ESRI.ArcGIS.Geodatabase.IWorkspace)workspace; + fieldChecker.Validate(fields, out enumFieldError, out validatedFields); + + // The enumFieldError enumerator can be inspected at this point to determine + // which fields were modified during validation. + + + // finally create and return the feature class + featureClass = featureWorkspace.CreateFeatureClass(featureClassName, validatedFields, CLSID, null, ESRI.ArcGIS.Geodatabase.esriFeatureType.esriFTSimple, strShapeField, strConfigKeyword); + + // create the openstreetmap specific metadata + _osmUtility.CreateOSMMetadata((IDataset)featureClass, metadataAbstract, metadataPurpose); + } + catch + { + throw; + } + + return featureClass; + } + #endregion + + #region Utility Methods + /// + /// Deletes the dataset if possible /// /// /// - Checks for a shcema lock before deleting (CanDelete returns true even if the dataset is locked) @@ -1444,15 +1915,16 @@ internal ESRI.ArcGIS.Geodatabase.IFeatureClass CreatePolygonFeatureClass(ESRI.Ar /// private static bool DeleteDataset(IDataset ds) { - ISchemaLock schemaLock = ds as ISchemaLock; + bool deleteSuccess = false; + ISchemaLock schemaLock = ds as ISchemaLock; if (ds.CanDelete() && (schemaLock != null)) { try { schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock); ds.Delete(); - return true; + deleteSuccess = true; } catch { @@ -1460,7 +1932,7 @@ private static bool DeleteDataset(IDataset ds) } } - return false; + return deleteSuccess; } #endregion @@ -1538,6 +2010,96 @@ private IVariantArray CreateAddGridIndexParameterArray(string featureClassName, return featureClassArray; } + //internal void BuildSpatialIndex(IGPValue gpFeatureClass, Geoprocessor.Geoprocessor geoProcessor, IGPUtilities gpUtil, ITrackCancel trackCancel, IGPMessages message) + //{ + // if ((gpFeatureClass == null) || (geoProcessor == null) || (gpUtil == null)) + // return; + + // // Check if the feature class supports spatial index grids + // IFeatureClass fc = gpUtil.OpenDataset(gpFeatureClass) as IFeatureClass; + // if (fc == null) + // return; + + // int idxShapeField = fc.FindField(fc.ShapeFieldName); + // if (idxShapeField >= 0) + // { + // IField shapeField = fc.Fields.get_Field(idxShapeField); + // if (shapeField.GeometryDef.GridCount > 0) + // { + // if (shapeField.GeometryDef.get_GridSize(0) == -2.0) + // return; + // } + // } + + // // Create the new spatial index grid + // bool storedOriginal = geoProcessor.AddOutputsToMap; + + // try + // { + // geoProcessor.AddOutputsToMap = false; + + // DataManagementTools.CalculateDefaultGridIndex calculateDefaultGridIndex = + // new DataManagementTools.CalculateDefaultGridIndex(gpFeatureClass); + // IGeoProcessorResult2 gpResults2 = + // geoProcessor.Execute(calculateDefaultGridIndex, trackCancel) as IGeoProcessorResult2; + // message.AddMessages(gpResults2.GetResultMessages()); + + // if (gpResults2 != null) + // { + // DataManagementTools.RemoveSpatialIndex removeSpatialIndex = + // new DataManagementTools.RemoveSpatialIndex(gpFeatureClass.GetAsText()); + // removeSpatialIndex.out_feature_class = gpFeatureClass.GetAsText(); + // gpResults2 = geoProcessor.Execute(removeSpatialIndex, trackCancel) as IGeoProcessorResult2; + // message.AddMessages(gpResults2.GetResultMessages()); + + // DataManagementTools.AddSpatialIndex addSpatialIndex = + // new DataManagementTools.AddSpatialIndex(gpFeatureClass.GetAsText()); + // addSpatialIndex.out_feature_class = gpFeatureClass.GetAsText(); + + // addSpatialIndex.spatial_grid_1 = calculateDefaultGridIndex.grid_index1; + // addSpatialIndex.spatial_grid_2 = calculateDefaultGridIndex.grid_index2; + // addSpatialIndex.spatial_grid_3 = calculateDefaultGridIndex.grid_index3; + + // gpResults2 = geoProcessor.Execute(addSpatialIndex, trackCancel) as IGeoProcessorResult2; + // message.AddMessages(gpResults2.GetResultMessages()); + // } + // } + // catch (Exception ex) + // { + // message.AddWarning(ex.Message); + // } + // finally + // { + // geoProcessor.AddOutputsToMap = storedOriginal; + // } + //} + + /// + /// Generate equal paritions for each capacity + /// + /// capacity number + /// number of partitions + /// an array of length count and the sum all values is the capacity + private long[] PartitionValue(long value, int count) + { + if (count <= 0) throw new ArgumentException("The count must be greater than zero.", "count"); + + var result = new long[count]; + + long runningTotal = 0; + for (int i = 0; i < count; i++) + { + var remainder = value - runningTotal; + var share = remainder > 0 ? remainder / (count - i) : 0; + result[i] = share; + runningTotal += share; + } + + if (runningTotal < value) result[count - 1] += value - runningTotal; + + return result; + } + internal IVariantArray CreateAddIndexParameterArray(string featureClassName, string fieldsToIndex, string IndexName, string unique, string sortingOrder) { IVariantArray parameterArrary = new VarArrayClass(); @@ -1561,1633 +2123,4053 @@ internal IVariantArray CreateAddIndexParameterArray(string featureClassName, str return parameterArrary; } - internal void loadOSMNodes(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message,IGPValue targetGPValue, IFeatureClass osmPointFeatureClass, bool conserveMemory, bool fastLoad, int nodeCapacity, ref Dictionary osmNodeDictionary, IFeatureWorkspace featureWorkspace, ISpatialReference downloadSpatialReference, OSMDomains availableDomains, bool checkForExisting) + internal void splitOSMFile(string osmFileLocation, string tempFolder, long nodeCapacity, long wayCapacity, long relationCapacity, int numberOfThreads, out List nodeFileNames, out List nodeGDBNames, out List wayFileNames, out List wayGDBNames, out List relationFileNames, out List relationGDBNames) { - XmlReader osmFileXmlReader = null; - XmlSerializer nodeSerializer = null; + long[] node_partitions = PartitionValue(nodeCapacity, numberOfThreads); + long[] way_partitions = PartitionValue(wayCapacity, numberOfThreads); + long[] relation_partitions = PartitionValue(relationCapacity, numberOfThreads); - try + int node_index = 0; + int way_index = 0; + int relation_index = 0; + + nodeFileNames = new List(numberOfThreads); + wayFileNames = new List(numberOfThreads); + relationFileNames = new List(numberOfThreads); + + nodeGDBNames = new List(numberOfThreads); + wayGDBNames = new List(numberOfThreads); + relationGDBNames = new List(numberOfThreads); + + String newName = String.Empty; + String nodeFile = String.Empty; + String gdbName = String.Empty; + + FileInfo osmFileInfo = new FileInfo(osmFileLocation); + + for (int i = 0; i < numberOfThreads; i++) { - osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation); - nodeSerializer = new XmlSerializer(typeof(node)); + // for the nodes + newName = osmFileInfo.Name.Substring(0, osmFileInfo.Name.Length - osmFileInfo.Extension.Length) + "_n" + i.ToString() + osmFileInfo.Extension; + nodeFileNames.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { tempFolder, newName })); + gdbName = osmFileInfo.Name.Substring(0, osmFileInfo.Name.Length - osmFileInfo.Extension.Length) + "_n" + i.ToString() + ".gdb"; + nodeGDBNames.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { tempFolder, gdbName })); + + // for the ways + newName = osmFileInfo.Name.Substring(0, osmFileInfo.Name.Length - osmFileInfo.Extension.Length) + "_w" + i.ToString() + osmFileInfo.Extension; + wayFileNames.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { tempFolder, newName })); + gdbName = osmFileInfo.Name.Substring(0, osmFileInfo.Name.Length - osmFileInfo.Extension.Length) + "_w" + i.ToString() + ".gdb"; + wayGDBNames.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { tempFolder, gdbName })); + + // for the relations + newName = osmFileInfo.Name.Substring(0, osmFileInfo.Name.Length - osmFileInfo.Extension.Length) + "_r" + i.ToString() + osmFileInfo.Extension; + relationFileNames.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { tempFolder, newName })); + gdbName = osmFileInfo.Name.Substring(0, osmFileInfo.Name.Length - osmFileInfo.Extension.Length) + "_r" + i.ToString() + ".gdb"; + relationGDBNames.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { tempFolder, gdbName })); + } - ISpatialReferenceFactory spatialRef = new SpatialReferenceEnvironmentClass(); - ISpatialReference wgs84 = spatialRef.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984); + // in this case we are working with one thread and this can be handled with the target gdb directly + if (nodeFileNames.Count == 0) + return; - bool shouldProject = !((IClone)wgs84).IsEqual((IClone)downloadSpatialReference); + XmlWriter node_writer = XmlWriter.Create(nodeFileNames[node_index]); + node_writer.WriteStartDocument(); + node_writer.WriteStartElement("osm"); + XmlWriter way_writer = XmlWriter.Create(wayFileNames[way_index]); + way_writer.WriteStartDocument(); + way_writer.WriteStartElement("osm"); + XmlWriter relation_writer = XmlWriter.Create(relationFileNames[relation_index]); + relation_writer.WriteStartDocument(); + relation_writer.WriteStartElement("osm"); - int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID"); - Dictionary osmPointDomainAttributeFieldIndices = new Dictionary(); - Dictionary osmPointDomainAttributeFieldLength = new Dictionary(); + long nodeCounter = 0; + long wayCounter = 0; + long relationCounter = 0; - foreach (var domains in availableDomains.domain) + + XmlReader reader = XmlReader.Create(osmFileLocation); + reader.MoveToContent(); + + while(reader.Read()) + { + if (reader.IsStartElement()) { - int currentFieldIndex = osmPointFeatureClass.FindField(domains.name); + if (reader.Name == "node") + { + if (nodeCounter < node_partitions[node_index]) + { + node_writer.WriteNode(reader, true); + nodeCounter++; + } + else + { + node_writer.WriteEndElement(); + node_writer.Close(); - if (currentFieldIndex != -1) + node_index++; + + nodeCounter = 0; + + node_writer = XmlWriter.Create(nodeFileNames[node_index], new XmlWriterSettings()); + node_writer.WriteStartDocument(); + node_writer.WriteStartElement("osm"); + node_writer.WriteNode(reader, true); + } + } + else if (reader.Name == "way") { - osmPointDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex); - osmPointDomainAttributeFieldLength.Add(domains.name, osmPointFeatureClass.Fields.get_Field(currentFieldIndex).Length); + if (wayCounter < way_partitions[way_index]) + { + way_writer.WriteNode(reader, true); + wayCounter++; + } + else + { + way_writer.WriteEndElement(); + way_writer.Close(); + way_index++; + wayCounter = 0; + + way_writer = XmlWriter.Create(wayFileNames[way_index], new XmlWriterSettings()); + way_writer.WriteStartDocument(); + way_writer.WriteStartElement("osm"); + way_writer.WriteNode(reader, true); + } + } + else if (reader.Name == "relation") + { + if (relationCounter < relation_partitions[relation_index]) + { + relation_writer.WriteNode(reader, true); + relationCounter++; + } + else + { + relation_writer.WriteEndElement(); + relation_writer.Close(); + relation_index++; + relationCounter = 0; + + relation_writer = XmlWriter.Create(relationFileNames[relation_index], new XmlWriterSettings()); + relation_writer.WriteStartDocument(); + relation_writer.WriteStartElement("osm"); + relation_writer.WriteNode(reader, true); + } } } + } - int tagCollectionPointFieldIndex = osmPointFeatureClass.FindField("osmTags"); - int osmUserPointFieldIndex = osmPointFeatureClass.FindField("osmuser"); - int osmUIDPointFieldIndex = osmPointFeatureClass.FindField("osmuid"); - int osmVisiblePointFieldIndex = osmPointFeatureClass.FindField("osmvisible"); - int osmVersionPointFieldIndex = osmPointFeatureClass.FindField("osmversion"); - int osmChangesetPointFieldIndex = osmPointFeatureClass.FindField("osmchangeset"); - int osmTimeStampPointFieldIndex = osmPointFeatureClass.FindField("osmtimestamp"); - int osmMemberOfPointFieldIndex = osmPointFeatureClass.FindField("osmMemberOf"); - int osmSupportingElementPointFieldIndex = osmPointFeatureClass.FindField("osmSupportingElement"); - int osmWayRefCountFieldIndex = osmPointFeatureClass.FindField("wayRefCount"); + reader.Close(); + if (node_writer != null) + node_writer.Close(); + if (way_writer != null) + way_writer.Close(); + if (relation_writer != null) + relation_writer.Close(); + } - // set up the progress indicator - IStepProgressor stepProgressor = TrackCancel as IStepProgressor; + public static IEnumerable ParseXml(string xml) + { + var settings = new XmlReaderSettings + { + ConformanceLevel = ConformanceLevel.Fragment, + IgnoreWhitespace = true + }; - if (stepProgressor != null) + using (var stringReader = new StringReader(xml)) + using (var xmlReader = XmlReader.Create(stringReader, settings)) + { + xmlReader.MoveToContent(); + while (xmlReader.ReadState != ReadState.EndOfFile) { - stepProgressor.MinRange = 0; - stepProgressor.MaxRange = nodeCapacity; - stepProgressor.StepValue = (1); - stepProgressor.Message = _resourceManager.GetString("GPTools_OSMGPFileReader_loadingNodes"); - stepProgressor.Position = 0; - stepProgressor.Show(); + yield return XNode.ReadFrom(xmlReader); } + } + } - // flag to determine if a computation of indices is required - bool indexBuildRequired = false; - if (nodeCapacity > 0) - indexBuildRequired = true; - - int pointCount = 0; + internal void smallLoadOSMWay(string osmFileLocation, string sourcePointsFeatureClassName, string fileGDBLocation, string lineFeatureClassName, string polygonFeatureClassName, List lineFieldNames, List polygonFieldNames) + { + using (ComReleaser comReleaser = new ComReleaser()) + { + List tags = null; + IGPUtilities3 gpUtilities = new GPUtilitiesClass() as IGPUtilities3; + comReleaser.ManageLifetime(gpUtilities); - // let's insert all the points first - if (osmPointFeatureClass != null) + try { - IPoint pointGeometry = null; - IFeatureBuffer pointFeature = null; - IFeatureClassLoad pointFeatureLoad = null; + IWorkspaceFactory2 workspaceFactory = guessWorkspaceFactory(fileGDBLocation) as IWorkspaceFactory2; + comReleaser.ManageLifetime(workspaceFactory); + IFeatureWorkspace tempWorkspace = workspaceFactory.OpenFromFile(fileGDBLocation, 0) as IFeatureWorkspace; + comReleaser.ManageLifetime(tempWorkspace); - using (ComReleaser comReleaser = new ComReleaser()) + IFeatureClass lineFeatureClass = tempWorkspace.OpenFeatureClass(lineFeatureClassName); + comReleaser.ManageLifetime(lineFeatureClass); + + IFeatureClass polygonFeatureClass = tempWorkspace.OpenFeatureClass(polygonFeatureClassName); + comReleaser.ManageLifetime(polygonFeatureClass); + + IFeatureWorkspace sourceWorkspace = null; + string sourceFCNameString = String.Empty; + + string[] sourcePointFCElements = sourcePointsFeatureClassName.Split(new char[] { System.IO.Path.DirectorySeparatorChar }); + sourceFCNameString = sourcePointFCElements[sourcePointFCElements.Length - 1]; + + if (sourcePointsFeatureClassName.Contains(fileGDBLocation)) { - using (SchemaLockManager schemaLockManager = new SchemaLockManager(osmPointFeatureClass as ITable)) - { + // re-use the existing workspace connection + sourceWorkspace = tempWorkspace; + } + else + { + IWorkspaceFactory sourceWorkspaceFactory = guessWorkspaceFactory(sourcePointsFeatureClassName); + comReleaser.ManageLifetime(sourceWorkspaceFactory); - if (((IWorkspace)featureWorkspace).WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace) - { - pointFeatureLoad = osmPointFeatureClass as IFeatureClassLoad; - } + sourceWorkspace = sourceWorkspaceFactory.OpenFromFile(sourcePointsFeatureClassName.Substring(0, sourcePointsFeatureClassName.Length - sourceFCNameString.Length - 1), 0) as IFeatureWorkspace; + comReleaser.ManageLifetime(sourceWorkspace); + } - IFeatureCursor pointInsertCursor = osmPointFeatureClass.Insert(true); - comReleaser.ManageLifetime(pointInsertCursor); + IFeatureClass sourcePointsFeatureClass = sourceWorkspace.OpenFeatureClass(sourceFCNameString); + comReleaser.ManageLifetime(sourcePointsFeatureClass); - if (pointFeatureLoad != null) - { - pointFeatureLoad.LoadOnlyMode = true; - } + int osmPointIDFieldIndex = sourcePointsFeatureClass.FindField("OSMID"); + string sqlPointOSMID = sourcePointsFeatureClass.SqlIdentifier("OSMID"); - osmFileXmlReader.MoveToContent(); + XmlReader wayFileXmlReader = XmlReader.Create(osmFileLocation); + wayFileXmlReader.ReadToFollowing("way"); - while (osmFileXmlReader.Read()) - { - if (osmFileXmlReader.IsStartElement()) - { - if (osmFileXmlReader.Name == "node") - { - string currentNodeString = osmFileXmlReader.ReadOuterXml(); - // turn the xml node representation into a node class representation - ESRI.ArcGIS.OSM.OSMClassExtension.node currentNode = null; - using (StringReader nodeReader = new System.IO.StringReader(currentNodeString)) - { - currentNode = nodeSerializer.Deserialize(nodeReader) as ESRI.ArcGIS.OSM.OSMClassExtension.node; - } - - // check if a feature with the same OSMID already exists, because the can only be one - if (checkForExisting == true) - { - if (CheckIfExists(osmPointFeatureClass as ITable, currentNode.id)) - { - continue; - } - } - - try - { - pointFeature = osmPointFeatureClass.CreateFeatureBuffer(); - - pointGeometry = new PointClass(); - pointGeometry.X = Convert.ToDouble(currentNode.lon, new CultureInfo("en-US")); - pointGeometry.Y = Convert.ToDouble(currentNode.lat, new CultureInfo("en-US")); - pointGeometry.SpatialReference = wgs84; + int osmLineIDFieldIndex = lineFeatureClass.FindField("OSMID"); - if (shouldProject) - { - pointGeometry.Project(downloadSpatialReference); - } + Dictionary mainLineAttributeFieldIndices = new Dictionary(); + foreach (string fieldName in lineFieldNames) + { + int currentFieldIndex = lineFeatureClass.FindField(OSMToolHelper.convert2AttributeFieldName(fieldName, null)); - pointFeature.Shape = pointGeometry; + if (currentFieldIndex != -1) + { + mainLineAttributeFieldIndices.Add(OSMToolHelper.convert2AttributeFieldName(fieldName, null), currentFieldIndex); + } + } - pointFeature.set_Value(osmPointIDFieldIndex, currentNode.id); + int tagCollectionLineFieldIndex = lineFeatureClass.FindField("osmTags"); - string isSupportingNode = ""; - if (_osmUtility.DoesHaveKeys(currentNode.tag)) - { - // if case it has tags I assume that the node presents an entity of it own, - // hence it is not a supporting node in the context of supporting a way or relation - isSupportingNode = "no"; + int osmPolygonIDFieldIndex = polygonFeatureClass.FindField("OSMID"); - if (conserveMemory == false) - { - osmNodeDictionary[currentNode.id] = new simplePointRef(Convert.ToSingle(currentNode.lon, new CultureInfo("en-US")), Convert.ToSingle(currentNode.lat, new CultureInfo("en-US")), 0, 0); - } - } - else - { - // node has no tags -- at this point I assume that the absence of tags indicates that it is a supporting node - // for a way or a relation - isSupportingNode = "yes"; + Dictionary mainPolygonAttributeFieldIndices = new Dictionary(); + foreach (string fieldName in polygonFieldNames) + { + int currentFieldIndex = lineFeatureClass.FindField(OSMToolHelper.convert2AttributeFieldName(fieldName, null)); - if (conserveMemory == false) - { - osmNodeDictionary[currentNode.id] = new simplePointRef(Convert.ToSingle(currentNode.lon, new CultureInfo("en-US")), Convert.ToSingle(currentNode.lat, new CultureInfo("en-US")), 0, 0); - } - } + if (currentFieldIndex != -1) + { + mainPolygonAttributeFieldIndices.Add(OSMToolHelper.convert2AttributeFieldName(fieldName, null), currentFieldIndex); + } + } - insertTags(osmPointDomainAttributeFieldIndices, osmPointDomainAttributeFieldLength, tagCollectionPointFieldIndex, pointFeature, currentNode.tag); + int tagCollectionPolygonFieldIndex = polygonFeatureClass.FindField("osmTags"); - if (fastLoad == false) - { - if (osmSupportingElementPointFieldIndex > -1) - { - pointFeature.set_Value(osmSupportingElementPointFieldIndex, isSupportingNode); - } + IFeatureBuffer lineFeature = lineFeatureClass.CreateFeatureBuffer(); + comReleaser.ManageLifetime(lineFeature); - if (osmWayRefCountFieldIndex > -1) - { - pointFeature.set_Value(osmWayRefCountFieldIndex, 0); - } + IFeatureBuffer polygonFeature = polygonFeatureClass.CreateFeatureBuffer(); + comReleaser.ManageLifetime(polygonFeature); - // store the administrative attributes - // user, uid, version, changeset, timestamp, visible - if (osmUserPointFieldIndex > -1) - { - if (!String.IsNullOrEmpty(currentNode.user)) - { - pointFeature.set_Value(osmUserPointFieldIndex, currentNode.user); - } - } - if (osmUIDPointFieldIndex > -1) - { - if (!String.IsNullOrEmpty(currentNode.uid)) - { - pointFeature.set_Value(osmUIDPointFieldIndex, Convert.ToInt32(currentNode.uid)); - } - } + IFeatureCursor lineInsertCursor = lineFeatureClass.Insert(true); + comReleaser.ManageLifetime(lineInsertCursor); - if (osmVisiblePointFieldIndex > -1) - { - pointFeature.set_Value(osmVisiblePointFieldIndex, currentNode.visible.ToString()); - } + IFeatureCursor polygonInsertCursor = polygonFeatureClass.Insert(true); + comReleaser.ManageLifetime(polygonInsertCursor); - if (osmVersionPointFieldIndex > -1) - { - if (!String.IsNullOrEmpty(currentNode.version)) - { - pointFeature.set_Value(osmVersionPointFieldIndex, Convert.ToInt32(currentNode.version)); - } - } + ISpatialReferenceFactory spatialRef = new SpatialReferenceEnvironmentClass(); + ISpatialReference wgs84 = spatialRef.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984); - if (osmChangesetPointFieldIndex > -1) - { - if (!String.IsNullOrEmpty(currentNode.changeset)) - { - pointFeature.set_Value(osmChangesetPointFieldIndex, Convert.ToInt32(currentNode.changeset)); - } - } + CultureInfo en_us = new CultureInfo("en-US"); - if (osmTimeStampPointFieldIndex > -1) - { - if (!String.IsNullOrEmpty(currentNode.timestamp)) - { - try - { - pointFeature.set_Value(osmTimeStampPointFieldIndex, Convert.ToDateTime(currentNode.timestamp)); - } - catch (Exception ex) - { - message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_invalidTimeFormat"), ex.Message)); - } - } - } - } - try - { - pointInsertCursor.InsertFeature(pointFeature); - pointCount = pointCount + 1; + OSMUtility osmUtility = new OSMUtility(); + long lineWayCount = 0; + long polygonWayCount = 0; - if (stepProgressor != null) - { - stepProgressor.Position = pointCount; - } - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(ex.Message); - message.AddWarning(ex.Message); - } + // ------------------------------- + IQueryFilter osmIDQueryFilter = new QueryFilterClass(); + // the point query filter for updates will not changes, so let's do that ahead of time + try + { + osmIDQueryFilter.SubFields = sourcePointsFeatureClass.ShapeFieldName + "," + sourcePointsFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name; + } + catch + { } + // do a 'small' query to establish an instance for a cursor and manage the cursor throughout the loading process + osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN ('n1')"; + IFeatureCursor searchPointCursor = sourcePointsFeatureClass.Search(osmIDQueryFilter, false); + comReleaser.ManageLifetime(searchPointCursor); - if (TrackCancel.Continue() == false) - { - return; - } + do + { + string wayOSMID = "w" + wayFileXmlReader.GetAttribute("id"); - if ((pointCount % 50000) == 0) - { - message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_pointsloaded"), pointCount)); - pointInsertCursor.Flush(); - System.GC.Collect(); - } - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(ex.Message); - message.AddWarning(ex.Message); - } - finally - { - if (pointFeature != null) - { - Marshal.FinalReleaseComObject(pointFeature); - pointFeature = null; - } + string ndsAndTags = wayFileXmlReader.ReadInnerXml(); - if (pointGeometry != null) - { - Marshal.FinalReleaseComObject(pointGeometry); - pointGeometry = null; - } - } + bool wayIsLine = true; + bool wayIsComplete = true; - currentNode = null; - } - } - } + tags = new List(); + List nodes = new List(); - if (stepProgressor != null) + foreach (XElement item in ParseXml(ndsAndTags)) + { + if (item.Name == "nd") { - stepProgressor.Hide(); + nodes.Add("n" + item.Attribute("ref").Value); } - - pointInsertCursor.Flush(); - osmFileXmlReader.Close(); - - message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_pointsloaded"), pointCount)); - message.AddMessage(_resourceManager.GetString("GPTools_buildingpointidx")); - - if (pointFeatureLoad != null) + else if (item.Name == "tag") { - pointFeatureLoad.LoadOnlyMode = false; + tags.Add(new tag() { k = item.Attribute("k").Value, v = item.Attribute("v").Value }); } } - } - - if (TrackCancel.Continue() == false) - { - return; - } - using (ComReleaser comReleaser = new ComReleaser()) - { - IFeatureCursor updatePoints = osmPointFeatureClass.Update(null, false); - comReleaser.ManageLifetime(updatePoints); + IPointCollection wayPointCollection = null; + wayIsLine = IsThisWayALine(tags, nodes); - IFeature feature2Update = updatePoints.NextFeature(); + List idRequests = SplitOSMIDRequests(nodes); + osmIDQueryFilter.SubFields = sourcePointsFeatureClass.ShapeFieldName + "," + sourcePointsFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name; - while (feature2Update != null) + if (wayIsLine) { - pointGeometry = feature2Update.Shape as IPoint; - pointGeometry.ID = feature2Update.OID; - feature2Update.Shape = pointGeometry; - if (conserveMemory == false) - { - string osmid = Convert.ToString(feature2Update.get_Value(osmPointIDFieldIndex)); - if (osmNodeDictionary.ContainsKey(osmid)) - osmNodeDictionary[osmid].pointObjectID = feature2Update.OID; - } + IPolyline wayPolyline = new PolylineClass(); + wayPolyline.SpatialReference = wgs84; - updatePoints.UpdateFeature(feature2Update); + wayPointCollection = wayPolyline as IPointCollection; - if (TrackCancel.Continue() == false) + // build a list of node ids we can use to determine the point index in the line geometry + // as well as a dictionary to determine the position in the list in case of duplicates nodes + Dictionary> nodePositionDictionary = new Dictionary>(nodes.Count); + + for (int index = 0; index < nodes.Count; index++) { - return; + if (nodePositionDictionary.ContainsKey(nodes[index])) + nodePositionDictionary[nodes[index]].Add(index); + else + nodePositionDictionary.Add(nodes[index], new List() { index }); + + wayPointCollection.AddPoint(new PointClass()); } - if (feature2Update != null) - Marshal.ReleaseComObject(feature2Update); + foreach (string request in idRequests) + { + string idCompareString = request; + osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + request; - if (pointGeometry != null) - Marshal.ReleaseComObject(pointGeometry); + searchPointCursor = sourcePointsFeatureClass.Search(osmIDQueryFilter, false); - feature2Update = updatePoints.NextFeature(); - } - } + IFeature nodeFeature = searchPointCursor.NextFeature(); - if (indexBuildRequired) - { + while (nodeFeature != null) + { + // determine the index of the point in with respect to the node position + string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex)); - IGeoProcessor2 geoProcessor = new GeoProcessorClass(); - bool storedOriginal = geoProcessor.AddOutputsToMap; + // remove the ID from the request string + // this has the problem of potentially removing the start and the end point + // there will be an additional test to see if the last point is empty + idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty); - try - { - IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + wayPointCollection.UpdatePoint(nodePositionDictionary[nodeOSMIDString][0], (IPoint)nodeFeature.ShapeCopy); - IGPValue pointFeatureClass = gpUtilities3.MakeGPValueFromObject(osmPointFeatureClass); + foreach (var index in nodePositionDictionary[nodeOSMIDString]) + { + wayPointCollection.UpdatePoint(index, (IPoint)nodeFeature.ShapeCopy); + } - string fcLocation = GetLocationString(targetGPValue, osmPointFeatureClass); + nodeFeature = searchPointCursor.NextFeature(); + } - IIndexes featureClassIndexes = osmPointFeatureClass.Indexes; - int indexPosition = -1; - featureClassIndexes.FindIndex("osmID_IDX", out indexPosition); + idCompareString = CleanReportedIDs(idCompareString); - if (indexPosition == -1) - { + // after removing the commas we should be left with only paranthesis left, meaning a string of length 2 + // if we have more then we have found a missing node, resulting in an incomplete way geometry + if (idCompareString.Length > 2) { - geoProcessor.AddOutputsToMap = false; - - IVariantArray parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", ""); - IGeoProcessorResult2 gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2; + wayIsComplete = false; + break; } } - if (pointCount > 500) + + if (wayIsComplete) { - if (pointFeatureLoad == null) + try { - UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation); + lineFeature.Shape = wayPolyline; + } + catch (Exception exs) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(wayOSMID); + System.Diagnostics.Debug.WriteLine(exs.Message); +#endif } } } - catch (COMException comEx) - { - message.AddWarning(comEx.Message); - } - catch (Exception ex) - { - message.AddWarning(ex.Message); - } - finally + else { - geoProcessor.AddOutputsToMap = storedOriginal; - } - } - } - } - catch (Exception ex) - { - message.AddError(120100, String.Format(_resourceManager.GetString("GPTools_Utility_NodeLoadError"), ex.Message)); - } - finally - { - if (osmFileXmlReader != null) - osmFileXmlReader = null; + IPolygon wayPolygon = new PolygonClass(); + wayPolygon.SpatialReference = wgs84; - if (nodeSerializer != null) - nodeSerializer = null; + wayPointCollection = wayPolygon as IPointCollection; + + Dictionary> nodePositionDictionary = new Dictionary>(nodes.Count); + + // build a list of node ids we can use to determine the point index in the line geometry + // -- it is assumed that there are no duplicate nodes in the area + for (int index = 0; index < nodes.Count; index++) + { + if (nodePositionDictionary.ContainsKey(nodes[index])) + nodePositionDictionary[nodes[index]].Add(index); + else + nodePositionDictionary.Add(nodes[index], new List() { index }); + wayPointCollection.AddPoint(new PointClass()); + } + + foreach (string osmIDRequest in idRequests) + { + string idCompareString = osmIDRequest; + + osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + osmIDRequest; + searchPointCursor = sourcePointsFeatureClass.Search(osmIDQueryFilter, false); + + IFeature nodeFeature = searchPointCursor.NextFeature(); + + while (nodeFeature != null) + { + // determine the index of the point in with respect to the node position + string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex)); + + idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty); + + foreach (var index in nodePositionDictionary[nodeOSMIDString]) + { + wayPointCollection.UpdatePoint(index, (IPoint)nodeFeature.ShapeCopy); + } + + nodeFeature = searchPointCursor.NextFeature(); + } + + idCompareString = CleanReportedIDs(idCompareString); + + if (idCompareString.Length > 2) + { + wayIsComplete = false; + break; + } + } + + if (wayIsComplete) + { + ((ITopologicalOperator2)wayPointCollection).IsKnownSimple_2 = false; + ((IPolygon4)wayPointCollection).SimplifyEx(true, true, false); + + try + { + polygonFeature.Shape = (IPolygon)wayPointCollection; + } + catch (Exception exs) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(wayOSMID); + System.Diagnostics.Debug.WriteLine(exs.Message); +#endif + } + } + } + + + if (wayIsLine) + { + insertTags(mainLineAttributeFieldIndices,tagCollectionLineFieldIndex, lineFeature, tags.ToArray()); + lineFeature.set_Value(osmLineIDFieldIndex, wayOSMID); + } + else + { + insertTags(mainPolygonAttributeFieldIndices, tagCollectionPolygonFieldIndex, polygonFeature, tags.ToArray()); + polygonFeature.set_Value(osmPolygonIDFieldIndex, wayOSMID); + } + + try + { + if (wayIsLine) + { + lineInsertCursor.InsertFeature(lineFeature); + lineWayCount++; + } + else + { + polygonInsertCursor.InsertFeature(polygonFeature); + polygonWayCount++; + } + + + if ((lineWayCount % 50000) == 0) + { + lineInsertCursor.Flush(); + } + + if ((polygonWayCount % 50000) == 0) + { + polygonInsertCursor.Flush(); + } + + } + catch (Exception ex) + { +#if DEBUG + foreach (var item in tags) + { + System.Diagnostics.Debug.WriteLine(string.Format("{0},{1}", item.k, item.v)); + } + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + + // if we encounter a whitespace, attempt to find the next way if it exists + if (wayFileXmlReader.NodeType != XmlNodeType.Element) + wayFileXmlReader.ReadToFollowing("way"); + + } while (wayFileXmlReader.Name == "way"); + + wayFileXmlReader.Close(); + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(osmFileLocation); + System.Diagnostics.Debug.WriteLine(sourcePointsFeatureClassName); + System.Diagnostics.Debug.WriteLine(fileGDBLocation); + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); + System.Diagnostics.Debug.WriteLine(ex.Source); +#endif + } + finally + { + + } } } - private void insertTags(Dictionary domainAttributeFieldIndices, Dictionary domainAttributeFieldLength, int tagCollectionFieldIndex, IRowBuffer row, tag[] tagsToInsert) + internal void smallLoadOSMNode(string osmFileLocation, string fileGDBLocation, string featureClassName, List tagsToLoad, bool useFeatureBuffer) { - Dictionary tagGdbStorageValues = new Dictionary(domainAttributeFieldIndices.Count); - foreach (var item in domainAttributeFieldIndices) + using (ComReleaser comReleaser = new ComReleaser()) { - tagGdbStorageValues[item.Key] = null; - } + List tags = null; - if (tagsToInsert != null) - { - foreach (tag tagItem in tagsToInsert) + try { - if (domainAttributeFieldIndices.ContainsKey(tagItem.k)) + IWorkspaceFactory2 workspaceFactory = new FileGDBWorkspaceFactoryClass(); + comReleaser.ManageLifetime(workspaceFactory); + IFeatureWorkspace nodeWorkspace = workspaceFactory.OpenFromFile(fileGDBLocation, 0) as IFeatureWorkspace; + comReleaser.ManageLifetime(nodeWorkspace); + + IFeatureClass nodeFeatureClass = nodeWorkspace.OpenFeatureClass(featureClassName); + comReleaser.ManageLifetime(nodeFeatureClass); + + XmlReader nodeFileXmlReader = XmlReader.Create(osmFileLocation); + nodeFileXmlReader.ReadToFollowing("node"); + + int osmPointIDFieldIndex = nodeFeatureClass.FindField("OSMID"); + + Dictionary mainPointAttributeFieldIndices = new Dictionary(); + foreach (string fieldName in tagsToLoad) { - if (tagItem.v.Length <= domainAttributeFieldLength[tagItem.k]) + int currentFieldIndex = nodeFeatureClass.FindField(OSMToolHelper.convert2AttributeFieldName(fieldName, null)); + + if (currentFieldIndex != -1) { - tagGdbStorageValues[tagItem.k] = tagItem.v; + mainPointAttributeFieldIndices.Add(OSMToolHelper.convert2AttributeFieldName(fieldName, null), currentFieldIndex); } } - } - } - foreach (var item in domainAttributeFieldIndices) - { - row.set_Value(item.Value, tagGdbStorageValues[item.Key]); - } + int tagCollectionPointFieldIndex = nodeFeatureClass.FindField("osmTags"); + int osmSupportingElementPointFieldIndex = nodeFeatureClass.FindField("osmSupportingElement"); + IFeatureBuffer pointFeature = nodeFeatureClass.CreateFeatureBuffer(); + comReleaser.ManageLifetime(pointFeature); - if (tagCollectionFieldIndex > -1) - { - _osmUtility.insertOSMTags(tagCollectionFieldIndex, row, tagsToInsert); - } + IFeatureCursor pointInsertCursor = nodeFeatureClass.Insert(true); + comReleaser.ManageLifetime(pointInsertCursor); + CultureInfo en_us = new CultureInfo("en-US"); - tagGdbStorageValues.Clear(); - tagGdbStorageValues = null; - } + IPoint pointGeometry = null; + OSMUtility osmUtility = new OSMUtility(); + long counter = 0; - private string GetLocationString(IGPValue gpValue, ITable table) - { - string locationString = String.Empty; + ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass() as ISpatialReferenceFactory; + ISpatialReference wgs84 = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984) as ISpatialReference; - { - if (((IDataset)table).Workspace.PathName.ToUpper().Contains(".GDS\\")) - { - string partialString = gpValue.GetAsText().Substring(0, gpValue.GetAsText().ToUpper().IndexOf(".GDS\\") + 4); + do + { + string osmID = "n" + nodeFileXmlReader.GetAttribute("id"); + double latitude = Convert.ToDouble(nodeFileXmlReader.GetAttribute("lat"), en_us); + double longitude = Convert.ToDouble(nodeFileXmlReader.GetAttribute("lon"), en_us); - string secondString = gpValue.GetAsText().Substring(0, gpValue.GetAsText().LastIndexOf("\\")); + string xmlTags = nodeFileXmlReader.ReadInnerXml(); - locationString = secondString + System.IO.Path.DirectorySeparatorChar + ((IDataset)table).BrowseName; + tags = new List(); + + if (xmlTags.Length > 0) + { + foreach (XElement item in ParseXml(xmlTags)) + { + tags.Add(new tag() { k = item.Attribute("k").Value, v = item.Attribute("v").Value }); + } + } + + pointGeometry = new PointClass(); + pointGeometry.X = longitude; + pointGeometry.Y = latitude; + pointGeometry.SpatialReference = wgs84; + + pointFeature.Shape = pointGeometry; + pointFeature.set_Value(osmPointIDFieldIndex, osmID); + + if (tags.Count > 0) + { + // if the feature buffer is used only update/enter attributes if there are tags + if (useFeatureBuffer) + insertTags(mainPointAttributeFieldIndices, tagCollectionPointFieldIndex, pointFeature, tags.ToArray()); + + pointFeature.set_Value(osmSupportingElementPointFieldIndex, "no"); + } + else + pointFeature.set_Value(osmSupportingElementPointFieldIndex, "yes"); + + try + { + if (useFeatureBuffer == false) + insertTags(mainPointAttributeFieldIndices, tagCollectionPointFieldIndex, pointFeature, tags.ToArray()); + + pointInsertCursor.InsertFeature(pointFeature); + } + catch (Exception inEx) + { +#if DEBUG + foreach (var item in tags) + { + System.Diagnostics.Debug.WriteLine(string.Format("{0},{1}", item.k, item.v)); + } + System.Diagnostics.Debug.WriteLine(inEx.Message); + System.Diagnostics.Debug.WriteLine(inEx.StackTrace); +#endif + } + + if ((counter % 50000) == 0) + { + pointInsertCursor.Flush(); + } + + counter++; + + // if we encounter a whitespace, attempt to find the next node if it exists + if (nodeFileXmlReader.NodeType != XmlNodeType.Element) + nodeFileXmlReader.ReadToFollowing("node"); + + } while (nodeFileXmlReader.Name == "node"); + + nodeFileXmlReader.Close(); } - else + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + finally { - locationString = ((IDataset)table).Workspace.PathName + System.IO.Path.DirectorySeparatorChar + ((IDataset)table).BrowseName; } } - - return locationString; } - private string GetLocationString(IGPValue gpValue, IFeatureClass featureClass) + internal void PythonLoadOSMRelations(System.Object args) { - string locationString = String.Empty; - - if (featureClass.FeatureDataset != null) + using (ComReleaser comReleaser = new ComReleaser()) { - if (featureClass.FeatureDataset.Workspace.PathName.ToUpper().Contains(".GDS\\")) + string loadRelationsScriptName = String.Empty; + + try { - locationString = gpValue.GetAsText() + System.IO.Path.DirectorySeparatorChar + ((IDataset)featureClass).BrowseName; + string osmFileLocation = (args as List)[0]; + string loadSuperRelations = (args as List)[1]; + string sourceLineFeatureClassLocation = (args as List)[2]; + string sourcePolygonFeatureClassLocation = (args as List)[3]; + string lineFieldNames = (args as List)[4]; + string polygonFieldNames = (args as List)[5]; + string lineFeatureClassLocation = (args as List)[6]; + string polygonFeatureClassLocation = (args as List)[7]; + + FileInfo parseFileInfo = new FileInfo(osmFileLocation); + string pyScriptFileName = parseFileInfo.Name.Split('.')[0] + ".py"; + loadRelationsScriptName = System.IO.Path.GetTempPath() + pyScriptFileName; + string toolboxPath = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), + new string[] {OSMGPFactory.GetArcGIS10InstallLocation(), + @"ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx" + }); + + using (TextWriter writer = new StreamWriter(loadRelationsScriptName)) + { + writer.WriteLine("import arcpy, sys"); + writer.WriteLine(""); + writer.WriteLine("# load the standard OpenStreetMap tool box as it references the core OSM tools"); + writer.WriteLine(String.Format("arcpy.ImportToolbox(r'{0}')", toolboxPath)); + writer.WriteLine("arcpy.env.overwriteOutput = True"); + writer.WriteLine(""); + writer.WriteLine("arcpy.OSMGPRelationLoader_osmtools(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7], sys.argv[8])"); + } + + System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", + String.Join(" ", new string[] {"/c python", + loadRelationsScriptName, + osmFileLocation, + loadSuperRelations, + sourceLineFeatureClassLocation, + sourcePolygonFeatureClassLocation, + lineFieldNames, + polygonFieldNames, + lineFeatureClassLocation, + polygonFeatureClassLocation + }) + ); + + processStartInfo.RedirectStandardOutput = true; + processStartInfo.UseShellExecute = false; + + processStartInfo.CreateNoWindow = true; + + System.Diagnostics.Process loadProcess = new System.Diagnostics.Process(); + loadProcess.StartInfo = processStartInfo; + loadProcess.Start(); + + string result = loadProcess.StandardOutput.ReadToEnd(); } - else - locationString = featureClass.FeatureDataset.Workspace.PathName + System.IO.Path.DirectorySeparatorChar + featureClass.FeatureDataset.BrowseName + System.IO.Path.DirectorySeparatorChar + ((IDataset)featureClass).BrowseName; - } - else - { - locationString = ((IDataset)featureClass).Workspace.PathName + System.IO.Path.DirectorySeparatorChar + ((IDataset)featureClass).BrowseName; - } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + finally + { + if (!String.IsNullOrEmpty(loadRelationsScriptName)) + System.IO.File.Delete(loadRelationsScriptName); - return locationString; + if (Interlocked.Decrement(ref _numberOfThreads) == 0) + _manualResetEvent.Set(); + } + } } - private bool CheckIfExists(ITable searchTable, string osmID) + internal void PythonLoadOSMWays(System.Object args) { - bool featureAlreadyExists = true; - - try + using (ComReleaser comReleaser = new ComReleaser()) { - string sqlIdentifier = searchTable.SqlIdentifier(osmID); - using (ComReleaser comReleaser = new ComReleaser()) + string loadWaysScriptName = String.Empty; + + try { + string osmFileLocation = (args as List)[0]; + string sourcePointsFeatureClassLocation = (args as List)[1]; + string lineFieldNames = (args as List)[2]; + string polygonFieldNames = (args as List)[3]; + string lineFeatureClassLocation = (args as List)[4]; + string polygonFeatureClassLocation = (args as List)[5]; + + + FileInfo parseFileInfo = new FileInfo(osmFileLocation); + string pyScriptFileName = parseFileInfo.Name.Split('.')[0] + ".py"; + loadWaysScriptName = System.IO.Path.GetTempPath() + pyScriptFileName; + string toolboxPath = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), + new string[] {OSMGPFactory.GetArcGIS10InstallLocation(), + @"ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx" + }); + + using (TextWriter writer = new StreamWriter(loadWaysScriptName)) + { + writer.WriteLine("import arcpy, sys"); + writer.WriteLine(""); + writer.WriteLine("# load the standard OpenStreetMap tool box as it references the core OSM tools"); + writer.WriteLine(String.Format("arcpy.ImportToolbox(r'{0}')", toolboxPath)); + writer.WriteLine("arcpy.env.overwriteOutput = True"); + writer.WriteLine(""); + writer.WriteLine("arcpy.OSMGPWayLoader_osmtools(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6])"); + } - IQueryFilter queryFilter = new QueryFilterClass(); - queryFilter.WhereClause = sqlIdentifier + " = '" + osmID + "'"; + System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", + String.Join(" ", new string[] {"/c python", + loadWaysScriptName, + osmFileLocation, + sourcePointsFeatureClassLocation, + lineFieldNames, + polygonFieldNames, + lineFeatureClassLocation, + polygonFeatureClassLocation + }) + ); - ICursor rowCursor = searchTable.Search(queryFilter, false); - comReleaser.ManageLifetime(rowCursor); + processStartInfo.RedirectStandardOutput = true; + processStartInfo.UseShellExecute = false; - IRow foundRow = rowCursor.NextRow(); + processStartInfo.CreateNoWindow = true; - if (foundRow == null) - { - featureAlreadyExists = false; - } + System.Diagnostics.Process loadProcess = new System.Diagnostics.Process(); + loadProcess.StartInfo = processStartInfo; + loadProcess.Start(); - Marshal.ReleaseComObject(foundRow); + string result = loadProcess.StandardOutput.ReadToEnd(); } - } - catch { } - - return featureAlreadyExists; + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + finally + { + if (!String.IsNullOrEmpty(loadWaysScriptName)) + System.IO.File.Delete(loadWaysScriptName); + if (Interlocked.Decrement(ref _numberOfThreads) == 0) + _manualResetEvent.Set(); + } + } } - internal List loadOSMWays(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message, IGPValue targetGPValue, IFeatureClass osmPointFeatureClass, IFeatureClass osmLineFeatureClass, IFeatureClass osmPolygonFeatureClass, bool conserveMemory, bool fastLoad, int wayCapacity, ref Dictionary osmNodeDictionary, IFeatureWorkspace featureWorkspace, ISpatialReference downloadSpatialReference, OSMDomains availableDomains, bool checkForExisting) + internal void PythonLoadOSMNodes(System.Object args) { - if (osmLineFeatureClass == null) + using (ComReleaser comReleaser = new ComReleaser()) { - throw new ArgumentNullException("osmLineFeatureClass"); - } + string loadNodeScriptName = String.Empty; - if (osmPolygonFeatureClass == null) - { - throw new ArgumentNullException("osmPolygonFeatureClass"); + try + { + string osmFileLocation = (args as List)[0]; + string fileGDBLocation = (args as List)[1]; + string featureClassName = (args as List)[2]; + string fieldNames = (args as List)[3]; + string useCacheString = (args as List)[4]; + + FileInfo parseFileInfo = new FileInfo(fileGDBLocation); + string pyScriptFileName = parseFileInfo.Name.Split('.')[0] + ".py"; + loadNodeScriptName = System.IO.Path.GetTempPath() + pyScriptFileName; + string toolboxPath = String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), + new string[] {OSMGPFactory.GetArcGIS10InstallLocation(), + @"ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx" + }); + + using (TextWriter writer = new StreamWriter(loadNodeScriptName)) + { + writer.WriteLine("import arcpy, sys"); + writer.WriteLine(""); + writer.WriteLine("# load the standard OpenStreetMap tool box as it references the core OSM tools"); + writer.WriteLine(String.Format("arcpy.ImportToolbox(r'{0}')", toolboxPath)); + writer.WriteLine("arcpy.env.overwriteOutput = True"); + writer.WriteLine(""); + writer.WriteLine("arcpy.OSMGPNodeLoader_osmtools(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])"); + } + +#if DEBUG + System.Diagnostics.Debug.WriteLine(String.Join(" ", new string[] {"/c python", + loadNodeScriptName, + osmFileLocation, + fieldNames, + useCacheString, + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { fileGDBLocation, featureClassName }) + }) + ); +#endif + + System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", + String.Join(" ", new string[] {"/c python", + loadNodeScriptName, + osmFileLocation, + fieldNames, + useCacheString, + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { fileGDBLocation, featureClassName }) + }) + ); + + processStartInfo.RedirectStandardOutput = true; + processStartInfo.UseShellExecute = false; + + processStartInfo.CreateNoWindow = true; + + System.Diagnostics.Process loadProcess = new System.Diagnostics.Process(); + loadProcess.StartInfo = processStartInfo; + loadProcess.Start(); + + string result = loadProcess.StandardOutput.ReadToEnd(); + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + finally + { + if (!string.IsNullOrEmpty(loadNodeScriptName)) + System.IO.File.Delete(loadNodeScriptName); + + if (Interlocked.Decrement(ref _numberOfThreads) == 0) + _manualResetEvent.Set(); + } } + } - XmlReader osmFileXmlReader = null; - XmlSerializer waySerializer = null; - List missingWays = null; + internal void loadOSMWays(List osmWayFileNames, string sourcePointFCName, List wayGDBNames, string lineFeatureClassName, string polygonFeatureClassName, List lineFieldNames, List polygonFieldNames, ref IGPMessages toolMessages, ref ITrackCancel CancelTracker) + { + // create the point feature classes in the temporary loading fgdbs + OSMToolHelper toolHelper = new OSMToolHelper(); + IGeoProcessor2 geoProcessor = new GeoProcessorClass() as IGeoProcessor2; + geoProcessor.AddOutputsToMap = false; + IGeoProcessorResult gpResults = null; - try + Stopwatch executionStopwatch = System.Diagnostics.Stopwatch.StartNew(); + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_loading_ways"))); + + // in the case of a single thread we can use the parent process directly to convert the osm to the target featureclass + if (osmWayFileNames.Count == 1) { - missingWays = new List(); + IGPFunction wayLoader = new OSMGPWayLoader() as IGPFunction; - int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID"); - int osmWayRefCountFieldIndex = osmPointFeatureClass.FindField("wayRefCount"); + IGPUtilities gpUtilities = new GPUtilitiesClass(); + IArray parameterValues = new ArrayClass(); + parameterValues.Add(gpUtilities.CreateParameterValue(osmWayFileNames[0], new DEFileTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(sourcePointFCName, new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(String.Join(";", lineFieldNames.ToArray()), new GPMultiValueTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(String.Join(";", polygonFieldNames.ToArray()), new GPMultiValueTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string [] {wayGDBNames[0], lineFeatureClassName}), new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionOutput)); + parameterValues.Add(gpUtilities.CreateParameterValue(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { wayGDBNames[0], polygonFeatureClassName}), new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionOutput)); + wayLoader.Execute(parameterValues, CancelTracker, null, toolMessages); - int osmLineIDFieldIndex = osmLineFeatureClass.FindField("OSMID"); - Dictionary osmLineDomainAttributeFieldIndices = new Dictionary(); - Dictionary osmLineDomainAttributeFieldLength = new Dictionary(); - foreach (var domains in availableDomains.domain) - { - int currentFieldIndex = osmLineFeatureClass.FindField(domains.name); + ComReleaser.ReleaseCOMObject(gpUtilities); - if (currentFieldIndex != -1) - { - osmLineDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex); - osmLineDomainAttributeFieldLength.Add(domains.name, osmLineFeatureClass.Fields.get_Field(currentFieldIndex).Length); - } - } - int tagCollectionPolylineFieldIndex = osmLineFeatureClass.FindField("osmTags"); - int osmUserPolylineFieldIndex = osmLineFeatureClass.FindField("osmuser"); - int osmUIDPolylineFieldIndex = osmLineFeatureClass.FindField("osmuid"); - int osmVisiblePolylineFieldIndex = osmLineFeatureClass.FindField("osmvisible"); - int osmVersionPolylineFieldIndex = osmLineFeatureClass.FindField("osmversion"); - int osmChangesetPolylineFieldIndex = osmLineFeatureClass.FindField("osmchangeset"); - int osmTimeStampPolylineFieldIndex = osmLineFeatureClass.FindField("osmtimestamp"); - int osmMemberOfPolylineFieldIndex = osmLineFeatureClass.FindField("osmMemberOf"); - int osmMembersPolylineFieldIndex = osmLineFeatureClass.FindField("osmMembers"); - int osmSupportingElementPolylineFieldIndex = osmLineFeatureClass.FindField("osmSupportingElement"); + executionStopwatch.Stop(); + TimeSpan wayLoadingTimeSpan = executionStopwatch.Elapsed; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_doneloading_ways"), wayLoadingTimeSpan.Hours, wayLoadingTimeSpan.Minutes, wayLoadingTimeSpan.Seconds)); - int osmPolygonIDFieldIndex = osmPolygonFeatureClass.FindField("OSMID"); - Dictionary osmPolygonDomainAttributeFieldIndices = new Dictionary(); - Dictionary osmPolygonDomainAttributeFieldLength = new Dictionary(); - foreach (var domains in availableDomains.domain) + } + else + { + using (ComReleaser comReleaser = new ComReleaser()) { - int currentFieldIndex = osmPolygonFeatureClass.FindField(domains.name); + IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactoryClass(); + comReleaser.ManageLifetime(workspaceFactory); - if (currentFieldIndex != -1) + for (int gdbIndex = 0; gdbIndex < wayGDBNames.Count; gdbIndex++) { - osmPolygonDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex); - osmPolygonDomainAttributeFieldLength.Add(domains.name, osmPolygonFeatureClass.Fields.get_Field(currentFieldIndex).Length); + FileInfo gdbFileInfo = new FileInfo(wayGDBNames[gdbIndex]); + IWorkspaceName workspaceName = workspaceFactory.Create(gdbFileInfo.DirectoryName, gdbFileInfo.Name, new PropertySetClass(), 0); + comReleaser.ManageLifetime(workspaceName); } } - int tagCollectionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmTags"); - int osmUserPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmuser"); - int osmUIDPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmuid"); - int osmVisiblePolygonFieldIndex = osmPolygonFeatureClass.FindField("osmvisible"); - int osmVersionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmversion"); - int osmChangesetPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmchangeset"); - int osmTimeStampPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmtimestamp"); - int osmMemberOfPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmMemberOf"); - int osmMembersPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmMembers"); - int osmSupportingElementPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmSupportingElement"); - - ISpatialReferenceFactory spatialRef = new SpatialReferenceEnvironmentClass(); - ISpatialReference wgs84 = spatialRef.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984); - - bool shouldProject = !((IClone)wgs84).IsEqual((IClone)downloadSpatialReference); - // set up the progress indicator - IStepProgressor stepProgressor = TrackCancel as IStepProgressor; + _manualResetEvent = new ManualResetEvent(false); + _numberOfThreads = osmWayFileNames.Count; - if (stepProgressor != null) + for (int i = 0; i < osmWayFileNames.Count; i++) { - stepProgressor.MinRange = 0; - stepProgressor.MaxRange = wayCapacity; - stepProgressor.Position = 0; - stepProgressor.Message = _resourceManager.GetString("GPTools_OSMGPFileReader_loadingWays"); - stepProgressor.StepValue = 1; - stepProgressor.Show(); + Thread t = new Thread(new ParameterizedThreadStart(PythonLoadOSMWays)); + t.Start(new List() { + osmWayFileNames[i], + sourcePointFCName, + String.Join(";", lineFieldNames.ToArray()), + String.Join(";", polygonFieldNames.ToArray()), + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string [] {wayGDBNames[i], lineFeatureClassName}), + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string [] {wayGDBNames[i], polygonFeatureClassName}) }); } - bool lineIndexRebuildRequired = false; - bool polygonIndexRebuildRequired = false; + // wait for all nodes to complete loading before appending all into the target feature class + _manualResetEvent.WaitOne(); + _manualResetEvent.Close(); - int wayCount = 0; - object missingValue = System.Reflection.Missing.Value; - // enterprise GDB indicator -- supporting load only mode - IFeatureClassLoad lineFeatureLoad = null; - IFeatureClassLoad polygonFeatureLoad = null; + executionStopwatch.Stop(); + TimeSpan wayLoadingTimeSpan = executionStopwatch.Elapsed; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_doneloading_ways"), wayLoadingTimeSpan.Hours, wayLoadingTimeSpan.Minutes, wayLoadingTimeSpan.Seconds)); - using (SchemaLockManager lineLock = new SchemaLockManager(osmLineFeatureClass as ITable), polygonLock = new SchemaLockManager(osmPolygonFeatureClass as ITable)) + + // delete the temp osm files from disk + foreach (string osmFile in osmWayFileNames) { - using (ComReleaser comReleaser = new ComReleaser()) + try { - IFeatureBuffer featureLineBuffer = null; - IFeatureCursor insertLineCursor = osmLineFeatureClass.Insert(true); - comReleaser.ManageLifetime(insertLineCursor); + System.IO.File.Delete(osmFile); + } + catch { } + } - IFeatureBuffer featurePolygonBuffer = null; - IFeatureCursor insertPolygonCursor = osmPolygonFeatureClass.Insert(true); - comReleaser.ManageLifetime(insertPolygonCursor); + // we will need one less as the first osm file is loaded into the target feature classes + List linesFCNamesArray = new List(wayGDBNames.Count); + List polygonFCNamesArray = new List(wayGDBNames.Count); - if (((IWorkspace)featureWorkspace).WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace) - { - lineFeatureLoad = osmLineFeatureClass as IFeatureClassLoad; - polygonFeatureLoad = osmPolygonFeatureClass as IFeatureClassLoad; - } + // append all lines into the target feature class + for (int gdbIndex = 0; gdbIndex < wayGDBNames.Count; gdbIndex++) + { + linesFCNamesArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { wayGDBNames[gdbIndex], lineFeatureClassName })); + polygonFCNamesArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { wayGDBNames[gdbIndex], polygonFeatureClassName })); + } - if (lineFeatureLoad != null) - { - lineFeatureLoad.LoadOnlyMode = true; - } + string[] pointFCElement = sourcePointFCName.Split(System.IO.Path.DirectorySeparatorChar); + string sourceFGDB = sourcePointFCName.Substring(0, sourcePointFCName.Length - pointFCElement[pointFCElement.Length - 1].Length - 1); - if (polygonFeatureLoad != null) - { - polygonFeatureLoad.LoadOnlyMode = true; - } + // append all the lines + IVariantArray parameterArray = new VarArrayClass(); + parameterArray.Add(String.Join(";", linesFCNamesArray.ToArray())); + parameterArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { sourceFGDB, lineFeatureClassName })); - ISpatialReference nativeLineSpatialReference = ((IGeoDataset)osmLineFeatureClass).SpatialReference; - ISpatialReference nativePolygonSpatialReference = ((IGeoDataset)osmPolygonFeatureClass).SpatialReference; + gpResults = geoProcessor.Execute("Append_management", parameterArray, CancelTracker); - IQueryFilter osmIDQueryFilter = new QueryFilterClass(); - string sqlPointOSMID = osmPointFeatureClass.SqlIdentifier("OSMID"); - IFeatureCursor updatePointCursor = null; + IGPMessages messages = gpResults.GetResultMessages(); + toolMessages.AddMessages(gpResults.GetResultMessages()); - osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation); - waySerializer = new XmlSerializer(typeof(way)); +#if DEBUG + for (int i = 0; i < messages.Count; i++) + { + System.Diagnostics.Debug.WriteLine(messages.GetMessage(i).Description); + } +#endif - // the point query filter for updates will not changes, so let's do that ahead of time - try - { - osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name; - } - catch - { } + // append all the polygons + parameterArray = new VarArrayClass(); + parameterArray.Add(String.Join(";", polygonFCNamesArray.ToArray())); + parameterArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { sourceFGDB, polygonFeatureClassName })); - osmFileXmlReader.MoveToContent(); - while (osmFileXmlReader.Read()) - { - if (osmFileXmlReader.IsStartElement()) - { - if (osmFileXmlReader.Name == "way") - { - string currentwayString = osmFileXmlReader.ReadOuterXml(); + gpResults = geoProcessor.Execute("Append_management", parameterArray, CancelTracker); - // assuming the way to be a polyline is sort of a safe assumption - // and won't cause any topology problem due to orientation and closeness - bool wayIsLine = true; - bool wayIsComplete = true; + messages = gpResults.GetResultMessages(); + toolMessages.AddMessages(gpResults.GetResultMessages()); - way currentWay = null; +#if DEBUG + for (int i = 0; i < messages.Count; i++) + { + System.Diagnostics.Debug.WriteLine(messages.GetMessage(i).Description); + } +#endif - try - { - using (StringReader wayReader = new System.IO.StringReader(currentwayString)) - { - currentWay = waySerializer.Deserialize(wayReader) as way; - } + // delete temp file geodatabases + for (int gdbIndex = 0; gdbIndex < wayGDBNames.Count; gdbIndex++) + { + if (!sourceFGDB.Equals(wayGDBNames[gdbIndex])) + { + parameterArray = new VarArrayClass(); + parameterArray.Add(wayGDBNames[gdbIndex]); + geoProcessor.Execute("Delete_management", parameterArray, CancelTracker); + } + } - // if the deserialization fails then go ahead and read the next xml element - if (currentWay == null) - { - continue; - } + // compute the OSM index on the target line featureclass + parameterArray = CreateAddIndexParameterArray(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { sourceFGDB, lineFeatureClassName }), "OSMID", "osmID_IDX", "UNIQUE", ""); + gpResults = geoProcessor.Execute("AddIndex_management", parameterArray, CancelTracker); + toolMessages.AddMessages(gpResults.GetResultMessages()); - // and we are expecting at least some nodes on the way itself - if (currentWay.nd == null) - { - continue; - } + // compute the OSM index on the target polygon featureclass + parameterArray = CreateAddIndexParameterArray(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { sourceFGDB, polygonFeatureClassName }), "OSMID", "osmID_IDX", "UNIQUE", ""); + gpResults = geoProcessor.Execute("AddIndex_management", parameterArray, CancelTracker); + toolMessages.AddMessages(gpResults.GetResultMessages()); - featureLineBuffer = osmLineFeatureClass.CreateFeatureBuffer(); - featurePolygonBuffer = osmPolygonFeatureClass.CreateFeatureBuffer(); + ComReleaser.ReleaseCOMObject(geoProcessor); + } + } - IPointCollection wayPointCollection = null; - wayIsLine = IsThisWayALine(currentWay); + internal void loadOSMNodes(List osmNodeFileNames, List nodeGDBNames, string featureClassName, string targetFeatureClass, List tagsToLoad, bool deleteNodes, ref IGPMessages toolMessages, ref ITrackCancel CancelTracker) + { + // create the point feature classes in the temporary loading fgdbs + OSMToolHelper toolHelper = new OSMToolHelper(); + IGeoProcessor2 geoProcessor = new GeoProcessorClass() as IGeoProcessor2; + geoProcessor.AddOutputsToMap = false; + IGeoProcessorResult gpResults = null; - if (wayIsLine) - { + Stopwatch executionStopwatch = System.Diagnostics.Stopwatch.StartNew(); - // check if a feature with the same OSMID already exists, because the can only be one - if (checkForExisting == true) - { - if (CheckIfExists(osmLineFeatureClass as ITable, currentWay.id)) - { - continue; - } - } + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_loading_nodes"))); - IPolyline wayPolyline = new PolylineClass(); - wayPolyline.SpatialReference = downloadSpatialReference; + string useCacheString = "USE_CACHE"; + if (!deleteNodes) + useCacheString = "DO_NOT_USE_CACHE"; - IPointIDAware polylineIDAware = wayPolyline as IPointIDAware; - polylineIDAware.PointIDAware = true; - wayPointCollection = wayPolyline as IPointCollection; + // in the case of a single thread we can use the parent process directly to convert the osm to the target featureclass + if (osmNodeFileNames.Count == 1) + { + IGPFunction nodeLoader = new OSMGPNodeLoader() as IGPFunction; - # region generate line geometry - if (conserveMemory == false) - { - for (int ndIndex = 0; ndIndex < currentWay.nd.Length; ndIndex++) - { - string ndID = currentWay.nd[ndIndex].@ref; - if (osmNodeDictionary.ContainsKey(ndID)) - { - IPoint newPoint = new PointClass(); - newPoint.X = osmNodeDictionary[ndID].Longitude; - newPoint.Y = osmNodeDictionary[ndID].Latitude; + IGPUtilities gpUtilities = new GPUtilitiesClass(); + IArray parameterValues = new ArrayClass(); + parameterValues.Add(gpUtilities.CreateParameterValue(osmNodeFileNames[0], new DEFileTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(String.Join(";",tagsToLoad.ToArray()), new GPMultiValueTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(useCacheString, new GPBooleanTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(targetFeatureClass, new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionOutput)); + nodeLoader.Execute(parameterValues, CancelTracker, null, toolMessages); - newPoint.SpatialReference = wgs84; + ComReleaser.ReleaseCOMObject(gpUtilities); - if (shouldProject) - { - newPoint.Project(((IGeoDataset)osmLineFeatureClass).SpatialReference); - } + executionStopwatch.Stop(); + TimeSpan nodeLoadingTimeSpan = executionStopwatch.Elapsed; - IPointIDAware idAware = newPoint as IPointIDAware; - idAware.PointIDAware = true; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_doneloading_nodes"), nodeLoadingTimeSpan.Hours, nodeLoadingTimeSpan.Minutes, nodeLoadingTimeSpan.Seconds)); + } + else + { + using (ComReleaser comReleaser = new ComReleaser()) + { + IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactoryClass(); + comReleaser.ManageLifetime(workspaceFactory); - newPoint.ID = osmNodeDictionary[ndID].pointObjectID; + for (int gdbIndex = 1; gdbIndex < nodeGDBNames.Count; gdbIndex++) + { + FileInfo gdbFileInfo = new FileInfo(nodeGDBNames[gdbIndex]); + IWorkspaceName workspaceName = workspaceFactory.Create(gdbFileInfo.DirectoryName, gdbFileInfo.Name, new PropertySetClass(), 0); + comReleaser.ManageLifetime(workspaceName); + } + } - wayPointCollection.AddPoint(newPoint, ref missingValue, ref missingValue); + _manualResetEvent = new ManualResetEvent(false); + _numberOfThreads = osmNodeFileNames.Count; - osmNodeDictionary[ndID].RefCounter = osmNodeDictionary[ndID].RefCounter + 1; - } - else - { - message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedline_node"), currentWay.id, ndID)); - // set the flag that the way is complete due to a missing node - wayIsComplete = false; - break; - } - } + for (int i = 0; i < osmNodeFileNames.Count; i++) + { + Thread t = new Thread(new ParameterizedThreadStart(PythonLoadOSMNodes)); + t.Start(new List() { osmNodeFileNames[i], nodeGDBNames[i], featureClassName, String.Join(";",tagsToLoad.ToArray()), useCacheString }); + } - } - else - { - for (int pointIndex = 0; pointIndex < currentWay.nd.Length; pointIndex++) - { - wayPointCollection.AddPoint(new PointClass()); - } + // wait for all nodes to complete loading before appending all into the target feature class + _manualResetEvent.WaitOne(); + _manualResetEvent.Close(); - List idRequests = SplitOSMIDRequests(currentWay, 2); + executionStopwatch.Stop(); + TimeSpan nodeLoadingTimeSpan = executionStopwatch.Elapsed; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_doneloading_nodes"), nodeLoadingTimeSpan.Hours, nodeLoadingTimeSpan.Minutes, nodeLoadingTimeSpan.Seconds)); - // build a list of node ids we can use to determine the point index in the line geometry - // as well as a dictionary to determine the position in the list in case of duplicates nodes - Dictionary nodePositionDictionary = new Dictionary(currentWay.nd.Length); - List nodeIDs = new List(currentWay.nd.Length); + // we done using the osm files for loading + foreach (string osmFile in osmNodeFileNames) + { + try + { + System.IO.File.Delete(osmFile); + } + catch { } + } - foreach (nd wayNode in currentWay.nd) - { - nodeIDs.Add(wayNode.@ref); + // we need one less as the first node is already loaded into the target feature class + List fcNamesArray = new List(osmNodeFileNames.Count - 1); + // - if (nodePositionDictionary.ContainsKey(wayNode.@ref) == false) - { - nodePositionDictionary.Add(wayNode.@ref, 0); - } - } + // append all points into the target feature class + for (int gdbIndex = 1; gdbIndex < nodeGDBNames.Count; gdbIndex++) + { + fcNamesArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { nodeGDBNames[gdbIndex], featureClassName })); + } - try - { - osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name; - } - catch - { } + IVariantArray parameterArray = new VarArrayClass(); + parameterArray.Add(String.Join(";", fcNamesArray.ToArray())); + parameterArray.Add(targetFeatureClass); + gpResults = geoProcessor.Execute("Append_management", parameterArray, CancelTracker); - foreach (string request in idRequests) - { - string idCompareString = request; - osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + request; - using (ComReleaser innerComReleaser = new ComReleaser()) - { - updatePointCursor = osmPointFeatureClass.Update(osmIDQueryFilter, true); - innerComReleaser.ManageLifetime(updatePointCursor); + IGPMessages messages = gpResults.GetResultMessages(); + toolMessages.AddMessages(gpResults.GetResultMessages()); - IFeature nodeFeature = updatePointCursor.NextFeature(); + // delete the temp loading fgdb for points + for (int gdbIndex = 1; gdbIndex < nodeGDBNames.Count; gdbIndex++) + { + parameterArray = new VarArrayClass(); + parameterArray.Add(nodeGDBNames[gdbIndex]); + geoProcessor.Execute("Delete_management", parameterArray, CancelTracker); + } - while (nodeFeature != null) - { - // determine the index of the point in with respect to the node position - string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex)); + // compute the OSM index on the target featureclass + parameterArray = CreateAddIndexParameterArray(targetFeatureClass, "OSMID", "osmID_IDX", "UNIQUE", ""); + gpResults = geoProcessor.Execute("AddIndex_management", parameterArray, CancelTracker); + toolMessages.AddMessages(gpResults.GetResultMessages()); - // remove the ID from the request string - idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty); + if (deleteNodes) + { + // compute the support element index on the target featureclass + parameterArray = CreateAddIndexParameterArray(targetFeatureClass, "osmSupportingElement", "supEl_IDX", "NON_UNIQUE", ""); + gpResults = geoProcessor.Execute("AddIndex_management", parameterArray, CancelTracker); + toolMessages.AddMessages(gpResults.GetResultMessages()); + } + } + ComReleaser.ReleaseCOMObject(geoProcessor); + } - int nodePositionIndex = -1; + internal void loadOSMNodes(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message, IGPValue targetGPValue, IFeatureClass osmPointFeatureClass, bool conserveMemory, bool fastLoad, int nodeCapacity, ref Dictionary osmNodeDictionary, IFeatureWorkspace featureWorkspace, ISpatialReference downloadSpatialReference, OSMDomains availableDomains, bool checkForExisting) + { + XmlReader osmFileXmlReader = null; + XmlSerializer nodeSerializer = null; - while ((nodePositionIndex = nodeIDs.IndexOf(nodeOSMIDString, nodePositionDictionary[nodeOSMIDString])) != -1) - { - //// update the new position start search index - nodePositionDictionary[nodeOSMIDString] = nodePositionIndex + 1; + try + { - IPoint nodePoint = (IPoint)nodeFeature.ShapeCopy; - nodePoint.ID = nodeFeature.OID; - wayPointCollection.UpdatePoint(nodePositionIndex, nodePoint); + osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation); + nodeSerializer = new XmlSerializer(typeof(node)); - // increase the reference counter - if (osmWayRefCountFieldIndex != -1) - { - nodeFeature.set_Value(osmWayRefCountFieldIndex, ((int)nodeFeature.get_Value(osmWayRefCountFieldIndex)) + 1); + ISpatialReferenceFactory spatialRef = new SpatialReferenceEnvironmentClass(); + ISpatialReference wgs84 = spatialRef.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984); - updatePointCursor.UpdateFeature(nodeFeature); - } - } + bool shouldProject = !((IClone)wgs84).IsEqual((IClone)downloadSpatialReference); - if (nodeFeature != null) - Marshal.ReleaseComObject(nodeFeature); + int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID"); + Dictionary osmPointDomainAttributeFieldIndices = new Dictionary(); + Dictionary osmPointDomainAttributeFieldLength = new Dictionary(); - nodeFeature = updatePointCursor.NextFeature(); - } + foreach (var domains in availableDomains.domain) + { + int currentFieldIndex = osmPointFeatureClass.FindField(domains.name); - idCompareString = CleanReportedNodes(idCompareString); + if (currentFieldIndex != -1) + { + osmPointDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex); + osmPointDomainAttributeFieldLength.Add(domains.name, osmPointFeatureClass.Fields.get_Field(currentFieldIndex).Length); + } + } - // after removing the commas we should be left with only paranthesis left, meaning a string of length 2 - // if we have more then we have found a missing node, resulting in an incomplete way geometry - if (idCompareString.Length > 2) - { - message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedline_node"), currentWay.id, idCompareString)); - wayIsComplete = false; - } - } - } - } - #endregion + int tagCollectionPointFieldIndex = osmPointFeatureClass.FindField("osmTags"); + int osmUserPointFieldIndex = osmPointFeatureClass.FindField("osmuser"); + int osmUIDPointFieldIndex = osmPointFeatureClass.FindField("osmuid"); + int osmVisiblePointFieldIndex = osmPointFeatureClass.FindField("osmvisible"); + int osmVersionPointFieldIndex = osmPointFeatureClass.FindField("osmversion"); + int osmChangesetPointFieldIndex = osmPointFeatureClass.FindField("osmchangeset"); + int osmTimeStampPointFieldIndex = osmPointFeatureClass.FindField("osmtimestamp"); + int osmMemberOfPointFieldIndex = osmPointFeatureClass.FindField("osmMemberOf"); + int osmSupportingElementPointFieldIndex = osmPointFeatureClass.FindField("osmSupportingElement"); + int osmWayRefCountFieldIndex = osmPointFeatureClass.FindField("wayRefCount"); - if (wayIsComplete == false) - { - // if the way geometry is incomplete due to a missing node let's continue to the next way element - missingWays.Add(currentWay.id); - continue; - } - featureLineBuffer.Shape = wayPolyline; - featureLineBuffer.set_Value(osmLineIDFieldIndex, currentWay.id); + // set up the progress indicator + IStepProgressor stepProgressor = TrackCancel as IStepProgressor; + + if (stepProgressor != null) + { + stepProgressor.MinRange = 0; + stepProgressor.MaxRange = nodeCapacity; + stepProgressor.StepValue = (1); + stepProgressor.Message = _resourceManager.GetString("GPTools_OSMGPFileReader_loadingNodes"); + stepProgressor.Position = 0; + stepProgressor.Show(); + } + + // flag to determine if a computation of indices is required + bool indexBuildRequired = false; + if (nodeCapacity > 0) + indexBuildRequired = true; + + int pointCount = 0; + + + // let's insert all the points first + if (osmPointFeatureClass != null) + { + IPoint pointGeometry = null; + IFeatureBuffer pointFeature = null; + IFeatureClassLoad pointFeatureLoad = null; + + using (ComReleaser comReleaser = new ComReleaser()) + { + using (SchemaLockManager schemaLockManager = new SchemaLockManager(osmPointFeatureClass as ITable)) + { + + //if (((IWorkspace)featureWorkspace).WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace) + //{ + pointFeatureLoad = osmPointFeatureClass as IFeatureClassLoad; + //} + + IFeatureCursor pointInsertCursor = osmPointFeatureClass.Insert(true); + comReleaser.ManageLifetime(pointInsertCursor); + + if (pointFeatureLoad != null) + { + pointFeatureLoad.LoadOnlyMode = true; + } + + osmFileXmlReader.MoveToContent(); + + while (osmFileXmlReader.Read()) + { + if (osmFileXmlReader.IsStartElement()) + { + if (osmFileXmlReader.Name == "node") + { + string currentNodeString = osmFileXmlReader.ReadOuterXml(); + // turn the xml node representation into a node class representation + ESRI.ArcGIS.OSM.OSMClassExtension.node currentNode = null; + using (StringReader nodeReader = new System.IO.StringReader(currentNodeString)) + { + currentNode = nodeSerializer.Deserialize(nodeReader) as ESRI.ArcGIS.OSM.OSMClassExtension.node; } - else + + // check if a feature with the same OSMID already exists, because the can only be one + if (checkForExisting == true) { - // check if a feature with the same OSMID already exists, because the can only be one - if (checkForExisting == true) + if (CheckIfExists(osmPointFeatureClass as ITable, currentNode.id)) { - if (CheckIfExists(osmPolygonFeatureClass as ITable, currentWay.id)) - { - continue; - } + continue; } + } + try + { + pointFeature = osmPointFeatureClass.CreateFeatureBuffer(); - IPolygon wayPolygon = new PolygonClass(); - wayPolygon.SpatialReference = downloadSpatialReference; - - IPointIDAware polygonIDAware = wayPolygon as IPointIDAware; - polygonIDAware.PointIDAware = true; - - wayPointCollection = wayPolygon as IPointCollection; + pointGeometry = new PointClass(); + pointGeometry.X = Convert.ToDouble(currentNode.lon, new CultureInfo("en-US")); + pointGeometry.Y = Convert.ToDouble(currentNode.lat, new CultureInfo("en-US")); + pointGeometry.SpatialReference = wgs84; - #region generate polygon geometry - if (conserveMemory == false) + if (shouldProject) { - for (int ndIndex = 0; ndIndex < currentWay.nd.Length; ndIndex++) - { - string ndID = currentWay.nd[ndIndex].@ref; - if (osmNodeDictionary.ContainsKey(ndID)) - { - IPoint newPoint = new PointClass(); - newPoint.X = osmNodeDictionary[ndID].Longitude; - newPoint.Y = osmNodeDictionary[ndID].Latitude; - newPoint.SpatialReference = wgs84; + pointGeometry.Project(downloadSpatialReference); + } - if (shouldProject) - { - newPoint.Project(nativePolygonSpatialReference); - } + pointFeature.Shape = pointGeometry; - IPointIDAware idAware = newPoint as IPointIDAware; - idAware.PointIDAware = true; + pointFeature.set_Value(osmPointIDFieldIndex, currentNode.id); - newPoint.ID = osmNodeDictionary[ndID].pointObjectID; + string isSupportingNode = ""; + if (_osmUtility.DoesHaveKeys(currentNode.tag)) + { + // if case it has tags I assume that the node presents an entity of it own, + // hence it is not a supporting node in the context of supporting a way or relation + isSupportingNode = "no"; - wayPointCollection.AddPoint(newPoint, ref missingValue, ref missingValue); - } - else - { - message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedpolygon_node"), currentWay.id, ndID)); - wayIsComplete = false; - break; - } + if (conserveMemory == false) + { + osmNodeDictionary[currentNode.id] = new simplePointRef(Convert.ToSingle(currentNode.lon, new CultureInfo("en-US")), Convert.ToSingle(currentNode.lat, new CultureInfo("en-US")), 0, 0); } } else { - for (int pointIndex = 0; pointIndex < currentWay.nd.Length; pointIndex++) + // node has no tags -- at this point I assume that the absence of tags indicates that it is a supporting node + // for a way or a relation + isSupportingNode = "yes"; + + if (conserveMemory == false) { - wayPointCollection.AddPoint(new PointClass()); + osmNodeDictionary[currentNode.id] = new simplePointRef(Convert.ToSingle(currentNode.lon, new CultureInfo("en-US")), Convert.ToSingle(currentNode.lat, new CultureInfo("en-US")), 0, 0); } + } - List idRequests = SplitOSMIDRequests(currentWay, 2); + insertTags(osmPointDomainAttributeFieldIndices, osmPointDomainAttributeFieldLength, tagCollectionPointFieldIndex, pointFeature, currentNode.tag); - // build a list of node ids we can use to determine the point index in the line geometry - // as well as a dictionary to determine the position in the list in case of duplicates nodes - Dictionary nodePositionDictionary = new Dictionary(currentWay.nd.Length); - List nodeIDs = new List(currentWay.nd.Length); + if (fastLoad == false) + { + if (osmSupportingElementPointFieldIndex > -1) + { + pointFeature.set_Value(osmSupportingElementPointFieldIndex, isSupportingNode); + } - foreach (nd wayNode in currentWay.nd) + if (osmWayRefCountFieldIndex > -1) { - nodeIDs.Add(wayNode.@ref); + pointFeature.set_Value(osmWayRefCountFieldIndex, 0); + } - if (nodePositionDictionary.ContainsKey(wayNode.@ref) == false) + // store the administrative attributes + // user, uid, version, changeset, timestamp, visible + if (osmUserPointFieldIndex > -1) + { + if (!String.IsNullOrEmpty(currentNode.user)) { - nodePositionDictionary.Add(wayNode.@ref, 0); + pointFeature.set_Value(osmUserPointFieldIndex, currentNode.user); } } - try + if (osmUIDPointFieldIndex > -1) { - osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name; + if (!String.IsNullOrEmpty(currentNode.uid)) + { + pointFeature.set_Value(osmUIDPointFieldIndex, Convert.ToInt32(currentNode.uid)); + } } - catch - { } - - foreach (string osmIDRequest in idRequests) + if (osmVisiblePointFieldIndex > -1) { - string idCompareString = osmIDRequest; + pointFeature.set_Value(osmVisiblePointFieldIndex, currentNode.visible.ToString()); + } - using (ComReleaser innercomReleaser = new ComReleaser()) + if (osmVersionPointFieldIndex > -1) + { + if (!String.IsNullOrEmpty(currentNode.version)) { - osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + osmIDRequest; - updatePointCursor = osmPointFeatureClass.Update(osmIDQueryFilter, false); - innercomReleaser.ManageLifetime(updatePointCursor); + pointFeature.set_Value(osmVersionPointFieldIndex, Convert.ToInt32(currentNode.version)); + } + } - IFeature nodeFeature = updatePointCursor.NextFeature(); + if (osmChangesetPointFieldIndex > -1) + { + if (!String.IsNullOrEmpty(currentNode.changeset)) + { + pointFeature.set_Value(osmChangesetPointFieldIndex, Convert.ToInt32(currentNode.changeset)); + } + } - while (nodeFeature != null) + if (osmTimeStampPointFieldIndex > -1) + { + if (!String.IsNullOrEmpty(currentNode.timestamp)) + { + try { - // determine the index of the point in with respect to the node position - string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex)); - - idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty); - - int nodePositionIndex = nodeIDs.IndexOf(nodeOSMIDString, nodePositionDictionary[nodeOSMIDString]); - - if (nodePositionIndex > -1) - { - // update the new position start search index - nodePositionDictionary[nodeOSMIDString] = nodePositionIndex + 1; - - IPoint nodePoint = (IPoint)nodeFeature.ShapeCopy; - nodePoint.ID = nodeFeature.OID; - wayPointCollection.UpdatePoint(nodePositionIndex, nodePoint); - - // increase the reference counter - if (osmWayRefCountFieldIndex != -1) - { - nodeFeature.set_Value(osmWayRefCountFieldIndex, ((int)nodeFeature.get_Value(osmWayRefCountFieldIndex)) + 1); - - updatePointCursor.UpdateFeature(nodeFeature); - } - } - - if (nodeFeature != null) - Marshal.ReleaseComObject(nodeFeature); - - nodeFeature = updatePointCursor.NextFeature(); + pointFeature.set_Value(osmTimeStampPointFieldIndex, Convert.ToDateTime(currentNode.timestamp)); } - - idCompareString = CleanReportedNodes(idCompareString); - - if (idCompareString.Length > 2) + catch (Exception ex) { - message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedpolygon_node"), currentWay.id, idCompareString)); - wayIsComplete = false; + message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_invalidTimeFormat"), ex.Message)); } } } } - #endregion + try + { + pointInsertCursor.InsertFeature(pointFeature); + pointCount = pointCount + 1; - if (wayIsComplete == false) + if (stepProgressor != null) + { + stepProgressor.Position = pointCount; + } + } + catch (Exception ex) { - continue; +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); +#endif + message.AddWarning(ex.Message); } - // remove the last point as OSM considers them to be coincident - wayPointCollection.RemovePoints(wayPointCollection.PointCount - 1, 1); - ((IPolygon)wayPointCollection).Close(); - - featurePolygonBuffer.Shape = (IPolygon)wayPointCollection; - featurePolygonBuffer.set_Value(osmPolygonIDFieldIndex, currentWay.id); - } + if ((pointCount % 50000) == 0) + { + message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_pointsloaded"), pointCount)); + pointInsertCursor.Flush(); + System.GC.Collect(); - if (wayIsLine) - { - insertTags(osmLineDomainAttributeFieldIndices, osmLineDomainAttributeFieldLength, tagCollectionPolylineFieldIndex, featureLineBuffer, currentWay.tag); + if (TrackCancel.Continue() == false) + { + return; + } + } } - else + catch (Exception ex) { - insertTags(osmPolygonDomainAttributeFieldIndices, osmPolygonDomainAttributeFieldLength, tagCollectionPolygonFieldIndex, featurePolygonBuffer, currentWay.tag); +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); +#endif + message.AddWarning(ex.Message); } - - // store the administrative attributes - // user, uid, version, changeset, timestamp, visible - if (fastLoad == false) + finally { - if (!String.IsNullOrEmpty(currentWay.user)) + if (pointFeature != null) { - if (wayIsLine) - { - if (osmUserPolylineFieldIndex != -1) - { - featureLineBuffer.set_Value(osmUserPolylineFieldIndex, currentWay.user); - } - } - else - { - if (osmUserPolygonFieldIndex != -1) - { - featurePolygonBuffer.set_Value(osmUserPolygonFieldIndex, currentWay.user); - } - } + Marshal.FinalReleaseComObject(pointFeature); + pointFeature = null; } - if (!String.IsNullOrEmpty(currentWay.uid)) + if (pointGeometry != null) { - if (wayIsLine) - { - if (osmUIDPolylineFieldIndex != -1) - { - featureLineBuffer.set_Value(osmUIDPolylineFieldIndex, Convert.ToInt32(currentWay.uid)); - } - } - else - { - if (osmUIDPolygonFieldIndex != -1) - { - featurePolygonBuffer.set_Value(osmUIDPolygonFieldIndex, Convert.ToInt32(currentWay.uid)); - } - } + Marshal.FinalReleaseComObject(pointGeometry); + pointGeometry = null; } + } - if (wayIsLine) - { - if (osmVisiblePolylineFieldIndex != -1) - { - featureLineBuffer.set_Value(osmVisiblePolylineFieldIndex, currentWay.visible.ToString()); - } - } - else - { - if (osmVisiblePolygonFieldIndex != -1) - { - featurePolygonBuffer.set_Value(osmVisiblePolygonFieldIndex, currentWay.visible.ToString()); - } - } + currentNode = null; + } + } + } - if (!String.IsNullOrEmpty(currentWay.version)) - { - if (wayIsLine) - { - if (osmVersionPolylineFieldIndex != -1) - { - featureLineBuffer.set_Value(osmVersionPolylineFieldIndex, Convert.ToInt32(currentWay.version)); - } - } - else + if (stepProgressor != null) + { + stepProgressor.Hide(); + } + + pointInsertCursor.Flush(); + osmFileXmlReader.Close(); + + message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_pointsloaded"), pointCount)); + message.AddMessage(_resourceManager.GetString("GPTools_buildingpointidx")); + + if (pointFeatureLoad != null) + { + pointFeatureLoad.LoadOnlyMode = false; + } + } + } + + if (TrackCancel.Continue() == false) + { + return; + } + + using (ComReleaser comReleaser = new ComReleaser()) + { + IFeatureCursor updatePoints = osmPointFeatureClass.Update(null, false); + comReleaser.ManageLifetime(updatePoints); + + IFeature feature2Update = updatePoints.NextFeature(); + + while (feature2Update != null) + { + pointGeometry = feature2Update.Shape as IPoint; + pointGeometry.ID = feature2Update.OID; + feature2Update.Shape = pointGeometry; + + if (conserveMemory == false) + { + string osmid = Convert.ToString(feature2Update.get_Value(osmPointIDFieldIndex)); + if (osmNodeDictionary.ContainsKey(osmid)) + osmNodeDictionary[osmid].pointObjectID = feature2Update.OID; + } + + updatePoints.UpdateFeature(feature2Update); + + if (TrackCancel.Continue() == false) + { + return; + } + + if (feature2Update != null) + Marshal.ReleaseComObject(feature2Update); + + if (pointGeometry != null) + Marshal.ReleaseComObject(pointGeometry); + + feature2Update = updatePoints.NextFeature(); + } + } + + if (indexBuildRequired) + { + + IGeoProcessor2 geoProcessor = new GeoProcessorClass(); + bool storedOriginal = geoProcessor.AddOutputsToMap; + + try + { + IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + + IGPValue pointFeatureClass = gpUtilities3.MakeGPValueFromObject(osmPointFeatureClass); + + string fcLocation = GetLocationString(targetGPValue, osmPointFeatureClass); + + IIndexes featureClassIndexes = osmPointFeatureClass.Indexes; + int indexPosition = -1; + featureClassIndexes.FindIndex("osmID_IDX", out indexPosition); + + if (indexPosition == -1) + { + { + geoProcessor.AddOutputsToMap = false; + + IVariantArray parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", ""); + IGeoProcessorResult2 gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2; + } + } + if (pointCount > 500) + { + if (pointFeatureLoad == null) + { + UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation); + } + } + } + catch (COMException comEx) + { + message.AddWarning(comEx.Message); + } + catch (Exception ex) + { + message.AddWarning(ex.Message); + } + finally + { + geoProcessor.AddOutputsToMap = storedOriginal; + } + } + + } + } + catch (Exception ex) + { + message.AddError(120100, String.Format(_resourceManager.GetString("GPTools_Utility_NodeLoadError"), ex.Message)); + } + finally + { + if (osmFileXmlReader != null) + osmFileXmlReader = null; + + if (nodeSerializer != null) + nodeSerializer = null; + } + } + + private void insertTags(Dictionary AttributeFieldIndices, int tagCollectionFieldIndex, IRowBuffer row, tag[] tagsToInsert) + { + if (tagsToInsert != null) + { + TagKeyComparer tagKeyComparer = new TagKeyComparer(); + + foreach (var fieldName in AttributeFieldIndices.Keys) + { + string keyName = convert2OSMKey(fieldName, string.Empty); + + if (tagsToInsert.Contains(new tag() { k = keyName }, tagKeyComparer)) + { + tag item = tagsToInsert.Where(t => t.k == keyName).First(); + + int fieldIndex = AttributeFieldIndices[fieldName]; + if (fieldIndex > -1) + { + if (item.v.Length > row.Fields.get_Field(fieldIndex).Length) + row.set_Value(fieldIndex, item.v.Substring(0, row.Fields.get_Field(fieldIndex).Length)); + else + row.set_Value(fieldIndex, item.v); + } + } + else + { + int fieldIndex = AttributeFieldIndices[fieldName]; + if (fieldIndex > -1) + { + row.set_Value(fieldIndex, System.DBNull.Value); + } + } + } + + if (tagCollectionFieldIndex > -1) + { + if (tagsToInsert.Count() == 0) + row.set_Value(tagCollectionFieldIndex, System.DBNull.Value); + else + _osmUtility.insertOSMTags(tagCollectionFieldIndex, row, tagsToInsert); + } + } + else + { + if (tagCollectionFieldIndex > -1) + { + row.set_Value(tagCollectionFieldIndex, System.DBNull.Value); + } + } + } + + private void insertTags(Dictionary domainAttributeFieldIndices, Dictionary domainAttributeFieldLength, int tagCollectionFieldIndex, IRowBuffer row, tag[] tagsToInsert) + { + Dictionary tagGdbStorageValues = new Dictionary(domainAttributeFieldIndices.Count); + foreach (var item in domainAttributeFieldIndices) + { + tagGdbStorageValues[item.Key] = null; + } + + if (tagsToInsert != null) + { + foreach (tag tagItem in tagsToInsert) + { + if (domainAttributeFieldIndices.ContainsKey(tagItem.k)) + { + if (tagItem.v.Length <= domainAttributeFieldLength[tagItem.k]) + { + tagGdbStorageValues[tagItem.k] = tagItem.v; + } + } + } + } + + foreach (var item in domainAttributeFieldIndices) + { + row.set_Value(item.Value, tagGdbStorageValues[item.Key]); + } + + + if (tagCollectionFieldIndex > -1) + { + _osmUtility.insertOSMTags(tagCollectionFieldIndex, row, tagsToInsert); + } + + tagGdbStorageValues.Clear(); + tagGdbStorageValues = null; + } + + private string GetLocationString(IGPValue gpValue, ITable table) + { + string locationString = String.Empty; + + { + if (((IDataset)table).Workspace.PathName.ToUpper().Contains(".GDS\\")) + { + string partialString = gpValue.GetAsText().Substring(0, gpValue.GetAsText().ToUpper().IndexOf(".GDS\\") + 4); + + string secondString = gpValue.GetAsText().Substring(0, gpValue.GetAsText().LastIndexOf("\\")); + + locationString = secondString + System.IO.Path.DirectorySeparatorChar + ((IDataset)table).BrowseName; + } + else + { + locationString = ((IDataset)table).Workspace.PathName + System.IO.Path.DirectorySeparatorChar + ((IDataset)table).BrowseName; + } + } + + return locationString; + } + + private string GetLocationString(IGPValue gpValue, IFeatureClass featureClass) + { + string locationString = String.Empty; + + if (featureClass.FeatureDataset != null) + { + if (featureClass.FeatureDataset.Workspace.PathName.ToUpper().Contains(".GDS\\")) + { + locationString = gpValue.GetAsText() + System.IO.Path.DirectorySeparatorChar + ((IDataset)featureClass).BrowseName; + } + else + locationString = featureClass.FeatureDataset.Workspace.PathName + System.IO.Path.DirectorySeparatorChar + featureClass.FeatureDataset.BrowseName + System.IO.Path.DirectorySeparatorChar + ((IDataset)featureClass).BrowseName; + } + else + { + locationString = ((IDataset)featureClass).Workspace.PathName + System.IO.Path.DirectorySeparatorChar + ((IDataset)featureClass).BrowseName; + } + + return locationString; + } + + private IWorkspaceFactory guessWorkspaceFactory(string workspacePath) + { + IWorkspaceFactory workspaceFactory = null; + + if (!String.IsNullOrEmpty(workspacePath)) + { + if (workspacePath.ToLower().Contains(".gdb")) + workspaceFactory = new FileGDBWorkspaceFactoryClass(); + else if (workspacePath.ToLower().Contains(".sde")) + workspaceFactory = new SdeWorkspaceFactoryClass(); + else if (workspacePath.ToLower().Contains(".gds")) + workspaceFactory = new SqlWorkspaceFactoryClass(); + } + + return workspaceFactory; + } + + private bool CheckIfExists(ITable searchTable, string osmID) + { + bool featureAlreadyExists = true; + + try + { + string sqlIdentifier = searchTable.SqlIdentifier(osmID); + using (ComReleaser comReleaser = new ComReleaser()) + { + + IQueryFilter queryFilter = new QueryFilterClass(); + queryFilter.WhereClause = sqlIdentifier + " = '" + osmID + "'"; + + ICursor rowCursor = searchTable.Search(queryFilter, false); + comReleaser.ManageLifetime(rowCursor); + + IRow foundRow = rowCursor.NextRow(); + + if (foundRow == null) + { + featureAlreadyExists = false; + } + + Marshal.ReleaseComObject(foundRow); + } + } + catch { } + + return featureAlreadyExists; + + } + + internal List loadOSMWays(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message, IGPValue targetGPValue, IFeatureClass osmPointFeatureClass, IFeatureClass osmLineFeatureClass, IFeatureClass osmPolygonFeatureClass, bool conserveMemory, bool fastLoad, int wayCapacity, ref Dictionary osmNodeDictionary, IFeatureWorkspace featureWorkspace, ISpatialReference downloadSpatialReference, OSMDomains availableDomains, bool checkForExisting) + { + if (osmLineFeatureClass == null) + { + throw new ArgumentNullException("osmLineFeatureClass"); + } + + if (osmPolygonFeatureClass == null) + { + throw new ArgumentNullException("osmPolygonFeatureClass"); + } + + XmlReader osmFileXmlReader = null; + XmlSerializer waySerializer = null; + List missingWays = null; + + try + { + missingWays = new List(); + + int osmPointIDFieldIndex = osmPointFeatureClass.FindField("OSMID"); + int osmWayRefCountFieldIndex = osmPointFeatureClass.FindField("wayRefCount"); + + int osmLineIDFieldIndex = osmLineFeatureClass.FindField("OSMID"); + Dictionary osmLineDomainAttributeFieldIndices = new Dictionary(); + Dictionary osmLineDomainAttributeFieldLength = new Dictionary(); + foreach (var domains in availableDomains.domain) + { + int currentFieldIndex = osmLineFeatureClass.FindField(domains.name); + + if (currentFieldIndex != -1) + { + osmLineDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex); + osmLineDomainAttributeFieldLength.Add(domains.name, osmLineFeatureClass.Fields.get_Field(currentFieldIndex).Length); + } + } + int tagCollectionPolylineFieldIndex = osmLineFeatureClass.FindField("osmTags"); + int osmUserPolylineFieldIndex = osmLineFeatureClass.FindField("osmuser"); + int osmUIDPolylineFieldIndex = osmLineFeatureClass.FindField("osmuid"); + int osmVisiblePolylineFieldIndex = osmLineFeatureClass.FindField("osmvisible"); + int osmVersionPolylineFieldIndex = osmLineFeatureClass.FindField("osmversion"); + int osmChangesetPolylineFieldIndex = osmLineFeatureClass.FindField("osmchangeset"); + int osmTimeStampPolylineFieldIndex = osmLineFeatureClass.FindField("osmtimestamp"); + int osmMemberOfPolylineFieldIndex = osmLineFeatureClass.FindField("osmMemberOf"); + int osmMembersPolylineFieldIndex = osmLineFeatureClass.FindField("osmMembers"); + int osmSupportingElementPolylineFieldIndex = osmLineFeatureClass.FindField("osmSupportingElement"); + + + int osmPolygonIDFieldIndex = osmPolygonFeatureClass.FindField("OSMID"); + Dictionary osmPolygonDomainAttributeFieldIndices = new Dictionary(); + Dictionary osmPolygonDomainAttributeFieldLength = new Dictionary(); + foreach (var domains in availableDomains.domain) + { + int currentFieldIndex = osmPolygonFeatureClass.FindField(domains.name); + + if (currentFieldIndex != -1) + { + osmPolygonDomainAttributeFieldIndices.Add(domains.name, currentFieldIndex); + osmPolygonDomainAttributeFieldLength.Add(domains.name, osmPolygonFeatureClass.Fields.get_Field(currentFieldIndex).Length); + } + } + int tagCollectionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmTags"); + int osmUserPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmuser"); + int osmUIDPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmuid"); + int osmVisiblePolygonFieldIndex = osmPolygonFeatureClass.FindField("osmvisible"); + int osmVersionPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmversion"); + int osmChangesetPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmchangeset"); + int osmTimeStampPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmtimestamp"); + int osmMemberOfPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmMemberOf"); + int osmMembersPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmMembers"); + int osmSupportingElementPolygonFieldIndex = osmPolygonFeatureClass.FindField("osmSupportingElement"); + + ISpatialReferenceFactory spatialRef = new SpatialReferenceEnvironmentClass(); + ISpatialReference wgs84 = spatialRef.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_WGS1984); + + bool shouldProject = !((IClone)wgs84).IsEqual((IClone)downloadSpatialReference); + + // set up the progress indicator + IStepProgressor stepProgressor = TrackCancel as IStepProgressor; + + if (stepProgressor != null) + { + stepProgressor.MinRange = 0; + stepProgressor.MaxRange = wayCapacity; + stepProgressor.Position = 0; + stepProgressor.Message = _resourceManager.GetString("GPTools_OSMGPFileReader_loadingWays"); + stepProgressor.StepValue = 1; + stepProgressor.Show(); + } + + bool lineIndexRebuildRequired = false; + bool polygonIndexRebuildRequired = false; + + int wayCount = 0; + object missingValue = System.Reflection.Missing.Value; + + // enterprise GDB indicator -- supporting load only mode + IFeatureClassLoad lineFeatureLoad = null; + IFeatureClassLoad polygonFeatureLoad = null; + + using (SchemaLockManager lineLock = new SchemaLockManager(osmLineFeatureClass as ITable), polygonLock = new SchemaLockManager(osmPolygonFeatureClass as ITable)) + { + using (ComReleaser comReleaser = new ComReleaser()) + { + IFeatureBuffer featureLineBuffer = null; + IFeatureCursor insertLineCursor = osmLineFeatureClass.Insert(true); + comReleaser.ManageLifetime(insertLineCursor); + + IFeatureBuffer featurePolygonBuffer = null; + IFeatureCursor insertPolygonCursor = osmPolygonFeatureClass.Insert(true); + comReleaser.ManageLifetime(insertPolygonCursor); + + //if (((IWorkspace)featureWorkspace).WorkspaceFactory.WorkspaceType == esriWorkspaceType.esriRemoteDatabaseWorkspace) + //{ + lineFeatureLoad = osmLineFeatureClass as IFeatureClassLoad; + polygonFeatureLoad = osmPolygonFeatureClass as IFeatureClassLoad; + //} + + if (lineFeatureLoad != null) + { + lineFeatureLoad.LoadOnlyMode = true; + } + + if (polygonFeatureLoad != null) + { + polygonFeatureLoad.LoadOnlyMode = true; + } + + ISpatialReference nativeLineSpatialReference = ((IGeoDataset)osmLineFeatureClass).SpatialReference; + ISpatialReference nativePolygonSpatialReference = ((IGeoDataset)osmPolygonFeatureClass).SpatialReference; + + IQueryFilter osmIDQueryFilter = new QueryFilterClass(); + string sqlPointOSMID = osmPointFeatureClass.SqlIdentifier("OSMID"); + IFeatureCursor updatePointCursor = null; + + osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation); + waySerializer = new XmlSerializer(typeof(way)); + + // the point query filter for updates will not changes, so let's do that ahead of time + try + { + osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name; + } + catch + { } + + osmFileXmlReader.MoveToContent(); + while (osmFileXmlReader.Read()) + { + if (osmFileXmlReader.IsStartElement()) + { + if (osmFileXmlReader.Name == "way") + { + string currentwayString = osmFileXmlReader.ReadOuterXml(); + + // assuming the way to be a polyline is sort of a safe assumption + // and won't cause any topology problem due to orientation and closeness + bool wayIsLine = true; + bool wayIsComplete = true; + + way currentWay = null; + + try + { + using (StringReader wayReader = new System.IO.StringReader(currentwayString)) + { + currentWay = waySerializer.Deserialize(wayReader) as way; + } + + // if the deserialization fails then go ahead and read the next xml element + if (currentWay == null) + { + continue; + } + + // and we are expecting at least some nodes on the way itself + if (currentWay.nd == null) + { + continue; + } + + //featureLineBuffer = osmLineFeatureClass.CreateFeatureBuffer(); + //featurePolygonBuffer = osmPolygonFeatureClass.CreateFeatureBuffer(); + + IPointCollection wayPointCollection = null; + wayIsLine = IsThisWayALine(currentWay); + + + if (wayIsLine) + { + + // check if a feature with the same OSMID already exists, because the can only be one + if (checkForExisting == true) + { + if (CheckIfExists(osmLineFeatureClass as ITable, currentWay.id)) + { + continue; + } + } + + IPolyline wayPolyline = new PolylineClass(); + wayPolyline.SpatialReference = downloadSpatialReference; + + IPointIDAware polylineIDAware = wayPolyline as IPointIDAware; + polylineIDAware.PointIDAware = true; + + wayPointCollection = wayPolyline as IPointCollection; + + # region generate line geometry + if (conserveMemory == false) + { + for (int ndIndex = 0; ndIndex < currentWay.nd.Length; ndIndex++) + { + string ndID = currentWay.nd[ndIndex].@ref; + if (osmNodeDictionary.ContainsKey(ndID)) + { + IPoint newPoint = new PointClass(); + newPoint.X = osmNodeDictionary[ndID].Longitude; + newPoint.Y = osmNodeDictionary[ndID].Latitude; + + newPoint.SpatialReference = wgs84; + + if (shouldProject) + { + newPoint.Project(((IGeoDataset)osmLineFeatureClass).SpatialReference); + } + + IPointIDAware idAware = newPoint as IPointIDAware; + idAware.PointIDAware = true; + + newPoint.ID = osmNodeDictionary[ndID].pointObjectID; + + wayPointCollection.AddPoint(newPoint, ref missingValue, ref missingValue); + + osmNodeDictionary[ndID].RefCounter = osmNodeDictionary[ndID].RefCounter + 1; + } + else + { + message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedline_node"), currentWay.id, ndID)); + // set the flag that the way is complete due to a missing node + wayIsComplete = false; + break; + } + } + + } + else + { + for (int pointIndex = 0; pointIndex < currentWay.nd.Length; pointIndex++) + { + wayPointCollection.AddPoint(new PointClass()); + } + + List idRequests = SplitOSMIDRequests(currentWay, 2); + + // build a list of node ids we can use to determine the point index in the line geometry + // as well as a dictionary to determine the position in the list in case of duplicates nodes + Dictionary nodePositionDictionary = new Dictionary(currentWay.nd.Length); + List nodeIDs = new List(currentWay.nd.Length); + + foreach (nd wayNode in currentWay.nd) + { + nodeIDs.Add(wayNode.@ref); + + if (nodePositionDictionary.ContainsKey(wayNode.@ref) == false) + { + nodePositionDictionary.Add(wayNode.@ref, 0); + } + } + + try + { + osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name; + } + catch + { } + + + foreach (string request in idRequests) + { + string idCompareString = request; + osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + request; + using (ComReleaser innerComReleaser = new ComReleaser()) + { + updatePointCursor = osmPointFeatureClass.Update(osmIDQueryFilter, true); + innerComReleaser.ManageLifetime(updatePointCursor); + + IFeature nodeFeature = updatePointCursor.NextFeature(); + + while (nodeFeature != null) + { + // determine the index of the point in with respect to the node position + string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex)); + + // remove the ID from the request string + idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty); + + int nodePositionIndex = -1; + + while ((nodePositionIndex = nodeIDs.IndexOf(nodeOSMIDString, nodePositionDictionary[nodeOSMIDString])) != -1) + { + //// update the new position start search index + nodePositionDictionary[nodeOSMIDString] = nodePositionIndex + 1; + + IPoint nodePoint = (IPoint)nodeFeature.ShapeCopy; + nodePoint.ID = nodeFeature.OID; + wayPointCollection.UpdatePoint(nodePositionIndex, nodePoint); + + // increase the reference counter + if (osmWayRefCountFieldIndex != -1) + { + nodeFeature.set_Value(osmWayRefCountFieldIndex, ((int)nodeFeature.get_Value(osmWayRefCountFieldIndex)) + 1); + + updatePointCursor.UpdateFeature(nodeFeature); + } + } + + if (nodeFeature != null) + Marshal.ReleaseComObject(nodeFeature); + + nodeFeature = updatePointCursor.NextFeature(); + } + + idCompareString = CleanReportedIDs(idCompareString); + + // after removing the commas we should be left with only paranthesis left, meaning a string of length 2 + // if we have more then we have found a missing node, resulting in an incomplete way geometry + if (idCompareString.Length > 2) + { + message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedline_node"), currentWay.id, idCompareString)); + wayIsComplete = false; + } + } + } + } + #endregion + + if (wayIsComplete == false) + { + // if the way geometry is incomplete due to a missing node let's continue to the next way element + missingWays.Add(currentWay.id); + continue; + } + + featureLineBuffer = osmLineFeatureClass.CreateFeatureBuffer(); + + featureLineBuffer.Shape = wayPolyline; + featureLineBuffer.set_Value(osmLineIDFieldIndex, currentWay.id); + } + else + { + // check if a feature with the same OSMID already exists, because the can only be one + if (checkForExisting == true) + { + if (CheckIfExists(osmPolygonFeatureClass as ITable, currentWay.id)) + { + continue; + } + } + + + IPolygon wayPolygon = new PolygonClass(); + wayPolygon.SpatialReference = downloadSpatialReference; + + IPointIDAware polygonIDAware = wayPolygon as IPointIDAware; + polygonIDAware.PointIDAware = true; + + wayPointCollection = wayPolygon as IPointCollection; + + #region generate polygon geometry + if (conserveMemory == false) + { + for (int ndIndex = 0; ndIndex < currentWay.nd.Length; ndIndex++) + { + string ndID = currentWay.nd[ndIndex].@ref; + if (osmNodeDictionary.ContainsKey(ndID)) + { + IPoint newPoint = new PointClass(); + newPoint.X = osmNodeDictionary[ndID].Longitude; + newPoint.Y = osmNodeDictionary[ndID].Latitude; + newPoint.SpatialReference = wgs84; + + if (shouldProject) + { + newPoint.Project(nativePolygonSpatialReference); + } + + IPointIDAware idAware = newPoint as IPointIDAware; + idAware.PointIDAware = true; + + newPoint.ID = osmNodeDictionary[ndID].pointObjectID; + + wayPointCollection.AddPoint(newPoint, ref missingValue, ref missingValue); + } + else + { + message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedpolygon_node"), currentWay.id, ndID)); + wayIsComplete = false; + break; + } + } + } + else + { + for (int pointIndex = 0; pointIndex < currentWay.nd.Length; pointIndex++) + { + wayPointCollection.AddPoint(new PointClass()); + } + + List idRequests = SplitOSMIDRequests(currentWay, 2); + + // build a list of node ids we can use to determine the point index in the line geometry + // as well as a dictionary to determine the position in the list in case of duplicates nodes + Dictionary nodePositionDictionary = new Dictionary(currentWay.nd.Length); + List nodeIDs = new List(currentWay.nd.Length); + + foreach (nd wayNode in currentWay.nd) + { + nodeIDs.Add(wayNode.@ref); + + if (nodePositionDictionary.ContainsKey(wayNode.@ref) == false) + { + nodePositionDictionary.Add(wayNode.@ref, 0); + } + } + + try + { + osmIDQueryFilter.SubFields = osmPointFeatureClass.ShapeFieldName + "," + osmPointFeatureClass.Fields.get_Field(osmPointIDFieldIndex).Name + "," + osmPointFeatureClass.Fields.get_Field(osmWayRefCountFieldIndex).Name + "," + osmPointFeatureClass.OIDFieldName; + } + catch + { } + + + foreach (string osmIDRequest in idRequests) + { + string idCompareString = osmIDRequest; + + using (ComReleaser innercomReleaser = new ComReleaser()) + { + osmIDQueryFilter.WhereClause = sqlPointOSMID + " IN " + osmIDRequest; + updatePointCursor = osmPointFeatureClass.Update(osmIDQueryFilter, false); + innercomReleaser.ManageLifetime(updatePointCursor); + + IFeature nodeFeature = updatePointCursor.NextFeature(); + + while (nodeFeature != null) + { + // determine the index of the point in with respect to the node position + string nodeOSMIDString = Convert.ToString(nodeFeature.get_Value(osmPointIDFieldIndex)); + + idCompareString = idCompareString.Replace(nodeOSMIDString, String.Empty); + + int nodePositionIndex = nodeIDs.IndexOf(nodeOSMIDString, nodePositionDictionary[nodeOSMIDString]); + + while (nodePositionIndex > -1) + { + // update the new position start search index + nodePositionDictionary[nodeOSMIDString] = nodePositionIndex + 1; + + IPoint nodePoint = (IPoint)nodeFeature.ShapeCopy; + nodePoint.ID = nodeFeature.OID; + wayPointCollection.UpdatePoint(nodePositionIndex, nodePoint); + + // increase the reference counter + if (osmWayRefCountFieldIndex != -1) + { + nodeFeature.set_Value(osmWayRefCountFieldIndex, ((int)nodeFeature.get_Value(osmWayRefCountFieldIndex)) + 1); + + updatePointCursor.UpdateFeature(nodeFeature); + } + + nodePositionIndex = nodeIDs.IndexOf(nodeOSMIDString, nodePositionDictionary[nodeOSMIDString]); + } + + if (nodeFeature != null) + Marshal.ReleaseComObject(nodeFeature); + + nodeFeature = updatePointCursor.NextFeature(); + } + + idCompareString = CleanReportedIDs(idCompareString); + + if (idCompareString.Length > 2) + { + message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_undeterminedpolygon_node"), currentWay.id, idCompareString)); + wayIsComplete = false; + } + } + } + } + #endregion + + if (wayIsComplete == false) + { + missingWays.Add(currentWay.id); + continue; // continue to read the next way + } + + featurePolygonBuffer = osmPolygonFeatureClass.CreateFeatureBuffer(); + + ((IPolygon)wayPointCollection).Close(); + ((IPolygon)wayPointCollection).SimplifyPreserveFromTo(); + + featurePolygonBuffer.Shape = (IPolygon)wayPointCollection; + featurePolygonBuffer.set_Value(osmPolygonIDFieldIndex, currentWay.id); + } + + + if (wayIsLine) + { + insertTags(osmLineDomainAttributeFieldIndices, osmLineDomainAttributeFieldLength, tagCollectionPolylineFieldIndex, featureLineBuffer, currentWay.tag); + } + else + { + insertTags(osmPolygonDomainAttributeFieldIndices, osmPolygonDomainAttributeFieldLength, tagCollectionPolygonFieldIndex, featurePolygonBuffer, currentWay.tag); + } + + // store the administrative attributes + // user, uid, version, changeset, timestamp, visible + if (fastLoad == false) + { + if (!String.IsNullOrEmpty(currentWay.user)) + { + if (wayIsLine) + { + if (osmUserPolylineFieldIndex != -1) + { + featureLineBuffer.set_Value(osmUserPolylineFieldIndex, currentWay.user); + } + } + else + { + if (osmUserPolygonFieldIndex != -1) + { + featurePolygonBuffer.set_Value(osmUserPolygonFieldIndex, currentWay.user); + } + } + } + + if (!String.IsNullOrEmpty(currentWay.uid)) + { + if (wayIsLine) + { + if (osmUIDPolylineFieldIndex != -1) + { + featureLineBuffer.set_Value(osmUIDPolylineFieldIndex, Convert.ToInt32(currentWay.uid)); + } + } + else + { + if (osmUIDPolygonFieldIndex != -1) + { + featurePolygonBuffer.set_Value(osmUIDPolygonFieldIndex, Convert.ToInt32(currentWay.uid)); + } + } + } + + if (wayIsLine) + { + if (osmVisiblePolylineFieldIndex != -1) + { + featureLineBuffer.set_Value(osmVisiblePolylineFieldIndex, currentWay.visible.ToString()); + } + } + else + { + if (osmVisiblePolygonFieldIndex != -1) + { + featurePolygonBuffer.set_Value(osmVisiblePolygonFieldIndex, currentWay.visible.ToString()); + } + } + + if (!String.IsNullOrEmpty(currentWay.version)) + { + if (wayIsLine) + { + if (osmVersionPolylineFieldIndex != -1) + { + featureLineBuffer.set_Value(osmVersionPolylineFieldIndex, Convert.ToInt32(currentWay.version)); + } + } + else + { + if (osmVersionPolygonFieldIndex != -1) + { + featurePolygonBuffer.set_Value(osmVersionPolygonFieldIndex, Convert.ToInt32(currentWay.version)); + } + } + } + + if (!String.IsNullOrEmpty(currentWay.changeset)) + { + if (wayIsLine) + { + if (osmChangesetPolylineFieldIndex != -1) + { + featureLineBuffer.set_Value(osmChangesetPolylineFieldIndex, Convert.ToInt32(currentWay.changeset)); + } + } + else + { + if (osmChangesetPolygonFieldIndex != -1) + { + featurePolygonBuffer.set_Value(osmChangesetPolygonFieldIndex, Convert.ToInt32(currentWay.changeset)); + } + } + } + + if (!String.IsNullOrEmpty(currentWay.timestamp)) + { + try + { + if (wayIsLine) + { + if (osmTimeStampPolylineFieldIndex != -1) + { + featureLineBuffer.set_Value(osmTimeStampPolylineFieldIndex, Convert.ToDateTime(currentWay.timestamp)); + } + } + else + { + if (osmTimeStampPolygonFieldIndex != -1) + { + featurePolygonBuffer.set_Value(osmTimeStampPolygonFieldIndex, Convert.ToDateTime(currentWay.timestamp)); + } + } + } + catch (Exception ex) + { + message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_invalidTimeFormat"), ex.Message)); + } + } + + if (wayIsLine) + { + if (osmSupportingElementPolylineFieldIndex > -1) + { + if (_osmUtility.DoesHaveKeys(currentWay)) + { + featureLineBuffer.set_Value(osmSupportingElementPolylineFieldIndex, "no"); + } + else + { + featureLineBuffer.set_Value(osmSupportingElementPolylineFieldIndex, "yes"); + } + } + } + else + { + if (osmSupportingElementPolygonFieldIndex > -1) + { + if (_osmUtility.DoesHaveKeys(currentWay)) + { + featurePolygonBuffer.set_Value(osmSupportingElementPolygonFieldIndex, "no"); + } + else + { + featurePolygonBuffer.set_Value(osmSupportingElementPolygonFieldIndex, "yes"); + } + } + } + } // fast load + + try + { + if (wayIsLine) + { + insertLineCursor.InsertFeature(featureLineBuffer); + lineIndexRebuildRequired = true; + } + else + { + insertPolygonCursor.InsertFeature(featurePolygonBuffer); + polygonIndexRebuildRequired = true; + } + + wayCount = wayCount + 1; + + + if (stepProgressor != null) + { + stepProgressor.Position = wayCount; + } + + + if ((wayCount % 50000) == 0) + { + message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_waysloaded"), wayCount)); + } + + } + catch (Exception ex) + { + message.AddWarning(ex.Message); + message.AddWarning(currentwayString); + } + + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(String.Format("Feature OSMID {0}", currentWay.id)); + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + finally + { + if (featureLineBuffer != null) + { + Marshal.ReleaseComObject(featureLineBuffer); + + if (featureLineBuffer != null) + featureLineBuffer = null; + } + + if (featurePolygonBuffer != null) + { + Marshal.ReleaseComObject(featurePolygonBuffer); + + if (featurePolygonBuffer != null) + featurePolygonBuffer = null; + } + + currentWay = null; + } + + if (TrackCancel.Continue() == false) + { + insertPolygonCursor.Flush(); + if (polygonFeatureLoad != null) + { + polygonFeatureLoad.LoadOnlyMode = false; + } + + insertLineCursor.Flush(); + if (lineFeatureLoad != null) + { + lineFeatureLoad.LoadOnlyMode = false; + } + + return missingWays; + } + } + } + } + + osmFileXmlReader.Close(); + + if (stepProgressor != null) + { + stepProgressor.Hide(); + } + + message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_waysloaded"), wayCount)); + + insertPolygonCursor.Flush(); + if (polygonFeatureLoad != null) + { + polygonFeatureLoad.LoadOnlyMode = false; + } + + insertLineCursor.Flush(); + if (lineFeatureLoad != null) + { + lineFeatureLoad.LoadOnlyMode = false; + } + } + } + + IGeoProcessor2 geoProcessor = new GeoProcessorClass(); + IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); + bool storedOriginal = geoProcessor.AddOutputsToMap; + IVariantArray parameterArrary = null; + IGeoProcessorResult2 gpResults2 = null; + + try + { + geoProcessor.AddOutputsToMap = false; + + if (lineIndexRebuildRequired) + { + IIndexes featureClassIndexes = osmLineFeatureClass.Indexes; + int indexPosition = -1; + featureClassIndexes.FindIndex("osmID_IDX", out indexPosition); + + string fcLocation = GetLocationString(targetGPValue, osmLineFeatureClass); + + if (indexPosition == -1) + { + message.AddMessage(_resourceManager.GetString("GPTools_buildinglineidx")); + + // Addd index for osmid column + parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", ""); + gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2; + } + + if (wayCount > 100) + { + // in this case we are dealing with a file geodatabase + if (lineFeatureLoad == null) + { + UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation); + } + } + } + + if (polygonIndexRebuildRequired) + { + IIndexes featureClassIndexes = osmPolygonFeatureClass.Indexes; + int indexPosition = -1; + featureClassIndexes.FindIndex("osmID_IDX", out indexPosition); + + string fcLocation = GetLocationString(targetGPValue, osmPolygonFeatureClass); + + if (indexPosition == -1) + { + message.AddMessage(_resourceManager.GetString("GPTools_buildingpolygonidx")); + + IGPValue polygonFeatureClassGPValue = gpUtilities3.MakeGPValueFromObject(osmPolygonFeatureClass); + + if (polygonFeatureClassGPValue != null) + { + // Addd index for osmid column + parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", ""); + gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2; + } + } + + if (wayCount > 100) + { + if (polygonFeatureLoad == null) + { + UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation); + } + } + } + } + catch (Exception ex) + { + message.AddWarning(ex.Message); + } + finally + { + geoProcessor.AddOutputsToMap = storedOriginal; + + Marshal.FinalReleaseComObject(gpUtilities3); + Marshal.FinalReleaseComObject(geoProcessor); + } + } + catch (Exception ex) + { + message.AddWarning(ex.Message); + } + finally + { + if (waySerializer != null) + waySerializer = null; + + if (osmFileXmlReader != null) + osmFileXmlReader = null; + + System.GC.Collect(); + System.GC.WaitForPendingFinalizers(); + } + + return missingWays; + } + + /// + /// + /// + /// + /// + /// returns null pointer if no environment with the specified name is found. + public static IGPEnvironment getEnvironment(IGPEnvironmentManager environmentManager, string name) + { + IGPUtilities3 gpUtils = new GPUtilitiesClass(); + IGPEnvironment returnEnv = null; + + try + { + if (environmentManager.GetLocalEnvironments().Count > 0) + returnEnv = gpUtils.GetEnvironment(environmentManager.GetLocalEnvironments(), name); + + if (returnEnv == null) + returnEnv = gpUtils.GetEnvironment(environmentManager.GetEnvironments(), name); + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + + return returnEnv; + } + + private static string CleanReportedIDs(string idCompareString) + { + // if all the requested IDs were returned we should only have brackets and commas left + string save_compareString = idCompareString; + string searchPattern = @"(\b[nrw0-9]\d+)"; + Regex regularExpression = new Regex(searchPattern); + + List missingIDs = new List(); + + foreach (Match match in regularExpression.Matches(save_compareString)) + { + if (String.IsNullOrEmpty(match.Value) == false) + { + missingIDs.Add(match.Value); + } + } + + idCompareString = "(" + string.Join(",", missingIDs.ToArray()) + ")"; + return idCompareString; + } + + internal static string retrieveNodeID(IFeatureClass pointFeatureClass, int osmIDPointFieldIndex, int extensionVersion, IPoint pointGeometry) + { + string nodeID = string.Empty; + + if (pointGeometry == null) + return String.Empty; + + if (pointGeometry.IsEmpty) + return String.Empty; + + if (((IPointIDAware)pointGeometry).PointIDAware == false) + { + return nodeID; + } + if (extensionVersion == 1) + { + nodeID = Convert.ToString(pointGeometry.ID); + } + else if (extensionVersion == 2) + { + IFeature pointFeature = null; + try + { + pointFeature = pointFeatureClass.GetFeature(pointGeometry.ID); + } + catch { } + if (pointFeature != null) + { + if (osmIDPointFieldIndex > -1) + { + nodeID = Convert.ToString(pointFeature.get_Value(osmIDPointFieldIndex)); + } + + Marshal.ReleaseComObject(pointFeature); + } + } + return nodeID; + } + + /// + /// This method counts nodes, ways, and relations. However it does assume a tidy XML file (line formatted). + /// + /// + /// + /// + /// + /// + internal void countOSMStuffFast(string osmFileLocation, ref long nodeCapacity, ref long wayCapacity, ref long relationCapacity, ref ITrackCancel CancelTracker) + { + using (System.IO.FileStream fStream = new System.IO.FileStream(osmFileLocation, FileMode.Open, FileAccess.Read)) + { + using (StreamReader sReader = new StreamReader(fStream)) + { + string line; + while ((line = sReader.ReadLine()) != null) + { + //if (!CancelTracker.Continue()) + // return; + + if (line.Contains("> countOSMCapacityAndTags(string osmFileLocation, ref long nodeCapacity, ref long wayCapacity, ref long relationCapacity, ref ITrackCancel CancelTracker) + { + Dictionary> attributesDictionary = new Dictionary>(); + + try + { + XmlSerializer nodeSerializer = new XmlSerializer(typeof(node)); + XmlSerializer waySerializer = new XmlSerializer(typeof(way)); + XmlSerializer relationSerializer = new XmlSerializer(typeof(relation)); + + List pointTags = new List(); + List lineTags = new List(); + List polygonTags = new List(); + + using (System.Xml.XmlReader osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation)) + { + osmFileXmlReader.MoveToContent(); + + while (osmFileXmlReader.Read()) + { + if (CancelTracker.Continue()) + { + if (osmFileXmlReader.IsStartElement()) + { + string currentNodeName = osmFileXmlReader.Name; + + switch (currentNodeName) + { + case "node": + string currentNodeString = osmFileXmlReader.ReadOuterXml(); + // turn the xml node representation into a node class representation + ESRI.ArcGIS.OSM.OSMClassExtension.node currentNode = null; + using (StringReader nodeReader = new System.IO.StringReader(currentNodeString)) + { + try + { + currentNode = nodeSerializer.Deserialize(nodeReader) as ESRI.ArcGIS.OSM.OSMClassExtension.node; + } + catch { } + } + + if (currentNode != null) + { + if (currentNode.tag != null) + { + foreach (tag currentTag in currentNode.tag) { - if (osmVersionPolygonFieldIndex != -1) + if (!pointTags.Contains(currentTag.k)) { - featurePolygonBuffer.set_Value(osmVersionPolygonFieldIndex, Convert.ToInt32(currentWay.version)); + pointTags.Add(currentTag.k); } } } + } - if (!String.IsNullOrEmpty(currentWay.changeset)) + nodeCapacity++; + break; + case "way": + wayCapacity++; + + string currentWayString = osmFileXmlReader.ReadOuterXml(); + // turn the xml node representation into a node class representation + ESRI.ArcGIS.OSM.OSMClassExtension.way currentWay = null; + using (StringReader wayReader = new System.IO.StringReader(currentWayString)) + { + try { - if (wayIsLine) - { - if (osmChangesetPolylineFieldIndex != -1) - { - featureLineBuffer.set_Value(osmChangesetPolylineFieldIndex, Convert.ToInt32(currentWay.changeset)); - } - } - else - { - if (osmChangesetPolygonFieldIndex != -1) - { - featurePolygonBuffer.set_Value(osmChangesetPolygonFieldIndex, Convert.ToInt32(currentWay.changeset)); - } - } + currentWay = waySerializer.Deserialize(wayReader) as ESRI.ArcGIS.OSM.OSMClassExtension.way; } + catch { } + } - if (!String.IsNullOrEmpty(currentWay.timestamp)) + if (currentWay != null) + { + if (currentWay.tag != null) { - try + foreach (tag currentTag in currentWay.tag) { - if (wayIsLine) + if (OSMToolHelper.IsThisWayALine(currentWay) && !lineTags.Contains(currentTag.k)) { - if (osmTimeStampPolylineFieldIndex != -1) - { - featureLineBuffer.set_Value(osmTimeStampPolylineFieldIndex, Convert.ToDateTime(currentWay.timestamp)); - } + lineTags.Add(currentTag.k); } - else + else if (!polygonTags.Contains(currentTag.k)) { - if (osmTimeStampPolygonFieldIndex != -1) - { - featurePolygonBuffer.set_Value(osmTimeStampPolygonFieldIndex, Convert.ToDateTime(currentWay.timestamp)); - } + polygonTags.Add(currentTag.k); } } - catch (Exception ex) - { - message.AddWarning(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_invalidTimeFormat"), ex.Message)); - } } + } - if (wayIsLine) + break; + case "relation": + relationCapacity++; + + // for relation let's NOT do an exhaustive determine if we have a polygon or maybe a multipart polyline + // or maybe a super relation + string currentRelationString = osmFileXmlReader.ReadOuterXml(); + + ESRI.ArcGIS.OSM.OSMClassExtension.relation currentRelation = null; + using (StringReader relationReader = new System.IO.StringReader(currentRelationString)) + { + try { - if (osmSupportingElementPolylineFieldIndex > -1) - { - if (_osmUtility.DoesHaveKeys(currentWay)) - { - featureLineBuffer.set_Value(osmSupportingElementPolylineFieldIndex, "no"); - } - else - { - featureLineBuffer.set_Value(osmSupportingElementPolylineFieldIndex, "yes"); - } - } + currentRelation = relationSerializer.Deserialize(relationReader) as ESRI.ArcGIS.OSM.OSMClassExtension.relation; } - else + catch { } + } + + if (currentRelation != null) + { + if (currentRelation.Items != null) { - if (osmSupportingElementPolygonFieldIndex > -1) + bool polygonTagDetected = false; + + foreach (var item in currentRelation.Items) { - if (_osmUtility.DoesHaveKeys(currentWay)) - { - featurePolygonBuffer.set_Value(osmSupportingElementPolygonFieldIndex, "no"); - } - else + if (item is ESRI.ArcGIS.OSM.OSMClassExtension.tag) { - featurePolygonBuffer.set_Value(osmSupportingElementPolygonFieldIndex, "yes"); + ESRI.ArcGIS.OSM.OSMClassExtension.tag currentTag = item as ESRI.ArcGIS.OSM.OSMClassExtension.tag; + + if (polygonTagDetected) + { + if (!polygonTags.Contains(currentTag.k)) + { + polygonTags.Add(currentTag.k); + } + } + else if (currentTag.k.ToUpper().Equals("TYPE")) + { + if ((currentTag.v.ToUpper().Equals("POLYGON") || currentTag.v.ToUpper().Equals("MULTIPOLYGON"))) + { + polygonTagDetected = true; + } + } } } } - } // fast load + } + break; + } + } + } + } - try - { - if (wayIsLine) - { - insertLineCursor.InsertFeature(featureLineBuffer); - lineIndexRebuildRequired = true; - } - else - { - insertPolygonCursor.InsertFeature(featurePolygonBuffer); - polygonIndexRebuildRequired = true; - } + osmFileXmlReader.Close(); + } - wayCount = wayCount + 1; + attributesDictionary.Add(esriGeometryType.esriGeometryPoint, pointTags); + attributesDictionary.Add(esriGeometryType.esriGeometryPolyline, lineTags); + attributesDictionary.Add(esriGeometryType.esriGeometryPolygon, polygonTags); + } + catch { } - if (stepProgressor != null) - { - stepProgressor.Position = wayCount; - } + return attributesDictionary; + } + internal void loadOSMRelations(List osmRelationFileNames, string sourceLineFCName, string sourcePolygonFCName, List relationGDBNames, List lineFieldNames, List polygonFieldNames, ref ITrackCancel TrackCancel, ref IGPMessages toolMessages) + { + // create the point feature classes in the temporary loading fgdbs + OSMToolHelper toolHelper = new OSMToolHelper(); + IGeoProcessor2 geoProcessor = new GeoProcessorClass() as IGeoProcessor2; + geoProcessor.AddOutputsToMap = false; + IGeoProcessorResult gpResults = null; - if ((wayCount % 50000) == 0) - { - message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_waysloaded"), wayCount)); - } + Stopwatch executionStopwatch = System.Diagnostics.Stopwatch.StartNew(); + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_loading_relations"))); - } - catch (Exception ex) - { - message.AddWarning(ex.Message); - message.AddWarning(currentwayString); - } + string loadSuperRelationParameterValue = "DO_NOT_LOAD_SUPER_RELATION"; - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(ex.Message); - System.Diagnostics.Debug.WriteLine(ex.StackTrace); - } - finally - { - if (featureLineBuffer != null) - { - Marshal.ReleaseComObject(featureLineBuffer); + // take the name of the temp line and polygon featureclass from the source names + string[] sourceLineNameElements = sourceLineFCName.Split(System.IO.Path.DirectorySeparatorChar); + string lineFeatureClassName = sourceLineNameElements[sourceLineNameElements.Length - 1]; + string[] sourcePolygonNameElements = sourcePolygonFCName.Split(System.IO.Path.DirectorySeparatorChar); + string polygonFeatureClassName = sourcePolygonNameElements[sourcePolygonNameElements.Length - 1]; - if (featureLineBuffer != null) - featureLineBuffer = null; - } + // in the case of a single thread we can use the parent process directly to convert the osm to the target featureclass + if (osmRelationFileNames.Count == 1) + { + IGPFunction relationLoader = new OSMGPRelationLoader() as IGPFunction; + + IGPUtilities gpUtilities = new GPUtilitiesClass(); + IArray parameterValues = new ArrayClass(); + parameterValues.Add(gpUtilities.CreateParameterValue(osmRelationFileNames[0], new DEFileTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(loadSuperRelationParameterValue, new GPBooleanTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(sourceLineFCName, new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(sourcePolygonFCName, new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(String.Join(";", lineFieldNames.ToArray()), new GPMultiValueTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue(String.Join(";", polygonFieldNames.ToArray()), new GPMultiValueTypeClass(), esriGPParameterDirection.esriGPParameterDirectionInput)); + parameterValues.Add(gpUtilities.CreateParameterValue( + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { relationGDBNames[0], lineFeatureClassName }), + new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionOutput)); + parameterValues.Add(gpUtilities.CreateParameterValue( + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { relationGDBNames[0], polygonFeatureClassName }), + new DEFeatureClassTypeClass(), esriGPParameterDirection.esriGPParameterDirectionOutput)); + relationLoader.Execute(parameterValues, TrackCancel, null, toolMessages); + + ComReleaser.ReleaseCOMObject(gpUtilities); + + executionStopwatch.Stop(); + TimeSpan relationLoadingTimeSpan = executionStopwatch.Elapsed; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_doneloading_relations"), relationLoadingTimeSpan.Hours, relationLoadingTimeSpan.Minutes, relationLoadingTimeSpan.Seconds)); + } + else + { + #region load relation containing only ways + using (ComReleaser comReleaser = new ComReleaser()) + { + IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactoryClass(); + comReleaser.ManageLifetime(workspaceFactory); - if (featurePolygonBuffer != null) - { - Marshal.ReleaseComObject(featurePolygonBuffer); + for (int gdbIndex = 0; gdbIndex < relationGDBNames.Count; gdbIndex++) + { + FileInfo gdbFileInfo = new FileInfo(relationGDBNames[gdbIndex]); + IWorkspaceName workspaceName = workspaceFactory.Create(gdbFileInfo.DirectoryName, gdbFileInfo.Name, new PropertySetClass(), 0); + comReleaser.ManageLifetime(workspaceName); + } + } - if (featurePolygonBuffer != null) - featurePolygonBuffer = null; - } + _manualResetEvent = new ManualResetEvent(false); + _numberOfThreads = osmRelationFileNames.Count; + + + for (int i = 0; i < osmRelationFileNames.Count; i++) + { + Thread t = new Thread(new ParameterizedThreadStart(PythonLoadOSMRelations)); + t.Start(new List() { + osmRelationFileNames[i], + loadSuperRelationParameterValue, + sourceLineFCName, + sourcePolygonFCName, + String.Join(";", lineFieldNames.ToArray()), + String.Join(";", polygonFieldNames.ToArray()), + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { relationGDBNames[i], lineFeatureClassName }), + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { relationGDBNames[i], polygonFeatureClassName }), + }); + } + + // wait for all nodes to complete loading before appending all into the target feature class + _manualResetEvent.WaitOne(); + _manualResetEvent.Close(); + + + executionStopwatch.Stop(); + TimeSpan relationLoadingTimeSpan = executionStopwatch.Elapsed; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_doneloading_relations"), relationLoadingTimeSpan.Hours, relationLoadingTimeSpan.Minutes, relationLoadingTimeSpan.Seconds)); + + List linesFCNamesArray = new List(relationGDBNames.Count); + List polygonFCNamesArray = new List(relationGDBNames.Count); + + // append all lines into the target feature class + foreach (string fileGDB in relationGDBNames) + { + linesFCNamesArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { fileGDB, lineFeatureClassName })); + polygonFCNamesArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { fileGDB, polygonFeatureClassName })); + } + + // append all the lines + IVariantArray parameterArray = new VarArrayClass(); + parameterArray.Add(String.Join(";", linesFCNamesArray.ToArray())); + parameterArray.Add(sourceLineFCName); + + gpResults = geoProcessor.Execute("Append_management", parameterArray, TrackCancel); + + IGPMessages messages = gpResults.GetResultMessages(); + toolMessages.AddMessages(gpResults.GetResultMessages()); + +#if DEBUG + for (int i = 0; i < messages.Count; i++) + { + System.Diagnostics.Debug.WriteLine(messages.GetMessage(i).Description); + } +#endif + + // append all the polygons + parameterArray = new VarArrayClass(); + parameterArray.Add(String.Join(";", polygonFCNamesArray.ToArray())); + parameterArray.Add(sourcePolygonFCName); + + gpResults = geoProcessor.Execute("Append_management", parameterArray, TrackCancel); + + messages = gpResults.GetResultMessages(); + toolMessages.AddMessages(gpResults.GetResultMessages()); + +#if DEBUG + for (int i = 0; i < messages.Count; i++) + { + System.Diagnostics.Debug.WriteLine(messages.GetMessage(i).Description); + } +#endif + + // delete the temp loading fgdbs + for (int gdbIndex = 0; gdbIndex < relationGDBNames.Count; gdbIndex++) + { + parameterArray = new VarArrayClass(); + parameterArray.Add(relationGDBNames[gdbIndex]); + geoProcessor.Execute("Delete_management", parameterArray, new CancelTrackerClass()); + } + #endregion + + #region load super-relations + + using (ComReleaser comReleaser = new ComReleaser()) + { + IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactoryClass(); + comReleaser.ManageLifetime(workspaceFactory); + + for (int gdbIndex = 0; gdbIndex < relationGDBNames.Count; gdbIndex++) + { + FileInfo gdbFileInfo = new FileInfo(relationGDBNames[gdbIndex]); + IWorkspaceName workspaceName = workspaceFactory.Create(gdbFileInfo.DirectoryName, gdbFileInfo.Name, new PropertySetClass(), 0); + comReleaser.ManageLifetime(workspaceName); + } + } + + + loadSuperRelationParameterValue = "LOAD_SUPER_RELATION"; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_loading_super_relations"))); + executionStopwatch.Reset(); + executionStopwatch.Start(); + + _manualResetEvent = new ManualResetEvent(false); + _numberOfThreads = osmRelationFileNames.Count; + + + for (int i = 0; i < osmRelationFileNames.Count; i++) + { + Thread t = new Thread(new ParameterizedThreadStart(PythonLoadOSMRelations)); + t.Start(new List() { + osmRelationFileNames[i], + loadSuperRelationParameterValue, + sourceLineFCName, + sourcePolygonFCName, + String.Join(";", lineFieldNames.ToArray()), + String.Join(";", polygonFieldNames.ToArray()), + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { relationGDBNames[i], lineFeatureClassName }), + String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { relationGDBNames[i], polygonFeatureClassName }), + }); + } + + // wait for all nodes to complete loading before appending all into the target feature class + _manualResetEvent.WaitOne(); + _manualResetEvent.Close(); + + + executionStopwatch.Stop(); + relationLoadingTimeSpan = executionStopwatch.Elapsed; + toolMessages.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPMultiLoader_doneloading_super_relations"), relationLoadingTimeSpan.Hours, relationLoadingTimeSpan.Minutes, relationLoadingTimeSpan.Seconds)); + + linesFCNamesArray = new List(relationGDBNames.Count); + polygonFCNamesArray = new List(relationGDBNames.Count); + + // append all lines into the target feature class + foreach (string fileGDB in relationGDBNames) + { + linesFCNamesArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { fileGDB, lineFeatureClassName })); + polygonFCNamesArray.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[] { fileGDB, polygonFeatureClassName })); + } + + // append all the lines + parameterArray = new VarArrayClass(); + parameterArray.Add(String.Join(";", linesFCNamesArray.ToArray())); + parameterArray.Add(sourceLineFCName); + + gpResults = geoProcessor.Execute("Append_management", parameterArray, TrackCancel); + + messages = gpResults.GetResultMessages(); + toolMessages.AddMessages(gpResults.GetResultMessages()); + +#if DEBUG + for (int i = 0; i < messages.Count; i++) + { + System.Diagnostics.Debug.WriteLine(messages.GetMessage(i).Description); + } +#endif + + // append all the polygons + parameterArray = new VarArrayClass(); + parameterArray.Add(String.Join(";", polygonFCNamesArray.ToArray())); + parameterArray.Add(sourcePolygonFCName); + + gpResults = geoProcessor.Execute("Append_management", parameterArray, TrackCancel); + + messages = gpResults.GetResultMessages(); + toolMessages.AddMessages(gpResults.GetResultMessages()); + +#if DEBUG + for (int i = 0; i < messages.Count; i++) + { + System.Diagnostics.Debug.WriteLine(messages.GetMessage(i).Description); + } +#endif + + // delete the temp loading fgdbs + for (int gdbIndex = 0; gdbIndex < relationGDBNames.Count; gdbIndex++) + { + parameterArray = new VarArrayClass(); + parameterArray.Add(relationGDBNames[gdbIndex]); + geoProcessor.Execute("Delete_management", parameterArray, new CancelTrackerClass()); + } + + #endregion + + // delete the temp loading relation osm files + foreach (string osmFile in osmRelationFileNames) + { + try + { + System.IO.File.Delete(osmFile); + } + catch { } + } - currentWay = null; - } - if (TrackCancel.Continue() == false) - { - insertPolygonCursor.Flush(); - if (polygonFeatureLoad != null) - { - polygonFeatureLoad.LoadOnlyMode = false; - } + } + } - insertLineCursor.Flush(); - if (lineFeatureLoad != null) - { - lineFeatureLoad.LoadOnlyMode = false; - } + internal void smallLoadOSMRelations(string osmFileLocation, string sourceLineFeatureClassLocation, string sourcePolygonFeatureClassLocation, string targetLineFeatureClassLocation, string targetPolygonFeatureClassLocation, List lineFieldNames, List polygonFieldNames, bool includeSuperRelations) + { + using (ComReleaser comReleaser = new ComReleaser()) + { + List tags = null; - return missingWays; - } - } - } - } + IGPUtilities3 gpUtilities = new GPUtilitiesClass() as IGPUtilities3; + comReleaser.ManageLifetime(gpUtilities); + XmlReader relationFileXmlReader = null; - osmFileXmlReader.Close(); + try + { + // info about the source lines + IFeatureClass sourceLineFeatureClass = gpUtilities.OpenFeatureClassFromString(sourceLineFeatureClassLocation); + comReleaser.ManageLifetime(sourceLineFeatureClass); + int osmSourceLineIDFieldIndex = sourceLineFeatureClass.FindField("OSMID"); + string sourceSQLLineOSMID = sourceLineFeatureClass.SqlIdentifier("OSMID"); + + // info about the source polygons + IFeatureClass sourcePolygonFeatureClass = gpUtilities.OpenFeatureClassFromString(sourcePolygonFeatureClassLocation); + comReleaser.ManageLifetime(sourcePolygonFeatureClass); + int osmSourcePolygonIDFieldIndex = sourcePolygonFeatureClass.FindField("OSMID"); + string sourceSQLPolygonOSMID = sourcePolygonFeatureClass.SqlIdentifier("OSMID"); + + // info about the target lines + IFeatureClass targetLineFeatureClass = gpUtilities.OpenFeatureClassFromString(targetLineFeatureClassLocation); + comReleaser.ManageLifetime(targetLineFeatureClass); + int osmTargetLineIDFieldIndex = targetLineFeatureClass.FindField("OSMID"); + int osmTargetLineTagCollectionFieldIndex = targetLineFeatureClass.FindField("osmTags"); + string targetSQLLineOSMID = targetLineFeatureClass.SqlIdentifier("OSMID"); + + Dictionary mainLineAttributeFieldIndices = new Dictionary(); + foreach (string fieldName in lineFieldNames) + { + int currentFieldIndex = targetLineFeatureClass.FindField(OSMToolHelper.convert2AttributeFieldName(fieldName, null)); - if (stepProgressor != null) + if (currentFieldIndex != -1) { - stepProgressor.Hide(); + mainLineAttributeFieldIndices.Add(OSMToolHelper.convert2AttributeFieldName(fieldName, null), currentFieldIndex); } + } - message.AddMessage(String.Format(_resourceManager.GetString("GPTools_OSMGPFileReader_waysloaded"), wayCount)); + // info about the target polygons + IFeatureClass targetPolygonFeatureClass = gpUtilities.OpenFeatureClassFromString(targetPolygonFeatureClassLocation); + comReleaser.ManageLifetime(targetPolygonFeatureClass); + int osmTargetPolygonIDFieldIndex = targetPolygonFeatureClass.FindField("OSMID"); + int osmTargetPolygonTagCollectionFieldIndex = targetPolygonFeatureClass.FindField("osmTags"); + string targetSQLPolygonOSMID = targetPolygonFeatureClass.SqlIdentifier("OSMID"); - insertPolygonCursor.Flush(); - if (polygonFeatureLoad != null) - { - polygonFeatureLoad.LoadOnlyMode = false; - } + Dictionary mainPolygonAttributeFieldIndices = new Dictionary(); + foreach (string fieldName in polygonFieldNames) + { + int currentFieldIndex = targetPolygonFeatureClass.FindField(OSMToolHelper.convert2AttributeFieldName(fieldName, null)); - insertLineCursor.Flush(); - if (lineFeatureLoad != null) + if (currentFieldIndex != -1) { - lineFeatureLoad.LoadOnlyMode = false; + mainPolygonAttributeFieldIndices.Add(OSMToolHelper.convert2AttributeFieldName(fieldName, null), currentFieldIndex); } } - } - IGeoProcessor2 geoProcessor = new GeoProcessorClass(); - IGPUtilities3 gpUtilities3 = new GPUtilitiesClass(); - bool storedOriginal = geoProcessor.AddOutputsToMap; - IVariantArray parameterArrary = null; - IGeoProcessorResult2 gpResults2 = null; + relationFileXmlReader = XmlReader.Create(osmFileLocation); + relationFileXmlReader.ReadToFollowing("relation"); - try - { - geoProcessor.AddOutputsToMap = false; - if (lineIndexRebuildRequired) - { - IIndexes featureClassIndexes = osmLineFeatureClass.Indexes; - int indexPosition = -1; - featureClassIndexes.FindIndex("osmID_IDX", out indexPosition); + IFeatureBuffer lineFeatureBuffer = targetLineFeatureClass.CreateFeatureBuffer(); + comReleaser.ManageLifetime(lineFeatureBuffer); + IFeatureCursor lineFeatureInsertCursor = targetLineFeatureClass.Insert(true); + comReleaser.ManageLifetime(lineFeatureInsertCursor); - string fcLocation = GetLocationString(targetGPValue, osmLineFeatureClass); - if (indexPosition == -1) - { - message.AddMessage(_resourceManager.GetString("GPTools_buildinglineidx")); + IFeatureBuffer polygonFeatureBuffer = targetPolygonFeatureClass.CreateFeatureBuffer(); + comReleaser.ManageLifetime(polygonFeatureBuffer); + IFeatureCursor polygonFeatureInsertCursor = targetPolygonFeatureClass.Insert(true); + comReleaser.ManageLifetime(polygonFeatureInsertCursor); - // Addd index for osmid column - parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", ""); - gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2; - } - if (wayCount > 100) - { - // in this case we are dealing with a file geodatabase - if (lineFeatureLoad == null) - { - UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation); - } - } + IQueryFilter lineOSMIDQueryFilter = new QueryFilterClass(); + // the line query filter for updates will not changes, so let's do that ahead of time + try + { + lineOSMIDQueryFilter.SubFields = sourceLineFeatureClass.ShapeFieldName + "," + sourceLineFeatureClass.Fields.get_Field(osmSourceLineIDFieldIndex).Name; } + catch + { } - if (polygonIndexRebuildRequired) + IQueryFilter polygonOSMIDQueryFilter = new QueryFilterClass(); + // the line query filter for updates will not changes, so let's do that ahead of time + try { - IIndexes featureClassIndexes = osmPolygonFeatureClass.Indexes; - int indexPosition = -1; - featureClassIndexes.FindIndex("osmID_IDX", out indexPosition); + polygonOSMIDQueryFilter.SubFields = sourcePolygonFeatureClass.ShapeFieldName + "," + sourcePolygonFeatureClass.Fields.get_Field(osmSourcePolygonIDFieldIndex).Name; + } + catch + { } - string fcLocation = GetLocationString(targetGPValue, osmPolygonFeatureClass); + IQueryFilter outerPolygonQueryFilter = new QueryFilterClass(); + try + { + outerPolygonQueryFilter.SubFields = sourcePolygonFeatureClass.Fields.get_Field(osmTargetPolygonTagCollectionFieldIndex).Name + "," + sourcePolygonFeatureClass.Fields.get_Field(osmSourcePolygonIDFieldIndex).Name; + } + catch { } - if (indexPosition == -1) + polygonOSMIDQueryFilter.WhereClause = sourceSQLPolygonOSMID + " IN ('w1')"; + IFeatureCursor searchPolygonCursor = sourcePolygonFeatureClass.Search(polygonOSMIDQueryFilter, false); + comReleaser.ManageLifetime(searchPolygonCursor); + + lineOSMIDQueryFilter.WhereClause = sourceSQLLineOSMID + " IN ('w1')"; + IFeatureCursor searchLineCursor = sourceLineFeatureClass.Search(lineOSMIDQueryFilter, false); + comReleaser.ManageLifetime(searchLineCursor); + + TagKeyValueComparer routeTagComparer = new TagKeyValueComparer(); + + do { + + try { - message.AddMessage(_resourceManager.GetString("GPTools_buildingpolygonidx")); + string relationOSMID = "r" + relationFileXmlReader.GetAttribute("id"); - IGPValue polygonFeatureClassGPValue = gpUtilities3.MakeGPValueFromObject(osmPolygonFeatureClass); + string membersAndTags = relationFileXmlReader.ReadInnerXml(); - if (polygonFeatureClassGPValue != null) + bool relationIsComplete = true; + + tags = new List(); + + Dictionary> members = new Dictionary>(); + + List itemIDs = new List(); + List outerIDs = new List(); + List innerIDs = new List(); + List subAreaIDs = new List(); + + // determine the member of the relations and the tags + foreach (XElement item in ParseXml(membersAndTags)) { - // Addd index for osmid column - parameterArrary = CreateAddIndexParameterArray(fcLocation, "OSMID", "osmID_IDX", "UNIQUE", ""); - gpResults2 = geoProcessor.Execute("AddIndex_management", parameterArrary, TrackCancel) as IGeoProcessorResult2; + if (item.Name == "member") + { + // if the member is of type way, relation, point, or something else + string memberType = item.Attribute("type").Value; + string prefix = String.Empty; + if (memberType == "node") + prefix = "n"; + else if (memberType == "way") + prefix = "w"; + else if (memberType == "relation") + prefix = "r"; + + string refID = item.Attribute("ref").Value; + string role = item.Attribute("role").Value; + + if (role == "outer") + outerIDs.Add(prefix + refID); + + if (role == "inner") + innerIDs.Add(prefix + refID); + + if (role == "subarea") + subAreaIDs.Add(prefix + refID); + + if (includeSuperRelations) + { + if (memberType == "way" || memberType == "relation") + itemIDs.Add(prefix + refID); + } + else + { + if (memberType == "way") + itemIDs.Add(prefix + refID); + } + + if (!members.ContainsKey(memberType)) + members[memberType] = new List(); + + members[memberType].Add(prefix + refID); + } + else if (item.Name == "tag") + { + tags.Add(new tag() { k = item.Attribute("k").Value, v = item.Attribute("v").Value }); + } } - } - if (wayCount > 100) - { - if (polygonFeatureLoad == null) + // if instructed to ignore relations (even though containing relations) + // then empty out the list of collected IDs, and hence ignore the relation for loading + if (!includeSuperRelations && members.ContainsKey("relation")) + itemIDs.Clear(); + else if (includeSuperRelations && !members.ContainsKey("relation")) + itemIDs.Clear(); + + // remove items categorized as subareas + if (includeSuperRelations) { - UpdateSpatialGridIndex(TrackCancel, message, geoProcessor, fcLocation); + foreach (var subAreaID in subAreaIDs) + { + itemIDs.Remove(subAreaID); + } } - } - } - } - catch (Exception ex) - { - message.AddWarning(ex.Message); - } - finally - { - geoProcessor.AddOutputsToMap = storedOriginal; - Marshal.FinalReleaseComObject(gpUtilities3); - Marshal.FinalReleaseComObject(geoProcessor); - } - } - catch (Exception ex) - { - message.AddWarning(ex.Message); - } - finally - { - if (waySerializer != null) - waySerializer = null; + bool isRoute = false; + // check for the existence of a route, route_master, network tag -> indicating a linear feature and overrules the + // geometry determination of polygon or polyline + tag routeTag = new tag() { k = "type", v = "route" }; + tag routeMasterTag = new tag() { k = "type", v = "route_master" }; + tag networkTag = new tag() { k = "type", v = "network" }; + if (tags.Contains(routeTag, routeTagComparer) || tags.Contains(routeMasterTag, routeTagComparer) || tags.Contains(networkTag, routeTagComparer)) + { + isRoute = true; + } - if (osmFileXmlReader != null) - osmFileXmlReader = null; + bool checkOuter = false; + bool hasMultiPolygonTag = false; + tag multiPolygonTag = new tag() { k = "type", v = "multipolygon" }; + if (tags.Contains(multiPolygonTag, routeTagComparer)) + { + hasMultiPolygonTag = true; + if (tags.Count == 1) + { + checkOuter = true; + } + } - System.GC.Collect(); - System.GC.WaitForPendingFinalizers(); - } + // attempt to assemble the relation feature from the way and relation IDs + if (itemIDs.Count > 0) + { + bool isArea = false; - return missingWays; - } + List idRequests = SplitOSMIDRequests(itemIDs); + List itemGeometries = new List(itemIDs.Count); + Dictionary itemPositionDictionary = new Dictionary(itemIDs.Count); - private static string CleanReportedNodes(string idCompareString) - { - // if all the requested IDs were returned we should only have brackets and commas left - string save_compareString = idCompareString; - string searchPattern = @"(\d+,\d*)"; - Regex regularExpression = new Regex(searchPattern); + // build a list of way ids we can use to determine the order in the relation + for (int index = 0; index < itemIDs.Count; index++) + { + itemGeometries.Add(new PointClass()); + itemPositionDictionary[itemIDs[index]] = index; + } - Match matches = regularExpression.Match(save_compareString); - StringBuilder missingNodesString = new StringBuilder(); + List polygonIDs = new List(); - foreach (Group matchGroup in matches.Groups) - { - if (String.IsNullOrEmpty(matchGroup.Value) == false) - { - missingNodesString.Append(matchGroup.Value); - missingNodesString.Append(","); - } - } + // check in the line feature class first + foreach (string request in idRequests) + { + string idCompareString = request; + lineOSMIDQueryFilter.WhereClause = sourceSQLLineOSMID + " IN " + request; - idCompareString = "(" + missingNodesString.ToString().Replace(",,", ",") + ")"; - return idCompareString; - } + searchLineCursor = sourceLineFeatureClass.Search(lineOSMIDQueryFilter, false); - internal static string retrieveNodeID(IFeatureClass pointFeatureClass, int osmIDPointFieldIndex, int extensionVersion, IPoint pointGeometry) - { - string nodeID = string.Empty; + IFeature lineFeature = searchLineCursor.NextFeature(); - if (pointGeometry == null) - return String.Empty; + while (lineFeature != null) + { + // determine the ID of the line in with respect to the node position + string lineOSMIDString = Convert.ToString(lineFeature.get_Value(osmSourceLineIDFieldIndex)); - if (pointGeometry.IsEmpty) - return String.Empty; + // remove the ID from the request string + idCompareString = idCompareString.Replace(lineOSMIDString, String.Empty); - if (((IPointIDAware)pointGeometry).PointIDAware == false) - { - return nodeID; - } - if (extensionVersion == 1) - { - nodeID = Convert.ToString(pointGeometry.ID); - } - else if (extensionVersion == 2) - { - IFeature pointFeature = null; - try - { - pointFeature = pointFeatureClass.GetFeature(pointGeometry.ID); - } - catch { } - if (pointFeature != null) - { - if (osmIDPointFieldIndex > -1) - { - nodeID = Convert.ToString(pointFeature.get_Value(osmIDPointFieldIndex)); - } + itemGeometries[itemPositionDictionary[lineOSMIDString]] = lineFeature.ShapeCopy; - Marshal.ReleaseComObject(pointFeature); - } - } - return nodeID; - } + lineFeature = searchLineCursor.NextFeature(); + } + idCompareString = CleanReportedIDs(idCompareString); - internal void countOSMStuff(string osmFileLocation, ref long nodeCapacity, ref long wayCapacity, ref long relationCapacity, ref ITrackCancel CancelTracker) - { - using (System.Xml.XmlReader osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation)) - { - osmFileXmlReader.MoveToContent(); + // after removing the commas we should be left with only paranthesis left, meaning a string of length 2 + // if we have more then we have found a missing way as a line we still need to search the polygons + if (idCompareString.Length > 2) + { + string[] wayIDs = idCompareString.Substring(1, idCompareString.Length - 2).Split(",".ToCharArray()); + polygonIDs.AddRange(wayIDs); + } + } - while (osmFileXmlReader.Read()) - { - if (CancelTracker.Continue()) - { - if (osmFileXmlReader.IsStartElement()) - { - string currentNodeName = osmFileXmlReader.Name; + // next collect the polygon geometries + idRequests = SplitOSMIDRequests(polygonIDs); - switch (currentNodeName) - { - case "node": - nodeCapacity++; - break; - case "way": - wayCapacity++; - break; - case "relation": - relationCapacity++; - break; - } - } - } - else - return; - } + foreach (string request in idRequests) + { + string idCompareString = request; + polygonOSMIDQueryFilter.WhereClause = sourceSQLPolygonOSMID + " IN " + request; - osmFileXmlReader.Close(); - } - } + searchPolygonCursor = sourcePolygonFeatureClass.Search(polygonOSMIDQueryFilter, false); - internal Dictionary> countOSMCapacityAndTags(string osmFileLocation, ref long nodeCapacity, ref long wayCapacity, ref long relationCapacity, ref ITrackCancel CancelTracker) - { - Dictionary> attributesDictionary = new Dictionary>(); + IFeature polygonFeature = searchPolygonCursor.NextFeature(); + + while (polygonFeature != null) + { + // determine the ID of the polygon in with respect to the way position + string polygonOSMIDString = Convert.ToString(polygonFeature.get_Value(osmSourcePolygonIDFieldIndex)); - try - { - XmlSerializer nodeSerializer = new XmlSerializer(typeof(node)); - XmlSerializer waySerializer = new XmlSerializer(typeof(way)); - XmlSerializer relationSerializer = new XmlSerializer(typeof(relation)); + // remove the ID from the request string + idCompareString = idCompareString.Replace(polygonOSMIDString, String.Empty); - List pointTags = new List(); - List lineTags = new List(); - List polygonTags = new List(); + itemGeometries[itemPositionDictionary[polygonOSMIDString]] = polygonFeature.ShapeCopy; - using (System.Xml.XmlReader osmFileXmlReader = System.Xml.XmlReader.Create(osmFileLocation)) - { - osmFileXmlReader.MoveToContent(); + polygonFeature = searchPolygonCursor.NextFeature(); + } - while (osmFileXmlReader.Read()) - { - if (CancelTracker.Continue()) - { - if (osmFileXmlReader.IsStartElement()) - { - string currentNodeName = osmFileXmlReader.Name; + idCompareString = CleanReportedIDs(idCompareString); - switch (currentNodeName) + // after removing the commas we should be left with only paranthesis left, meaning a string of length 2 + // if we have more then we have found a missing way as a line we still need to search the polygons + if (idCompareString.Length > 2) + { + relationIsComplete = false; + break; + } + } + + if (relationIsComplete == true) { - case "node": - string currentNodeString = osmFileXmlReader.ReadOuterXml(); - // turn the xml node representation into a node class representation - ESRI.ArcGIS.OSM.OSMClassExtension.node currentNode = null; - using (StringReader nodeReader = new System.IO.StringReader(currentNodeString)) + List relationParts = new List(); + + // special case for multipolygon + // in this case we know we are dealing with polygon -- in other words, we just need to piece it together + if (hasMultiPolygonTag) + { + isArea = true; + + #region multipolygon + // find the first polyline in the geometry collection + int startIndex = 0; + foreach (var itemGeometry in itemGeometries) { - try + startIndex++; + + if (itemGeometry is IPolyline) { - currentNode = nodeSerializer.Deserialize(nodeReader) as ESRI.ArcGIS.OSM.OSMClassExtension.node; + relationParts.Add(itemGeometry as IGeometryCollection); + break; } - catch { } } - if (currentNode != null) + for (int i = startIndex; i < itemGeometries.Count; i++) { - if (currentNode.tag != null) + IPolyline wayGeometry = itemGeometries[i] as IPolyline; + + // first pieces the polylines together and into parts + if (wayGeometry == null) + continue; + + IGeometry mergedGeometry = FitPolylinePiecesTogether(relationParts[relationParts.Count - 1] as IPolyline, wayGeometry, false); + + if (mergedGeometry == null) + relationParts.Add(wayGeometry as IGeometryCollection); + else if (mergedGeometry is IPolyline) + relationParts[relationParts.Count - 1] = mergedGeometry as IGeometryCollection; + else if (mergedGeometry is IPolygon) { - foreach (tag currentTag in currentNode.tag) + relationParts[relationParts.Count - 1] = mergedGeometry as IGeometryCollection; + + for (int newPartIndex = i + 1; newPartIndex < itemGeometries.Count; newPartIndex++) { - if (!pointTags.Contains(currentTag.k)) + if (itemGeometries[newPartIndex] is IPolyline) { - pointTags.Add(currentTag.k); + relationParts.Add(itemGeometries[newPartIndex] as IGeometryCollection); + i = newPartIndex; + break; } } } } - nodeCapacity++; - break; - case "way": - wayCapacity++; + for (int i = 0; i < itemGeometries.Count; i++) + { + IPolygon wayGeometry = itemGeometries[i] as IPolygon; - string currentWayString = osmFileXmlReader.ReadOuterXml(); - // turn the xml node representation into a node class representation - ESRI.ArcGIS.OSM.OSMClassExtension.way currentWay = null; - using (StringReader wayReader = new System.IO.StringReader(currentWayString)) + if (wayGeometry != null) + { + relationParts.Add(wayGeometry as IGeometryCollection); + } + } + #endregion + } + else + { + int startIndex = 0; + foreach (var itemGeometry in itemGeometries) { - try + startIndex++; + + if (itemGeometry is IPolyline) { - currentWay = waySerializer.Deserialize(wayReader) as ESRI.ArcGIS.OSM.OSMClassExtension.way; + relationParts.Add(itemGeometry as IGeometryCollection); + break; + } + else if (itemGeometry is IPolygon) + { + if (!isRoute) + { + isArea = true; + relationParts.Add(itemGeometry as IGeometryCollection); + } } - catch { } } - if (currentWay != null) + for (int i = startIndex; i < itemGeometries.Count; i++) { - if (currentWay.tag != null) + IGeometry wayGeometry = itemGeometries[i]; + + if (wayGeometry is IPolygon) { - foreach (tag currentTag in currentWay.tag) + if (!isRoute) { - if (OSMToolHelper.IsThisWayALine(currentWay) && !lineTags.Contains(currentTag.k)) + isArea = true; + relationParts.Add(wayGeometry as IGeometryCollection); + + #region Ensure that the next part is a polyline + for (int newPartIndex = i + 1; newPartIndex < itemGeometries.Count; newPartIndex++) { - lineTags.Add(currentTag.k); + if (itemGeometries[newPartIndex] is IPolyline) + { + relationParts.Add(itemGeometries[newPartIndex] as IGeometryCollection); + i = newPartIndex; + break; + } + else if (itemGeometries[newPartIndex] is IPolygon) + { + if (!isRoute) + { + isArea = true; + relationParts.Add(itemGeometries[newPartIndex] as IGeometryCollection); + } + + i = newPartIndex; + } } - else if (!polygonTags.Contains(currentTag.k)) + #endregion + } + } + else if (wayGeometry is IPolyline) + { + IGeometry mergedGeometry = FitPolylinePiecesTogether(relationParts[relationParts.Count - 1] as IPolyline, wayGeometry as IPolyline, isRoute); + + if (mergedGeometry == null) + relationParts.Add(wayGeometry as IGeometryCollection); + else if (mergedGeometry is IPolyline) + relationParts[relationParts.Count - 1] = mergedGeometry as IGeometryCollection; + else if (mergedGeometry is IPolygon) + { + isArea = true; + relationParts[relationParts.Count - 1] = mergedGeometry as IGeometryCollection; + + #region Ensure that the next part is a polyline + for (int newPartIndex = i + 1; newPartIndex < itemGeometries.Count; newPartIndex++) { - polygonTags.Add(currentTag.k); + if (itemGeometries[newPartIndex] is IPolyline) + { + relationParts.Add(itemGeometries[newPartIndex] as IGeometryCollection); + i = newPartIndex; + break; + } + else if (itemGeometries[newPartIndex] is IPolygon) + { + if (!isRoute) + { + isArea = true; + relationParts.Add(itemGeometries[newPartIndex] as IGeometryCollection); + } + + i = newPartIndex; + } } + #endregion } } } + } - break; - case "relation": - relationCapacity++; + // some pieces might be still out of order - this call will reorder and connect linear geometries as well + // as close outstanding polygons + relationParts = HarmonizeGeometries(relationParts, isRoute); - // for relation let's NOT do an exhaustive determine if we have a polygon or maybe a multipart polyline - // or maybe a super relation - string currentRelationString = osmFileXmlReader.ReadOuterXml(); + //re-assess the type of geometry, additional lines might have joined into polygons + // favor tags over geometry determination + if (!isRoute & !hasMultiPolygonTag) + { + isArea = true; - ESRI.ArcGIS.OSM.OSMClassExtension.relation currentRelation = null; - using (StringReader relationReader = new System.IO.StringReader(currentRelationString)) + foreach (var part in relationParts) { - try + if (part is IPolyline) { - currentRelation = relationSerializer.Deserialize(relationReader) as ESRI.ArcGIS.OSM.OSMClassExtension.relation; + isArea = false; + break; } - catch { } } + } - if (currentRelation != null) + // now assemble the final geometry based on our discovery if there is an area and store the relation as a new feature + if (isArea) + { + #region transfer for outer tags to relation itself + // if needed to one more request to assemble the information of the outer rings to be transfer to the "empty" + // relation enity + if (checkOuter) { - if (currentRelation.Items != null) + idRequests = SplitOSMIDRequests(outerIDs); + + foreach (string request in idRequests) { - bool polygonTagDetected = false; + string idCompareString = request; + outerPolygonQueryFilter.WhereClause = sourceSQLPolygonOSMID + " IN " + request; - foreach (var item in currentRelation.Items) + searchPolygonCursor = sourcePolygonFeatureClass.Search(outerPolygonQueryFilter, false); + + IFeature polygonFeature = searchPolygonCursor.NextFeature(); + + while (polygonFeature != null) { - if (item is ESRI.ArcGIS.OSM.OSMClassExtension.tag) - { - ESRI.ArcGIS.OSM.OSMClassExtension.tag currentTag = item as ESRI.ArcGIS.OSM.OSMClassExtension.tag; + // determine the ID of the polygon in with respect to the way position + tag[] outerRingsTags = _osmUtility.retrieveOSMTags(polygonFeature, osmTargetPolygonTagCollectionFieldIndex, null); - if (polygonTagDetected) - { - if (!polygonTags.Contains(currentTag.k)) - { - polygonTags.Add(currentTag.k); - } - } - else if (currentTag.k.ToUpper().Equals("TYPE")) + if (outerRingsTags != null) + { + if (outerRingsTags.Count() > 0) { - if ((currentTag.v.ToUpper().Equals("POLYGON") || currentTag.v.ToUpper().Equals("MULTIPOLYGON"))) + foreach (var outerTag in outerRingsTags) { - polygonTagDetected = true; + if (!tags.Contains(outerTag, new TagKeyComparer())) + { + tags.Add(outerTag); + } } } } + + polygonFeature = searchPolygonCursor.NextFeature(); } } } - break; + #endregion + + IGeometryCollection relationPolygon = new PolygonClass(); + + foreach (var part in relationParts) + { + for (int ringIndex = 0; ringIndex < part.GeometryCount; ringIndex++) + { + ISegmentCollection ringSegmentCollection = new RingClass(); + ringSegmentCollection.AddSegmentCollection(part.get_Geometry(ringIndex) as ISegmentCollection); + relationPolygon.AddGeometry(ringSegmentCollection as IGeometry); + } + + } + + ((ITopologicalOperator2)relationPolygon).IsKnownSimple_2 = false; + ((IPolygon4)relationPolygon).SimplifyEx(true, false, false); + + + // set the shape + polygonFeatureBuffer.Shape = relationPolygon as IGeometry; + + // insert the relation ID + polygonFeatureBuffer.set_Value(osmTargetPolygonIDFieldIndex, relationOSMID); + + // insert the tags into the appropriate fields + insertTags(mainPolygonAttributeFieldIndices, osmTargetPolygonTagCollectionFieldIndex, polygonFeatureBuffer, tags.ToArray()); + + try + { + // load the polygon feature + polygonFeatureInsertCursor.InsertFeature(polygonFeatureBuffer); + } + catch (Exception inEx) + { +#if DEBUG + foreach (var item in tags) + { + System.Diagnostics.Debug.WriteLine(string.Format("{0},{1}", item.k, item.v)); + } + System.Diagnostics.Debug.WriteLine(inEx.Message); + System.Diagnostics.Debug.WriteLine(inEx.StackTrace); +#endif + } + } + else + { + IGeometryCollection relationPolyline = new PolylineClass(); + + foreach (var part in relationParts) + { + for (int pathIndex = 0; pathIndex < part.GeometryCount; pathIndex++) + { + ISegmentCollection pathSegmentCollection = new PathClass(); + pathSegmentCollection.AddSegmentCollection(part.get_Geometry(pathIndex) as ISegmentCollection); + relationPolyline.AddGeometry(pathSegmentCollection as IGeometry); + } + } + + // set the shape + lineFeatureBuffer.Shape = relationPolyline as IGeometry; + + // insert the relation ID + lineFeatureBuffer.set_Value(osmTargetLineIDFieldIndex, relationOSMID); + + // insert the tags into the appropriate fields + insertTags(mainLineAttributeFieldIndices, osmTargetLineIDFieldIndex, lineFeatureBuffer, tags.ToArray()); + + try + { + // load the line feature + lineFeatureInsertCursor.InsertFeature(lineFeatureBuffer); + } + catch (Exception inEx) + { +#if DEBUG + foreach (var item in tags) + { + System.Diagnostics.Debug.WriteLine(string.Format("{0},{1}", item.k, item.v)); + } + System.Diagnostics.Debug.WriteLine(inEx.Message); + System.Diagnostics.Debug.WriteLine(inEx.StackTrace); +#endif + } + } } } } + catch (Exception hmmEx) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine("Unexpected error : !!!!!!"); + System.Diagnostics.Debug.WriteLine(hmmEx.Message); + System.Diagnostics.Debug.WriteLine(hmmEx.StackTrace); +#endif + } + + // if we encounter a whitespace, attempt to find the next relation if it exists + if (relationFileXmlReader.NodeType != XmlNodeType.Element) + relationFileXmlReader.ReadToFollowing("relation"); + + } while (relationFileXmlReader.Name == "relation"); + + } + catch (Exception ex) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif + } + finally + { + if (relationFileXmlReader != null) + relationFileXmlReader.Close(); + } + } + } + + private List HarmonizeGeometries(List relationParts, bool isLinear) + { + List harmonizedList = new List(); + + List polylineIndices = new List(); + List isVisited = new List(); + + for (int partIndex = 0; partIndex < relationParts.Count; partIndex++) + { + if (relationParts[partIndex] is IPolyline) + { + polylineIndices.Add(partIndex); + isVisited.Add(true); + } + else if (relationParts[partIndex] is IPolygon) + harmonizedList.Add(relationParts[partIndex] as IGeometryCollection); + } + + if (polylineIndices.Count < 2) + return relationParts; + + IPolyline tempPolyline = ((IClone)relationParts[polylineIndices[0]]).Clone() as IPolyline; + isVisited[0] = false; + + int startIndex = 1; + + while (startIndex < polylineIndices.Count) + { + for (int i = startIndex; i < polylineIndices.Count; i++) + { + if (isVisited[i] == false) + continue; + + IGeometry compareGeometry = FitPolylinePiecesTogether(tempPolyline, relationParts[polylineIndices[i]] as IPolyline, isLinear); + + if (compareGeometry is IPolyline) + { + tempPolyline = ((IClone)compareGeometry).Clone() as IPolyline; + isVisited[i] = false; + i = startIndex - 1; + } + else if (compareGeometry is IPolygon) + { + harmonizedList.Add(compareGeometry as IGeometryCollection); + isVisited[i] = false; + tempPolyline = null; + + for (int ni = startIndex; ni < polylineIndices.Count; ni++) + { + if (isVisited[ni] == false) + continue; + + tempPolyline = ((IClone)relationParts[polylineIndices[ni]]).Clone() as IPolyline; + isVisited[ni] = false; + i = startIndex - 1; + break; + } + } + } + + if (tempPolyline == null) + startIndex = polylineIndices.Count; + else + { + harmonizedList.Add(((IClone)tempPolyline).Clone() as IGeometryCollection); + tempPolyline = null; + + for (int i = startIndex; i < polylineIndices.Count; i++) + { + if (isVisited[i] == false) + continue; + else + { + startIndex++; + tempPolyline = ((IClone)relationParts[polylineIndices[i]]).Clone() as IPolyline; + isVisited[i] = false; + break; + } } + } + } + + if (tempPolyline != null) + { + harmonizedList.Add(tempPolyline as IGeometryCollection); + } + + return harmonizedList; + } + + /// + /// Attempts to merge two polylines if the to and from points are coincident + /// + /// + /// + /// A Null pointer if the two polylines are disjoint, a polyline if there is + /// a coincidence in the from or to points, or a polygon if the to and from point of the merged polyline + /// are coincident, so they are forming a closed ring. + private IGeometry FitPolylinePiecesTogether(IPolyline partOne, IPolyline partTwo, bool isLinear) + { + IGeometry mergedPart = null; + + IPoint partOneFromPoint = null; + IPoint partOneToPoint = null; + + if (partOne == null) + throw new NullReferenceException("partOne is Null"); + + if (partTwo == null) + throw new NullReferenceException("partTwo is Null"); + + partOneFromPoint = partOne.FromPoint; + partOneToPoint = partOne.ToPoint; + + bool FromPointConnect = ((IRelationalOperator)partOneToPoint).Equals(partTwo.FromPoint); + bool ToPointConnect = ((IRelationalOperator)partOneToPoint).Equals(partTwo.ToPoint); + + if (FromPointConnect || ToPointConnect) + { + if (FromPointConnect) + { + mergedPart = new PolylineClass(); + ((IGeometryCollection) mergedPart).AddGeometryCollection(partOne as IGeometryCollection); + ((IGeometryCollection) mergedPart).AddGeometryCollection(partTwo as IGeometryCollection); + } + + if (ToPointConnect) + { + mergedPart = new PolylineClass(); + ((IGeometryCollection) mergedPart).AddGeometryCollection(partOne as IGeometryCollection); + + IPolyline flippedPartTwoGeometry = ((IClone) partTwo).Clone() as IPolyline; + flippedPartTwoGeometry.ReverseOrientation(); + + ((IGeometryCollection) mergedPart).AddGeometryCollection(((IClone)flippedPartTwoGeometry).Clone() as IGeometryCollection); + } + } + + FromPointConnect = ((IRelationalOperator)partOneFromPoint).Equals(partTwo.FromPoint); + ToPointConnect = ((IRelationalOperator)partOneFromPoint).Equals(partTwo.ToPoint); + + if (FromPointConnect || ToPointConnect) + { + if (FromPointConnect) + { + mergedPart = new PolylineClass(); - osmFileXmlReader.Close(); + IPolyline flippedPartOneGeometry = ((IClone) partOne).Clone() as IPolyline; + flippedPartOneGeometry.ReverseOrientation(); + + ((IGeometryCollection) mergedPart).AddGeometryCollection(((IClone)flippedPartOneGeometry).Clone() as IGeometryCollection); + ((IGeometryCollection) mergedPart).AddGeometryCollection(partTwo as IGeometryCollection); } - attributesDictionary.Add(esriGeometryType.esriGeometryPoint, pointTags); - attributesDictionary.Add(esriGeometryType.esriGeometryPolyline, lineTags); - attributesDictionary.Add(esriGeometryType.esriGeometryPolygon, polygonTags); - } + if (ToPointConnect) + { + mergedPart = new PolylineClass(); + ((IGeometryCollection) mergedPart).AddGeometryCollection(partTwo as IGeometryCollection); + ((IGeometryCollection) mergedPart).AddGeometryCollection(partOne as IGeometryCollection); + } + } - catch { } + if (!isLinear) + { + // now check if from and to points on the merged polyline are coincident + if (mergedPart != null) + { + IPolyline mergedPolyline = mergedPart as IPolyline; - return attributesDictionary; + if (((IRelationalOperator)mergedPolyline.FromPoint).Equals(mergedPolyline.ToPoint)) + { + IPolygon tempPolygon = new PolygonClass(); + ((ISegmentCollection)tempPolygon).AddSegmentCollection(mergedPart as ISegmentCollection); + + tempPolygon.Close(); + + mergedPart = ((IClone)tempPolygon).Clone() as IGeometry; + } + } + } + + + return mergedPart; } internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel TrackCancel, ref IGPMessages message, IGPValue targetGPValue, IFeatureClass osmPointFeatureClass, IFeatureClass osmLineFeatureClass, IFeatureClass osmPolygonFeatureClass, int relationCapacity, ITable relationTable, OSMDomains availableDomains, bool fastLoad, bool checkForExisting) @@ -3328,17 +6310,19 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel { using (SchemaLockManager linelock = new SchemaLockManager(osmLineFeatureClass as ITable), polygonLock = new SchemaLockManager(osmPolygonFeatureClass as ITable), relationLock = new SchemaLockManager(relationTable)) { - IRowBuffer rowBuffer = null; ICursor rowCursor = relationTable.Insert(true); comReleaser.ManageLifetime(rowCursor); + IRowBuffer rowBuffer = null; - IFeatureBuffer lineFeatureBuffer = null; IFeatureCursor lineFeatureInsertCursor = osmLineFeatureClass.Insert(true); + comReleaser.ManageLifetime(lineFeatureInsertCursor); + IFeatureBuffer lineFeatureBuffer = null; - IFeatureBuffer polygonFeatureBuffer = null; IFeatureCursor polygonFeatureInsertCursor = osmPolygonFeatureClass.Insert(true); + comReleaser.ManageLifetime(polygonFeatureInsertCursor); + IFeatureBuffer polygonFeatureBuffer = null; int relationCount = 1; int relationDebugCount = 1; @@ -3449,10 +6433,6 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel List osmPolygonList = null; List osmRelationList = null; - rowBuffer = relationTable.CreateRowBuffer(); - lineFeatureBuffer = osmLineFeatureClass.CreateFeatureBuffer(); - polygonFeatureBuffer = osmPolygonFeatureClass.CreateFeatureBuffer(); - foreach (var item in currentRelation.Items) { if (item is member) @@ -3598,8 +6578,6 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel if (detectedGeometryType == esriGeometryType.esriGeometryPolygon) { #region create multipart polygon geometry - //IFeature mpFeature = osmPolygonFeatureClass.CreateFeature(); - IPolygon relationMPPolygon = new PolygonClass(); relationMPPolygon.SpatialReference = ((IGeoDataset)osmPolygonFeatureClass).SpatialReference; @@ -3610,6 +6588,7 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel string sqlLineOSMID = osmLineFeatureClass.SqlIdentifier("OSMID"); object missing = Type.Missing; bool relationComplete = true; + string missingWayID = String.Empty; // loop through the list of referenced ways that are listed in a relation // for each of the items we need to make a decision if they have merit to qualify as stand-alone features @@ -3638,9 +6617,9 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel break; } - - System.Diagnostics.Debug.WriteLine("Relation (Polygon) #: " + relationDebugCount + " :___: " + currentRelation.id + " :___: " + wayKey.Key); - +#if DEBUG + System.Diagnostics.Debug.WriteLine("Relation (Polygon) #: " + relationDebugCount + " :___: " + currentRelation.id + " :___: " + wayKey); +#endif using (ComReleaser relationComReleaser = new ComReleaser()) { IFeatureCursor featureCursor = null; @@ -3663,16 +6642,16 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel // set the appropriate field attribute to become invisible as a standalone features if (partFeature != null) { - IGeometryCollection ringCollection = partFeature.Shape as IGeometryCollection; + ISegmentCollection ringCollection = partFeature.Shape as ISegmentCollection; // test for available content in the geometry collection - if (ringCollection.GeometryCount > 0) + if (ringCollection.SegmentCount > 0) { // test if we dealing with a valid geometry - if (ringCollection.get_Geometry(0).IsEmpty == false) + if (ringCollection.get_Segment(0).IsEmpty == false) { // add it to the new geometry and mark the added geometry as a supporting element - relationPolygonGeometryCollection.AddSegmentCollection((ISegmentCollection)ringCollection.get_Geometry(0)); + relationPolygonGeometryCollection.AddSegmentCollection(ringCollection); // TE - 10/14/2014 ( 1/5/2015 -- still under consideration) // the initial assessment if the feature is a supporting element based on the existence of tags @@ -3686,9 +6665,21 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel // of the relation parent, then mark it as a supporting element if (roleType.ToLower().Equals("outer")) { - if (_osmUtility.AreTagsTheSame(relationTagList, partFeature, tagCollectionPolygonFieldIndex, null)) + if (partFeature.Shape.GeometryType == esriGeometryType.esriGeometryPolyline) + { + if (_osmUtility.AreTagsTheSame(relationTagList, partFeature, tagCollectionPolylineFieldIndex, null)) + { + partFeature.set_Value(osmSupportingElementPolylineFieldIndex, "yes"); + partFeature.Store(); + } + } + else { - partFeature.set_Value(osmSupportingElementPolygonFieldIndex, "yes"); + if (_osmUtility.AreTagsTheSame(relationTagList, partFeature, tagCollectionPolygonFieldIndex, null)) + { + partFeature.set_Value(osmSupportingElementPolygonFieldIndex, "yes"); + partFeature.Store(); + } } } //else @@ -3700,9 +6691,6 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel // partFeature.set_Value(osmSupportingElementPolygonFieldIndex, "yes"); // } //} - - partFeature.Store(); - } } } @@ -3759,8 +6747,9 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel } else { + missingWayID = wayKey.Key; relationComplete = false; - continue; + break; } //} } @@ -3770,11 +6759,16 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel if (relationComplete == false) { missingRelations.Add(currentRelation.id); +#if DEBUG + System.Diagnostics.Debug.WriteLine("Incomplete Polygon # " + currentRelation.id + "; missing Way ID #" + missingWayID); +#endif continue; } // transform the added collections for geometries into a topological correct geometry representation - ((IPolygon4)relationMPPolygon).SimplifyEx(true, false, true); + ((IPolygon4)relationMPPolygon).SimplifyEx(true, false, false); + + polygonFeatureBuffer = osmPolygonFeatureClass.CreateFeatureBuffer(); polygonFeatureBuffer.Shape = relationMPPolygon; @@ -3862,27 +6856,34 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel try { - //mpFeature.Store(); polygonFeatureInsertCursor.InsertFeature(polygonFeatureBuffer); + + //if ((relationCount % 5000) == 0) + //{ + // polygonFeatureInsertCursor.Flush(); + //} } catch (Exception ex) { - message.AddWarning(ex.Message); + polygonFeatureInsertCursor.Flush(); + + message.AddWarning(ex.Message + "(Polygon # " + currentRelation.id + ")"); + message.AddWarning(ex.StackTrace); } #endregion } else if (detectedGeometryType == esriGeometryType.esriGeometryPolyline) { #region create multipart polyline geometry - //IFeature mpFeature = osmLineFeatureClass.CreateFeature(); - IPolyline relationMPPolyline = new PolylineClass(); relationMPPolyline.SpatialReference = ((IGeoDataset)osmLineFeatureClass).SpatialReference; - IGeometryCollection relationPolylineGeometryCollection = relationMPPolyline as IGeometryCollection; + ISegmentCollection relationPolylineGeometryCollection = relationMPPolyline as ISegmentCollection; IQueryFilter osmIDQueryFilter = new QueryFilterClass(); object missing = Type.Missing; + bool relationComplete = true; + string missingWayID = String.Empty; // loop through the foreach (KeyValuePair wayKey in wayList) @@ -3893,9 +6894,9 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel } osmIDQueryFilter.WhereClause = osmLineFeatureClass.WhereClauseByExtensionVersion(wayKey.Key, "OSMID", 2); - +#if DEBUG System.Diagnostics.Debug.WriteLine("Relation (Polyline) #: " + relationDebugCount + " :___: " + currentRelation.id + " :___: " + wayKey); - +#endif using (ComReleaser relationComReleaser = new ComReleaser()) { IFeatureCursor featureCursor = osmLineFeatureClass.Search(osmIDQueryFilter, false); @@ -3908,8 +6909,8 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel { if (partFeature.Shape.IsEmpty == false) { - IGeometryCollection pathCollection = partFeature.Shape as IGeometryCollection; - relationPolylineGeometryCollection.AddGeometry(pathCollection.get_Geometry(0), ref missing, ref missing); + ISegmentCollection pathCollection = partFeature.Shape as ISegmentCollection; + relationPolylineGeometryCollection.AddSegmentCollection(pathCollection); // TE - 10/14/2014 - see comment above if (osmSupportingElementPolylineFieldIndex > -1) @@ -3923,17 +6924,32 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel if (!_osmUtility.AreTagsTheSame(relationTagList, partFeature, tagCollectionPolylineFieldIndex, null)) { partFeature.set_Value(osmSupportingElementPolylineFieldIndex, "yes"); + partFeature.Store(); } } } - - partFeature.Store(); - } } + else + { + missingWayID = wayKey.Key; + relationComplete = false; + break; + } } } + if (relationComplete == false) + { + missingRelations.Add(currentRelation.id); +#if DEBUG + System.Diagnostics.Debug.WriteLine("Incomplete Polyline # " + currentRelation.id + "; missing Way ID #" + missingWayID); +#endif + continue; + } + + lineFeatureBuffer = osmLineFeatureClass.CreateFeatureBuffer(); + lineFeatureBuffer.Shape = relationMPPolyline; insertTags(osmLineDomainAttributeFieldIndices, osmLineDomainAttributeFieldLength, tagCollectionPolylineFieldIndex, lineFeatureBuffer, relationTagList.ToArray()); @@ -4013,17 +7029,26 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel try { lineFeatureInsertCursor.InsertFeature(lineFeatureBuffer); + + //if ((relationCount % 5000) == 0) + //{ + // lineFeatureInsertCursor.Flush(); + //} } catch (Exception ex) { - message.AddWarning(ex.Message); + lineFeatureInsertCursor.Flush(); + + message.AddWarning(ex.Message + "(Line #" + currentRelation.id + ")"); } #endregion } else if (detectedGeometryType == esriGeometryType.esriGeometryPoint) { +#if DEBUG System.Diagnostics.Debug.WriteLine("Relation #: " + relationDebugCount + " :____: POINT!!!"); +#endif if (TrackCancel.Continue() == false) { @@ -4038,8 +7063,11 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel return missingRelations; } - +#if DEBUG System.Diagnostics.Debug.WriteLine("Relation #: " + relationDebugCount + " :____: Kept as relation"); +#endif + + rowBuffer = relationTable.CreateRowBuffer(); if (tagCollectionRelationFieldIndex != -1) { @@ -4119,13 +7147,20 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel try { rowCursor.InsertRow(rowBuffer); - relationCount = relationCount + 1; + + //if ((relationCount % 5000) == 0) + //{ + // rowCursor.Flush(); + //} relationIndexRebuildRequired = true; } catch (Exception ex) { - System.Diagnostics.Debug.WriteLine(ex.Message); +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message + " (row #" + currentRelation.id + ")"); +#endif + message.AddWarning(ex.Message + " (row #" + currentRelation.id + ")"); } // check for user interruption @@ -4160,6 +7195,8 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel } } + relationCount = relationCount + 1; + if (stepProgressor != null) { stepProgressor.Position = relationCount; @@ -4172,7 +7209,10 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel } catch (Exception ex) { - message.AddWarning(ex.Message); +#if DEBUG + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); +#endif } finally { @@ -4195,9 +7235,9 @@ internal List loadOSMRelations(string osmFileLocation, ref ITrackCancel currentRelation = null; } - } - } - } + } // relation element + } // is start element? + } // osmFileXmlReader // close the OSM file osmFileXmlReader.Close(); @@ -4336,6 +7376,7 @@ internal bool IsThisWayALine(string osmID, IFeatureClass lineFeatureClass, strin try { int osmIDPolygonFieldIndex = polygonFeatureClass.FindField("OSMID"); + int tagFieldIndex = polygonFeatureClass.FindField("osmTags"); int osmSupportingElementFieldIndex = polygonFeatureClass.FindField("osmSupportingElement"); string sqlPolyOSMID = polygonFeatureClass.SqlIdentifier("OSMID"); @@ -4359,7 +7400,7 @@ internal bool IsThisWayALine(string osmID, IFeatureClass lineFeatureClass, strin if (foundPolygonFeature == null) continue; - tag[] foundTags = _osmUtility.retrieveOSMTags(foundPolygonFeature, osmIDPolygonFieldIndex, ((IDataset)polygonFeatureClass).Workspace); + tag[] foundTags = _osmUtility.retrieveOSMTags(foundPolygonFeature, tagFieldIndex, ((IDataset)polygonFeatureClass).Workspace); // set this feature from which we transfer to become a supporting element if (osmSupportingElementFieldIndex > -1) @@ -4445,9 +7486,88 @@ public static string convert2AttributeFieldName(string OSMKey, string IllegalCha return attributeFieldName; } + public static bool IsThisWayALine(List tags, List nodeIDs) + { + bool isALine = true; + bool startAndEndCoincide = false; + + try + { + if (nodeIDs[0] == nodeIDs[nodeIDs.Count - 1]) + { + startAndEndCoincide = true; + isALine = false; + } + else + { + startAndEndCoincide = false; + } + + // coastlines are special cases and we will accept them as lines only + //bool isCoastline = false; + + tag coastlineTag = new tag(); + coastlineTag.k = "natural"; + coastlineTag.v = "coastline"; + + + tag areaTag = new tag(); + areaTag.k = "area"; + areaTag.v = "yes"; + + tag highwayTag = new tag(); + highwayTag.k = "highway"; + highwayTag.v = "something"; + + tag routeTag = new tag(); + routeTag.k = "type"; + routeTag.v = "route"; + + tag serviceParkingTag = new tag(); + serviceParkingTag.k = "service"; + serviceParkingTag.v = "parking_aisle"; + + //if (tags.Contains(coastlineTag, new TagKeyValueComparer())) + //{ + // isCoastline = true; + // isALine = true; + // return isALine; + //} + + if (tags.Contains(highwayTag, new TagKeyComparer())) + { + if (tags.Contains(serviceParkingTag, new TagKeyValueComparer())) + { } // do nothing + else + isALine = true; + } + + if (tags.Contains(areaTag, new TagKeyValueComparer())) + { + if (startAndEndCoincide) + isALine = false; + else + isALine = true; + } + + if (tags.Contains(routeTag, new TagKeyValueComparer())) + { + isALine = true; + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine(ex.Message); + System.Diagnostics.Debug.WriteLine(ex.StackTrace); + } + + return isALine; + } + public static bool IsThisWayALine(way currentway) { bool isALine = true; + bool startAndEndCoincide = false; try { @@ -4455,11 +7575,12 @@ public static bool IsThisWayALine(way currentway) { if (currentway.nd[0].@ref == currentway.nd[currentway.nd.Length - 1].@ref) { + startAndEndCoincide = true; isALine = false; } else { - isALine = true; + startAndEndCoincide = false; } } @@ -4481,6 +7602,10 @@ public static bool IsThisWayALine(way currentway) highwayTag.k = "highway"; highwayTag.v = "something"; + tag serviceParkingTag = new tag(); + serviceParkingTag.k = "service"; + serviceParkingTag.v = "parking_aisle"; + if (currentway.tag.Contains(coastlineTag, new TagKeyValueComparer())) { isCoastline = true; @@ -4490,14 +7615,22 @@ public static bool IsThisWayALine(way currentway) if (currentway.tag.Contains(highwayTag, new TagKeyComparer())) { - isALine = true; + if (currentway.tag.Contains(serviceParkingTag, new TagKeyValueComparer())) + {} // do nothing + else + isALine = true; } if (currentway.tag.Contains(areaTag, new TagKeyValueComparer())) { if (isCoastline == false) { - isALine = false; + // only consider the area=yes combination if the way closes onto itself + // otherwise it is most likely an attribute error + if (startAndEndCoincide) + isALine = false; + else + isALine = true; } } } @@ -4575,6 +7708,56 @@ internal List SplitOSMIDRequests(List osmElements, int extensionVe return osmIDRequests; } + internal List SplitOSMIDRequests(List nodeIDs) + { + List osmIDRequests = new List(); + + if (nodeIDs == null) + return osmIDRequests; + + if (nodeIDs.Count == 0) + return osmIDRequests; + + try + { + StringBuilder newQueryString = new StringBuilder(); + newQueryString.Append("("); + + foreach (string nodeID in nodeIDs) + { + newQueryString.Append("'"); + newQueryString.Append(nodeID); + newQueryString.Append("'"); + newQueryString.Append(","); + + // not too sure about this hard coded length of 2048 + // since the SQL implementation is data source dependent + if (newQueryString.Length > 2048) + { + newQueryString = newQueryString.Remove(newQueryString.Length - 1, 1); + + newQueryString.Append(")"); + osmIDRequests.Add(newQueryString.ToString()); + + newQueryString = new StringBuilder(); + newQueryString.Append("("); + } + } + + if (newQueryString.Length > 2) + { + newQueryString = newQueryString.Remove(newQueryString.Length - 1, 1); + newQueryString.Append(")"); + osmIDRequests.Add(newQueryString.ToString()); + } + } + catch + { + } + + return osmIDRequests; + } + // split to node ids into manageable chunks of db requests internal List SplitOSMIDRequests(ESRI.ArcGIS.OSM.OSMClassExtension.way currentway, int extensionVersion) { @@ -4790,6 +7973,12 @@ internal esriGeometryType determineRelationGeometryType(IFeatureClass osmLineFea // or guarantuee that the geometry is indeed a 'polygon' return detectedGeometryType; } + + if ((currentTag.v.ToUpper().Equals("ROUTE")) || (currentTag.v.ToUpper().Equals("ROUTE_MASTER")) || (currentTag.v.ToUpper().Equals("NETWORK"))) + { + detectedGeometryType = esriGeometryType.esriGeometryPolyline; + return detectedGeometryType; + } } // consider administrative boundaries as polygonal in their type else if (currentTag.k.ToUpper().Equals("BOUNDARY")) @@ -5019,4 +8208,186 @@ private osmRelationGeometryType walkRelationGeometry(IFeatureClass osmLineFeatur return testedGeometry; } } + + /// + /// Adaptation from the implementation at + /// https://code.google.com/p/tambon/source/browse/trunk/AHGeo/GeoHash.cs + /// + static internal class GeoHash + { + private static Char[] _Digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + + private static int _NumberOfBits = 6 * 5; + private static Dictionary _LookupTable = CreateLookup(); + + private static Dictionary CreateLookup() + { + + Dictionary result = new Dictionary(); + Int32 i = 0; + + foreach (Char c in _Digits) + { + result[c] = i; + i++; + } + + return result; + } + + private static double GeoHashDecode(BitArray bits, double floorValue, double ceilingValue) + { + Double middle = 0; + Double floor = floorValue; + Double ceiling = ceilingValue; + + for (Int32 i = 0; i < bits.Length; i++) + { + middle = (floor + ceiling) / 2; + + if (bits[i]) + { + floor = middle; + } + else + { + ceiling = middle; + } + } + + return middle; + } + + private static BitArray GeoHashEncode(double value, double floorValue, double ceilingValue) + { + BitArray result = new BitArray(_NumberOfBits); + Double floor = floorValue; + Double ceiling = ceilingValue; + + for (Int32 i = 0; i < _NumberOfBits; i++) + { + Double middle = (floor + ceiling) / 2; + + if (value >= middle) + { + result[i] = true; + floor = middle; + } + else + { + result[i] = false; + ceiling = middle; + } + } + + return result; + } + + private static String EncodeBase32(String binaryStringValue) + { + StringBuilder buffer = new StringBuilder(); + String binaryString = binaryStringValue; + + while (binaryString.Length > 0) + { + String currentBlock = binaryString.Substring(0, 5).PadLeft(5, '0'); + + if (binaryString.Length > 5) + { + binaryString = binaryString.Substring(5, binaryString.Length - 5); + } + else + { + binaryString = String.Empty; + } + + Int32 value = Convert.ToInt32(currentBlock, 2); + buffer.Append(_Digits[value]); + } + + String result = buffer.ToString(); + + return result; + } + + internal static IPoint DecodeGeoHash(String value) + { + StringBuilder lBuffer = new StringBuilder(); + + foreach (Char c in value) + { + if (!_LookupTable.ContainsKey(c)) + { + throw new ArgumentException("Invalid character " + c); + } + + Int32 i = _LookupTable[c] + 32; + lBuffer.Append(Convert.ToString(i, 2).Substring(1)); + } + + BitArray lonset = new BitArray(_NumberOfBits); + BitArray latset = new BitArray(_NumberOfBits); + + //even bits + int j = 0; + + for (int i = 0; i < _NumberOfBits * 2; i += 2) + { + Boolean isSet = false; + + if (i < lBuffer.Length) + { + isSet = lBuffer[i] == '1'; + } + + lonset[j] = isSet; + j++; + } + + //odd bits + j = 0; + + for (int i = 1; i < _NumberOfBits * 2; i += 2) + { + Boolean isSet = false; + + if (i < lBuffer.Length) + { + isSet = lBuffer[i] == '1'; + } + + latset[j] = isSet; + j++; + } + + double longitude = GeoHashDecode(lonset, -180, 180); + double latitude = GeoHashDecode(latset, -90, 90); + + IPoint pointResult = new PointClass() { X = longitude, Y = latitude }; + + return pointResult; + } + + internal static String EncodeGeoHash(IPoint data, Int32 accuracy) + { + BitArray latitudeBits = GeoHashEncode(data.Y, -90, 90); + BitArray longitudeBits = GeoHashEncode(data.X, -180, 180); + + StringBuilder buffer = new StringBuilder(); + + for (Int32 i = 0; i < _NumberOfBits; i++) + { + buffer.Append((longitudeBits[i]) ? '1' : '0'); + buffer.Append((latitudeBits[i]) ? '1' : '0'); + } + + String binaryValue = buffer.ToString(); + String result = EncodeBase32(binaryValue); + + result = result.Substring(0, accuracy); + return result; + } + } } \ No newline at end of file diff --git a/src/OSMGeoProcessing/Properties/AssemblyInfo.cs b/src/OSMGeoProcessing/Properties/AssemblyInfo.cs index 3b9163c..05d89c2 100644 --- a/src/OSMGeoProcessing/Properties/AssemblyInfo.cs +++ b/src/OSMGeoProcessing/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ESRI")] [assembly: AssemblyProduct("ArcGIS Editor for OpenStreetMap")] -[assembly: AssemblyCopyright("Copyright © ESRI 2010 - 2012")] +[assembly: AssemblyCopyright("Copyright © ESRI 2010 - 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/OSMGeoProcessing/gp_documentation/osmgpmultiloader.xml b/src/OSMGeoProcessing/gp_documentation/osmgpmultiloader.xml new file mode 100644 index 0000000..ef07f3f --- /dev/null +++ b/src/OSMGeoProcessing/gp_documentation/osmgpmultiloader.xml @@ -0,0 +1,50 @@ +20151026095213001.0TRUE20151026154608001500000005000ItemDescription<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>OpenStreetMap file containing the data (nodes, ways, relations) to load in XML format.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>OpenStreetMap file containing the data (nodes, ways, relations) to load in XML format.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The name of tag keys to be loaded as attributes for point features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The name of tag keys to be loaded as attributes for point features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The name of tag keys to be loaded as attributes for line features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The name of tag keys to be loaded as attributes for line features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The name of tag keys to be loaded as attributes for polygon features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The name of tag keys to be loaded as attributes for polygon features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Indicates if the nodes without tags are kept as points.</SPAN></P><UL><LI><P><SPAN>DELETE_NODES - Nodes without tags, as indicated by osmSupportingElement = 'yes', are deleted.</SPAN></P></LI><LI><P><SPAN>DO_NOT_DELETE_NODES - All nodes are kept as points. This is the default.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Indicates if the nodes without tags are kept as points.</SPAN></P><UL><LI><P><SPAN>DELETE_NODES - Nodes without tags, as indicated by osmSupportingElement = 'yes', are deleted.</SPAN></P></LI><LI><P><SPAN>DO_NOT_DELETE_NODES - All nodes are kept as points. This is the default.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Indicates if the source OpenStreetMap file is deleted during the loading process.</SPAN></P><UL><LI><P><SPAN>DELETE_OSM_FILE - After the subfiles for data loading are created the source file is deleted to free disk space.</SPAN></P></LI><LI><P><SPAN>DO_NOT_DELETE_OSM_FILE - The source file is maintened and it is available after the loading process. This is the default.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Indicates if the source OpenStreetMap file is deleted during the loading process.</SPAN></P><UL><LI><P><SPAN>DELETE_OSM_FILE - After the subfiles for data loading are created the source file is deleted to free disk space.</SPAN></P></LI><LI><P><SPAN>DO_NOT_DELETE_OSM_FILE - The source file is maintened and it is available after the loading process. This is the default.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Name of the output point feature class. This feature class contains the OpenStreetMap node elements.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Name of the output point feature class. This feature class contains the OpenStreetMap node elements.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Name of the output line feature class. This feature class contains way and relation elements.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Name of the output line feature class. This feature class contains way and relation elements.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Name of the output polygon feature class. This feature class contains way and relation elements.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Name of the output polygon feature class. This feature class contains way and relation elements.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This tool loads data from a OpenStreetMap XML file into a geodatabase and creates points, line, and polygon features from the content. </SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><UL><LI><P><SPAN>Data loaded with this tool is for consumption within the ArcGIS platform only. Due to the absence of the OpenStreetMap metadata information, local data changes or updates will not synchronize back to the OpenStreetMap server. If syncronization with the OpenStreetMap server is required please use the </SPAN><SPAN STYLE="font-weight:bold;">Load OSM File</SPAN><SPAN>tool.</SPAN></P></LI><LI><P><SPAN>Data loading is a I/O intensive operation. Geoprocessing background processing is recommended to keep the application responsive for user interaction.</SPAN></P></LI><LI><P><SPAN>The tool spins up multiple Python processes for data loading. The tool uses the Parallel Processing Factor of the geoprocessing environment to determine how many processes are used for the data loading. Please refer to the environment documentation for a detailed explanation on how to change the values.</SPAN></P></LI><LI><P><SPAN>The tool will split the original OSM file into subfiles for node, ways, and relations. The number of files is determined by the Parallel Processing Factor mentioned above. The location of the file is determined by the Scratch Workspace environment setting. Please ensure that there is an appropriate amount of disk space available to store the files. The Scratch Workspace stores the split files as well as temporary file geodatabases containing points, lines, and polygons during the loading process. As an estimate reserve about 2 times the size of the original OSM file for the Scratch Workspace. If the Scratch Workspace and the target file geodatabase are on the same disk reserve about 2.5 times the size of the source OSM file. Consider having the Scratch Workspace and target geodatabase on different disks for better I/O performance.</SPAN></P></LI><LI><P><SPAN>The tool uses attribute indexing. Ensure that you have appropriate amount of disk space in the machines TEMP folder.</SPAN></P></LI><LI><P><SPAN>Streamline the loading of tags into attributes. If no tags are provided for nodes, ways, or lines a set of default tags is used, The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></LI><LI><P><SPAN>The full set of tags is always stored in the osmTags blob field. Use the </SPAN><SPAN STYLE="font-weight:bold;">OSM Attribute Selector</SPAN><SPAN>tool to extract additional attributes after the loading process.</SPAN></P></LI></UL></DIV></DIV></DIV>Loading using default attributes<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This example loads the OpenStreetMap extract for Lichtenstein using the the default list of tags as attributes and deletes nodes without tags.</SPAN></P></DIV></DIV></DIV># load the arcpy module +import arcpy + +# load the OpenStreetMap toolbox +arcpy.ImportToolbox(r'C:\Program Files (x86)\ArcGIS\Desktop10.3\ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx') + +# target point feature class +point_fc = r'D:\OSM\country.gdb\liechtenstein_pt' + +# target line feature class +line_fc = r'D:\OSM\country.gdb\liechtenstein_ln' + +# target polygon feature class +polygon_fc = r'D:\OSM\country.gdb\liechtenstein_ply' + +# OpenStreetMap XML file +osm_source = r'D:\OSM\liechtenstein-latest.osm' + +# load the data for Liechtenstein, delete the nodes without tags and leave +# everything else as the default +arcpy.OSMGPMultiLoader_osmtools(osm_source, '#', '#', '#', 'DELETE_NODES', + 'DO_NOT_DELETE_OSM_FILE', point_fc, line_fc, polygon_fc) Loading using custom attribute selection<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This example loads the OpenStreetMap extract for Lichtenstein using a separate scratch workspace and custom lists for the attribute loading.</SPAN></P></DIV></DIV></DIV># load the arcpy module +import arcpy + +# load the OpenStreetMap toolbox +arcpy.ImportToolbox(r'C:\Program Files (x86)\ArcGIS\Desktop10.3\ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx') + +# target point feature class +point_fc = r'D:\OSM\country.gdb\liechtenstein_pt' + +# target line feature class +line_fc = r'D:\OSM\country.gdb\liechtenstein_ln' + +# target polygon feature class +polygon_fc = r'D:\OSM\country.gdb\liechtenstein_ply' + +# OpenStreetMap XML file +osm_source = r'D:\OSM\liechtenstein-latest.osm' + +# define a scratchWorkspace to store the subfiles and temporary fgdbs +arcpy.env.scratchWorkspace = r'c:\scratch' + +# define custom listing for tags to extract +node_keys = 'name;operator' +line_keys = 'name;highway;route' +polygon_keys = 'name;boundary;type;natural' + +# load the data for Liechtenstein with custom set of tags +arcpy.OSMGPMultiLoader_osmtools(osm_source, node_keys, line_keys, polygon_keys, + out_osmPoints=point_fc, out_osmLines=line_fc, out_osmPolygons=polygon_fc) OSM File Loader (Load only)OpenStreetMapesriApplications Prototype Labopen dataOSM<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This tool loads data from a OpenStreetMap XML file into a geodatabase and creates points, line, and polygon features from the content. </SPAN></P></DIV></DIV></DIV>ArcToolbox Tool diff --git a/src/OSMGeoProcessing/gp_documentation/osmgpnodeloader.xml b/src/OSMGeoProcessing/gp_documentation/osmgpnodeloader.xml new file mode 100644 index 0000000..533de1f --- /dev/null +++ b/src/OSMGeoProcessing/gp_documentation/osmgpnodeloader.xml @@ -0,0 +1,14 @@ +20151026133804001.0TRUE20151106134901001500000005000ItemDescription<DIV STYLE="text-align:Left;"><DIV><P><SPAN>OpenStreetMap file containg the node elements to load in XML format.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>OpenStreetMap file containg the node elements to load in XML format.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>The name of tag keys to be loaded as attributes for point features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>The name of tag keys to be loaded as attributes for point features. If no names are given the tool uses a default set of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Use this option for a recycling cursor to insert features into the geodatabase.</SPAN></P><UL><LI><P><SPAN>DO_NOT_USE_CACHE Do not use a recycling cursor to insert nodes into the geodatabase. All fields are written for each feature. This is the default.</SPAN></P></LI><LI><P><SPAN>USE_CACHE Use a recycling cursor to insert nodes into the geodatabase. Only the osmTags and osmSupportingElement fields is written for each feature and the other field attributes as needed, meaning that not all field values are reset for each feature, only the values that are needed for the current feature. This can lead to attribute values that are 'shared' across features. This might be incorrect but the data loading is faster. Only features where the osmSupportingElement value is 'no' will have the correct attributes.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Use this option for a recycling cursor to insert features into the geodatabase.</SPAN></P><UL><LI><P><SPAN>DO_NOT_USE_CACHE Do not use a recycling cursor to insert nodes into the geodatabase. All fields are written for each feature. This is the default.</SPAN></P></LI><LI><P><SPAN>USE_CACHE Use a recycling cursor to insert nodes into the geodatabase. Only the osmTags and osmSupportingElement fields is written for each feature and the other field attributes as needed, meaning that not all field values are reset for each feature, only the values that are needed for the current feature. This can lead to attribute values that are 'shared' across features. This might be incorrect but the data loading is faster. Only features where the osmSupportingElement value is 'no' will have the correct attributes.</SPAN></P></LI></UL></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Name of the output point feature class. This feature class contains the OpenStreetMap node elements.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Name of the output point feature class. This feature class contains the OpenStreetMap node elements.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This tool loads nodes from a OpenStreetMap XML file into a geodatabase and creates point features from the content.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><UL><LI><P><SPAN>The tool is used in combination with the </SPAN><SPAN STYLE="font-weight:bold;">OSM File Loader</SPAN><SPAN>tool.</SPAN></P></LI><LI><P><SPAN>The tool only processes the node elements from the OpenStreetMap source file.</SPAN></P></LI><LI><P><SPAN>Streamline the loading of tags into attributes. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></LI></UL></DIV></DIV></DIV>Loading node element with default attribute set<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Load the node elements from the OpenStreetMap XML file into a point feature class.</SPAN></P></DIV></DIV></DIV># load the arcpy module +import arcpy + +# load the OpenStreetMap toolbox +arcpy.ImportToolbox(r'C:\Program Files (x86)\ArcGIS\Desktop10.3\ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx') + +# target point feature class +point_fc = r'D:\OSM\country.gdb\liechtenstein_pt' + +# OpenStreetMap XML file +osm_source = r'D:\OSM\liechtenstein-nodes.osm' + +# load the node elements into points for Liechtenstein +arcpy.OSMGPNodeLoader_osmtools(osm_source, '#', 'DO_NOT_USE_CACHE', point_fc) OSM Node Loader<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This tool loads nodes from a OpenStreetMap XML file into a geodatabase and creates point features from the content.</SPAN></P></DIV></DIV></DIV>OpenStreetMapesriApplications Prototype Labopen dataOSMArcToolbox Tool diff --git a/src/OSMGeoProcessing/gp_documentation/osmgprelationloader.xml b/src/OSMGeoProcessing/gp_documentation/osmgprelationloader.xml new file mode 100644 index 0000000..47a82ad --- /dev/null +++ b/src/OSMGeoProcessing/gp_documentation/osmgprelationloader.xml @@ -0,0 +1,24 @@ +20151026154037001.0TRUE20151106135958001500000005000ItemDescription<DIV STYLE="text-align:Left;"><DIV><P><SPAN>OpenStreetMap file containing the relation elements to load in the XML format.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>OpenStreetMap file containing the relation elements to load in the XML format.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>The parameter determines what types of relations, either relations or super-relations are loaded.</SPAN></P><UL><LI><P><SPAN>DO_NOT_LOAD_SUPER_RELATION Only load the relations composed of ways. This is the default.</SPAN></P></LI><LI><P><SPAN>LOAD_SUPER_RELATION Only super-relations composed of ways and relations are loaded. This option should only be used after the relations have been loaded.</SPAN></P></LI></UL></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>The parameter determines what types of relations, either relations or super-relations are loaded.</SPAN></P><UL><LI><P><SPAN>DO_NOT_LOAD_SUPER_RELATION Only load the relations composed of ways. This is the default.</SPAN></P></LI><LI><P><SPAN>LOAD_SUPER_RELATION Only super-relations composed of ways and relations are loaded. This option should only be used after the relations have been loaded.</SPAN></P></LI></UL></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Source line feature class representing the already loaded ways and relations. The lines were loaded with the </SPAN><SPAN STYLE="font-weight:bold;">OSM Way Loader</SPAN><SPAN> tool.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Source line feature class representing the already loaded ways and relations. The lines were loaded with the </SPAN><SPAN STYLE="font-weight:bold;">OSM Way Loader</SPAN><SPAN> tool.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Source polygon feature class representing the already loaded ways and relations. The polygons were loaded with the </SPAN><SPAN STYLE="font-weight:bold;">OSM Way Loader</SPAN><SPAN> tool.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Source polygon feature class representing the already loaded ways and relations. The polygons were loaded with the </SPAN><SPAN STYLE="font-weight:bold;">OSM Way Loader</SPAN><SPAN> tool.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Streamline the loading of relation tags into attributes for linear features. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Streamline the loading of relation tags into attributes for linear features. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Streamline the loading of relation tags into attributes for polygon features. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Streamline the loading of relation tags into attributes for polygon features. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Name of the output line feature class. This feature class contains the relation elements determined to represent a line feature.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Name of the output line feature class. This feature class contains the relation elements determined to represent a line feature.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Name of the output polygon feature class. This feature class contains the relation elements determined to represent a polygon feature.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Name of the output polygon feature class. This feature class contains the relation elements determined to represent a polygon feature.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This tool loads relations from a OpenStreetMap XML file into a geodatabase and creates line and polygon features from the content.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><UL><LI><P><SPAN>The tool is used in combination with the </SPAN><SPAN STYLE="font-weight:bold;">OSM File Loader</SPAN><SPAN>tool.</SPAN></P></LI><LI><P><SPAN>The tool tool only processes the relation elements from the OpenStreetMap source file. It is assumed that the ways already exist as line and polygon features.</SPAN></P></LI><LI><P><SPAN>The tool processes &lt;way&gt; and &lt;relation&gt; item elements for the &lt;relation&gt; element. In order for the relation to be loaded and have a geometric representation is needs to be either a line or a polygon feature.</SPAN></P></LI><LI><P><SPAN>If a tag &lt;tag k='type' v='route' /&gt; exists then the resulting geometry is a line. In other cases the resulting geometry depends on the geometry type of the way item or the connectedness of all way items.</SPAN></P></LI><LI><P><SPAN>Streamline the loading of tags into attributes. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></LI></UL></DIV></DIV></DIV>Loading relation elements to <DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Load the relation elements from the OpenStreetMap XML file into line and polygon feature classes. The source line and polygon feature classes are already loaded by using the </SPAN><SPAN STYLE="font-weight:bold;">OSM Way Loader</SPAN><SPAN>tool.</SPAN></P></DIV></DIV></DIV># load the arcpy module +import arcpy + +# load the OpenStreetMap toolbox +arcpy.ImportToolbox(r'C:\Program Files (x86)\ArcGIS\Desktop10.3\ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx') + +# source line feature class +source_line_fc = r'D:\OSM\country.gdb\liechtenstein_ln' + +# source polygon feature class +source_polygon_fc = r'D:\OSM\country.gdb\liechtenstein_ply' + +# target line feature class +target_line_fc = r'D:\OSM\country.gdb\liechtenstein_r_ln' + +# target polygon feature class +target_polygon_fc = r'D:\OSM\country.gdb\liechtenstein_r_ply' + +# OpenStreetMap XML file +osm_source = r'D:\OSM\liechtenstein-relations.osm' + +# load the relation elements into lines and polygons for Liechtenstein +arcpy.OSMGPRelationLoader_osmtools(osm_source, 'DO_NOT_LOAD_SUPER_RELATION', source_line_fc, source_polygon_fc, + '#', '#', target_line_fc, target_polygon_fc)OSM Relation Loader<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This tool loads relations from a OpenStreetMap XML file into a geodatabase and creates line and polygon features from the content.</SPAN></P></DIV></DIV></DIV>OpenStreetMapesriApplications Prototype Labopen dataOSMArcToolbox Tool diff --git a/src/OSMGeoProcessing/gp_documentation/osmgpwayloader.xml b/src/OSMGeoProcessing/gp_documentation/osmgpwayloader.xml new file mode 100644 index 0000000..6718398 --- /dev/null +++ b/src/OSMGeoProcessing/gp_documentation/osmgpwayloader.xml @@ -0,0 +1,20 @@ +20151026154506001.0TRUE20151026160940001500000005000ItemDescription<DIV STYLE="text-align:Left;"><DIV><P><SPAN>OpenStreetMap file containing the way elements to load in XML format.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>OpenStreetMap file containing the way elements to load in XML format.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Source point feature class representing the already loaded nodes. The geometry of the &lt;nd&gt; elements of the way are sourced from this feature class by the &lt;id&gt; of the node.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Source point feature class representing the already loaded nodes. The geometry of the &lt;nd&gt; elements of the way are sourced from this feature class by the &lt;id&gt; of the node.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Streamline the loading of line tags into attributes. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Streamline the loading of line tags into attributes. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Streamline the loading of polygon tags into attributes. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Streamline the loading of polygon tags into attributes. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Name of the output line feature class. This feature class contains the way elements determined to represent a line feature.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Name of the output line feature class. This feature class contains the way elements determined to represent a line feature.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Name of the output polygon feature class. This feature class contains the way elements determined to represent a polygon feature.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Name of the output polygon feature class. This feature class contains the way elements determined to represent a polygon feature.</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>This tool loads way elements from a OpenStreetMap XML File into a geodatabase and creates line and polygon features from the content.</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><UL><LI><P><SPAN>The tool is used in combination with the </SPAN><SPAN STYLE="font-weight:bold;">OSM File Loader</SPAN><SPAN> tool.</SPAN></P></LI><LI><P><SPAN>The tool only processes the way elements from the OpenStreetMap source file. It is assumed that the nodes already exist as a point feature class.</SPAN></P></LI><LI><P><SPAN>Streamline the loading of tags into attributes. If no tags are provided, a set of default tags is used. The default set consists of ('name', 'highway', 'building', 'natural', 'waterway', 'amenity', 'landuse', 'place', 'railway', 'boundary','power','leisure','man_made', 'shop', 'tourism', 'route', 'barrier', 'surface', 'type', 'service', 'sport').</SPAN></P></LI></UL></DIV></DIV>Loading ways into line and polygon feature classes.<DIV STYLE="text-align:Left;"><DIV><P><SPAN>Load the way elements from the OpenStreetMap XML file into line and polygon feature classes. The source point feature class is already loaded by using the </SPAN><SPAN STYLE="font-weight:bold;">OSM Node Loader</SPAN><SPAN> tool.</SPAN></P></DIV></DIV># load the arcpy module +import arcpy + +# load the OpenStreetMap toolbox +arcpy.ImportToolbox(r'C:\Program Files (x86)\ArcGIS\Desktop10.3\ArcToolbox\Toolboxes\OpenStreetMap Toolbox.tbx') + +# source point feature class +source_points_fc = r'D:\OSM\country.gdb\liechtenstein_pt' + +# target line feature class +line_fc = r'D:\OSM\country.gdb\liechtenstein_ln' + +# target polygon feature class +polygon_fc = r'D:\OSM\country.gdb\liechtenstein_ply' + +# OpenStreetMap XML file +osm_source = r'D:\OSM\liechtenstein-ways.osm' + +# load the way elements into lines and polygons for Liechtenstein +arcpy.OSMGPWayLoader_osmtools(osm_source, source_points_fc, '#', '#', line_fc, polygon_fc) OSM Way Loader<DIV STYLE="text-align:Left;"><DIV><P><SPAN>This tool loads way elements from a OpenStreetMap XML File into a geodatabase and creates line and polygon features from the content.</SPAN></P></DIV></DIV>OpenStreetMapesriApplications Prototype Labopen dataOSMArcToolbox Tool diff --git a/src/OSMGeoprocessing64/OSMGeoprocessing64.csproj b/src/OSMGeoprocessing64/OSMGeoprocessing64.csproj index ad1b6bb..943cec8 100644 --- a/src/OSMGeoprocessing64/OSMGeoprocessing64.csproj +++ b/src/OSMGeoprocessing64/OSMGeoprocessing64.csproj @@ -10,7 +10,7 @@ Properties ESRI.ArcGIS.OSM.GeoProcessing OSMGeoprocessing64 - v3.5 + v4.5 512 @@ -20,6 +20,7 @@ + x86 @@ -30,6 +31,7 @@ DEBUG;TRACE prompt 4 + false x86 @@ -39,6 +41,7 @@ TRACE prompt 4 + false @@ -56,6 +59,7 @@ MinimumRecommendedRules.ruleset ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false bin\Release\ @@ -72,6 +76,7 @@ false ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules false + false @@ -150,6 +155,15 @@ OSMGPFileLoader.cs + + OSMGPMultiLoader.cs + + + OSMGPNodeLoader.cs + + + OSMGPRelationLoader.cs + OSMGPRemoveExtension.cs @@ -159,6 +173,9 @@ OSMGPUpload.cs + + OSMGPWayLoader.cs + OsmRest\HttpUtils.cs @@ -179,67 +196,67 @@ - + False False - True + False - + False False - + False False - True + False - + False False - True + False - + False False - True + False - + False False - True + False - + False False - True + False - + False False - True + False - + False False - True + False - + False - True + False - + False False - + False False - True + False - + False False - True + False False diff --git a/src/OSMUtilities/OSMUtilities.csproj b/src/OSMUtilities/OSMUtilities.csproj index 73097a3..df8ca8f 100644 --- a/src/OSMUtilities/OSMUtilities.csproj +++ b/src/OSMUtilities/OSMUtilities.csproj @@ -10,7 +10,7 @@ Properties ESRI.ArcGIS.OSM.OSMUtilities OSMUtilities - v3.5 + v4.5 512 @@ -20,6 +20,7 @@ + true @@ -30,6 +31,7 @@ prompt 4 x86 + false pdbonly @@ -38,6 +40,7 @@ TRACE prompt 4 + false diff --git a/src/OSMUtilities/Properties/AssemblyInfo.cs b/src/OSMUtilities/Properties/AssemblyInfo.cs index c05b118..3e9427e 100644 --- a/src/OSMUtilities/Properties/AssemblyInfo.cs +++ b/src/OSMUtilities/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ESRI")] [assembly: AssemblyProduct("OSMUtilities")] -[assembly: AssemblyCopyright("Copyright © ESRI 2012")] +[assembly: AssemblyCopyright("Copyright © ESRI 2010 - 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/OSMUtilities/SyncState.cs b/src/OSMUtilities/SyncState.cs index eb5d93b..cbf678b 100644 --- a/src/OSMUtilities/SyncState.cs +++ b/src/OSMUtilities/SyncState.cs @@ -1,4 +1,4 @@ -// (c) Copyright Esri, 2010 - 2013 +// (c) Copyright Esri, 2010 - 2016 // This source is subject to the Apache 2.0 License. // Please see http://www.apache.org/licenses/LICENSE-2.0.html for details. // All other rights reserved. diff --git a/src/OSMUtilities64/OSMUtilities64.csproj b/src/OSMUtilities64/OSMUtilities64.csproj index 2ef1fef..89d7a52 100644 --- a/src/OSMUtilities64/OSMUtilities64.csproj +++ b/src/OSMUtilities64/OSMUtilities64.csproj @@ -10,7 +10,7 @@ Properties ESRI.ArcGIS.OSM.OSMUtilities OSMUtilities64 - v3.5 + v4.5 512 @@ -31,6 +31,7 @@ prompt 4 x64 + false pdbonly @@ -39,6 +40,7 @@ TRACE prompt 4 + false diff --git a/src/buildLanguages.bat b/src/buildLanguages.bat index cf27e2e..72723c9 100644 --- a/src/buildLanguages.bat +++ b/src/buildLanguages.bat @@ -20,7 +20,7 @@ cd .. rem then let's go build all aditional languages -set OSMEditorVersion=2.3.0.0 +set OSMEditorVersion=2.4.0.0 cd OSMGeoProcessing\languages diff --git a/src/data/OpenStreetMap Toolbox.tbx b/src/data/OpenStreetMap Toolbox.tbx index 06683749cd0d36a438bc6a1ab10663c43e76f6cd..459ec8961b6dfdf34c26498f2896f3e9ffa0eebb 100644 GIT binary patch delta 9168 zcmeI&33wBA-oWvhBt7Xly*WyNfGtqkavv?W+{i5;uz*lXfv%-3?UYNT1@Q->lq0|d zjRq?ot1c^|jYp+;?5-#xu)FHIqM)wp0f?)3V4?4Kk`@r&^*!8upZ9&9H+eqE%>SDI zmC1iHsoJ_Zsj6;s(x$BFP(@Kx)MqM6An(@AdG|Yy$A$%Fv6HPhhxPJ3*y?LuQ?=h?7{s^%~GO=m@Tr8>xY zme+pHiU?nH#6&g97j4WQkZf}~^Nil|C8)p<5*TtEbMjQ5um z?5v2cRF62%Mvo0tV+fD)hi`ILXk(p&gStDA4MVx(a_)Pg$mnro;1;xk`aj zM(m{&_NI9I6)7T}o0Afvm-zCQ`>IJcrMppCa zr_&t%OU<~RsuximT`8m~#aC4KQd+xmWy&j?7Hc-GRoNBgU20^euaVO(6>0Y3m4*Je zKQE>IPaZz{s>A!bV1{Q~8;3PI>GIO;O3KB?+MSh&2?NH`0p>_vp2|P{{M}_&np0fa z^eD6GG0m};nw()aId$lz-fm9v-#kP}bN+IFvnq$#6szyUap@3alnMq^_nnT-;Wj@y zSH~7!(aKgAQ`wbaOobx);m57~QGfZSN|6%1Oi3l<0yMSA__9XgDwj}#PH+iz(J9B= zHp^SctM2=}m=i9K`EOT-_$FT-TScVzf0pL5cXb*5lUq4)`J^l6S>h{wj<4(rrL?(( z2m;I^=8!C3xye(R>98hwT4y_~VV>Oy4r{QQ?wgAX|CN37f3Is+bDEeDXpWGgJP|+C z;tXgxU~g4omFlVD)02|$1K|xgj|*r7(`;{J(xPc`$Kn;`J-m>!Pco zTST{tZWBE~^gz*rL=P4{MD$S6TZkSedbsEjqDP7zC3>{zn&>g2$BG^&dc5cfq9=-; zBzjBHTZ!IU^fsa=i{4gryXfsiZ!dZW(H)|96upz^*NC1XdaCH1Meibd*IGTT%`mEy z;O$wLc2IR@1o!p!txJ1(vh#7(JjG`Qck$*}rtMcn>n2*dXc?kqiq>7U9-{RWt(R!M zMe8G4U(x!B)?c&%qGgGeE!sfQt`#juv|P~!i8ffYA)*ZxZJ21oMH?a7NYSnnZIo!E zMH?g9SkcCbHeR#|qFpcAMA0URHd(YAM4M8pO`Un#JJUApezn#%txk)3oMp})Jb}G< z6298rdm_;?V(pNGY4`=EV+Lm8M$E!&z*UjQuQR}+pz&!5(%gR1#t!3p$0deQ3 z{tsxtd0a59{XS?VDpBSAK4{f_Cq4Gw4r`qe|Lv+rqAstZx$TYmZq=sX*i_ot8C}p7 zW^1-Rxq6*t{9t3=;{4bu3VS}eDUWsO*FtF=h>1S5O0yi_|$Zn9V> z(PM`!wqa$lLI_ahY~H(M(HgQ@69R@yB2&?!Lsbdc|{e*o@1+$ zjd4pQ)cAC^1B``BrHzq2_hdwP;qrq1nHi;e z`%d%q0mk8#($#1;Tv{2&OC`=Yvs60xl7(DMW=yD*DMsl^8Sq~#`QS1NJz8{C$wtQ| z5@`%tE_?oi@>*T2f?3o2lHzi`tRmkWq3q7aiFwl6NLnuO|G1^`Kgz$LaQ=cNdCSPU zXRTy=c6O^$OTE{vkoKyty=JZY{C~gxoPN!lcXFU-_Q6Dp!<)TYz6vl7Pt8v@2CtJH z-oxu;i*44zxg*L(FCLgRF~6j=VDMbKIfDzb+h=6-YCkY5y(yHf=5*-`3-r9Xd3xT! z@K8ma$)!*spZii4J7vD*j=4-S7eM9`EnEpThHqq!S8tHMM(8F!5eGNOJ4Q{l^fn@P zNU-sCwUnA$$;Rr9GRWA!QO5csA~wmp{;kh8NuqIKlMM6idWUS5P}Oj4mM~-L7RmW> znndH}Ez;Q^M#9z)g*rtwcRLv=TP4L85u{VoWlDczvzwY}+nBONTculzTuyP5sPs}r z_eBL1D)SV(5xq^?B-v@Cxw30s)0qq1V$%8w>1dqZDhrH^?P4>|Y?r7OzKp&OC^qhM zNm6(!S+jZCm7e}AX-$Rax+K%6-X_(mucTf^=vKO-=MJj6e7ihu78hnj+$H^uxrWU1 z@4jl#Wz7dmyj0NhSC;Y4#q92%$l300`Ekxzw;a8gGuSxomY>S5-Yd^td0@M-#VuKe z=8=ch_GVvZ^LD_HMHj0b6=Gi2l{fcb+QoLa?=s%kappIUxg;-VW)(1>%r0HVzHfMV zEjH(x@xnGqXk(5|F;VjgF5$Jz_jR;@(EO$(0qvCbN~&*AeaF2tu+hx}d&Ph@55vE* zI_eII3pd-7PsK}VPt%P2pE|a|2P?|xy;HhPPEpLOB%Noe(qEau#f|ywMtAj+OM*e$C|dSx2i^1zgPEgSabFr zPqf%nuk8Ujd?2m&Vnyi#Rv=10^v3{XAsYi>u4i(1*NkJuYa1=~gT0+f*S@I+)Dq@3 z)Y4OJ)%|PFFItOrxEz+OCwr%($op2jnH7SEv$&to6zVYc%Hyoi_Z zGJcES;rDn22kkD<`ft!OHRIMAv_xIvHC+;7_-5~Ds;=Um6#`SKs+O5I@D{KfrAc7E#5QL%y!Vr!KL?Q~&&=7-I z#33FDNJJ7^q7_=B4U*9ocCVg_B(_OoBt5oxPeS~?%TUT#mx8bO|+0&8vX4sx)?s<;qRH^p*;{>!;1M0(6 zWxq#Von&dN9;iPbw@Q6(x~Gmf<|C)X4%KC=)atU;xD{(~8w6{y4!2`H?!cYcfNE^S zCTzwQII$JmupI_m*nzunH{7@f_rimnxDPeBAG`1X9>ha<7{9_JcodJ}*Vv8U;BoB1 z6WEI<@f2#|#nX5O&*C}M;d$&sJ@(@Tyoi_ZGJcES;rDn22k5+T7{U>ONJJqT8e$NO zIK(5tvac-B@@$c%v61OIcQ@13;>-!Q?PKF>OMT);iIz|9QD3R=$kcpG4Y)R3RdSf8 zEt#hy>(AesWU*dQM|e6C@P_RcB0XP!m}s%re@#HwC0QZdzzRhRgdrReh(r{kVSZu9 z@E(ge#5aX`W}Itj$w+mu+Yy~`4N{Pb&gg=!NW+D_(Uwtabwf)_bwew(MjIrfE$nEA z_UHfyI-(P( z3s8t(;wBVfA&OCgQY-?Kv7sC~DzF$!uoTO%95-VHZox`aq6(|98nV8gD>%Se1)%Z7T@4oe24FG4nLp)=Wzjzmh}zR>IM}SSYbl|0uh8@gdh|x5QcC> zAQDlChK3l#A`bCLKq8XR60Oi0ZIFz%u%jK?TlY0|ux^O=?1^<)+ZacORmJa%<2pn2 z)Ua~w?x~JjSFM zwx6^L4^(;(*7Pvi-S~N?XJ1=~b^Ho zk=jpE{69G+*VhuVAy7>+R@KGCc&2o6SR1U%S<4rnwD3`dp4#xtdoAC0ONxhG1nMv6V`-!Lc2MvQS~*c4r^Jmf2Y#? zi^4y;clXb^J9pI`D6Zj~?_|z1&eurD|N0wsM#QGvSkIZx4r{EM?osK*q;clI4XnO@ z1zftVY5uzKGj81mHRbml;YdAv|J?A{I9U9wmcD~sx)1#?xMv-C#XW0(CDcrRb4QtX fX04a~v*2g`_aMOc*MO#DbT@K~v^Guu6AAh^gxi2L delta 6221 zcmd_ud014{|G@FNGk}2X3<8Rm5yu@B+;?$LGndp-!IH==H!^WcFN^p=ElIiN(Nf1{ zG)o)Jg)z6$w8a*+vc=NUvQ;dtv@+4(8}Qq&`u_g@J>Tc~GSBPYbI_LvuIICl93WouebGbcD# z>ttTz*vibQo~t!6uW_7b=7i*Gd(CShL$t7}@!v6XLUXmc=C#mVmG*pspE)aRZbd}c z5G|@IBGSwW&kbnQ!(#chzj-5kj%G1)B63xp#Q2%NMfCTNUg!5Gbd_*dDNb&1)A5Q2KvX)6kFBQ-pq-nDWHZ3#49_R5kbk7k!D&@oOwDn*>qUv zmc#|_dLyy3)$G-<~8y&|YAOp^0G?!zPBG82(}eh*3?9Krw>E z2o|Hd7$IVWiV-G8xEK*)M2Zn5Mzk1qF=E81Ax5kiabm=aQB#asVkC%BTMS){L@^v< z)Da^|jJjet#i%DneK8t{(NK&=Vl)<`i5SVHM$_88RphFAcJI2> zvE)&^*P0$1R=F(En~C0B^c2xkMQjo#^dF?;v_d(L0IWS@bTV zcNINN^lqYe7rlq*Jw@*&dT-JDh<=yoeMRpl`rV@U7yTa52Z%mU^g*Hz7X4n)hloB@ z^kJgkC;I)R`tVUdcn4?9+*mQeWc!nR0G6N_Phly%X$j2^Yo%c$4n(O_juF{$Z}Ta5 z2Pbe6r|>R{de#|%kw`}dM&SWGh|$QzL*AZsvf}!BTQ+Os);3Sdvd6qk=lwWN?O?y2I=7Wbp#o+j?c#64ZyIpUrn z?wR7ACGOeco+IwZ#XYywJ@5Ef@9}0uZ8b;5=>Ou!^!yQkY6yhau_5ccRvKbl^!Klr z%^Ksw}@&=}tMUMQGhvHEi(1o``~_ zf%b}l8nfOeNJdkr-GK!Qt5vkLnNhi~9F*V!37#*(g%Z4=G*~(hR-O0D(b5c=XstEU zVzG?3Oy`wt>0oKj>k-Q=OD0znRO-dNdNrH>>yoC*YR)N^W|lS<*M+cQTCD5#={RdQ z75kuER_i*a)%5D4<*2`Pesgu<`tY8r!B{!q-!e6&MXKx3j(M8hKebic)-9DbPHL)T zPt(R~^*AX}gS$yvwRMsNd8dq*X@2VIc~V~mOcr~@<2|R&oHA)@=ED#6nl*jQlo3s)NMdTdCJs>$E2&`0;%=q5KR_~H}c;)Ds6^DN2F&> zo$}c9X*pTbCrq8vx$!6!F;QyAJBAD$(Z5&cr2o59_4M%*#*LquIr~n0BUke_PFow- zy0knk+ncdKk~B3To7=fv#Qxv1dUfTS{CeI-Ps-2!$}xfWwo{2H@8=~VekvhdLTy@R zklLigp}tbmO4VK|=asffTBwezB)irG%VZLKs%08!?;xwES+cmE&DT}1I^~u`b$pd{ zSK-e{Kb856oK-<>^BX*VZtTgj(eO7`s+hj|o+P7Nz{Mp*YJ8_L9XzGlctb1{- zG*p^P`b9G+|D@_Q!7`Ro!xb(`46S47OnCs)m|_{D*11{4`z{$@?M{qJaZ9RdzMg!% zv`$2=cQc2l)-tqfyCkV^)=Q~6w@EsvFE_|oHEg3~|Fvg(mFSkje|C!BBzr45t^Rxb z=;x%p8u;A5$M@YLJ1XJ>Rp|5o>{K~D-wU+mz90qv{7<{K%4W4{n@p;>I}s{#hct_C z{I{(p;~yJMe8!&}O~###CZlSjQAb8gtlBY}+aLOpM0tN>&(zf6U6QFXgNqWqX}cv) zTTv=!S9rzG`7&GJKJ3Q<9K<2`a2QA6_4CT9<3SaBWZM}QOOVp?i*ECS!D%h+p+3ng z(gV6uoi@X3EhzesFOj11`9)ZWMOcg{@FbR?7*Am-mZ1bDmg8xxfWk_w!ZUaltFZ=a z;lets#|CVK8=J5h&tVIm#|zksZFmtLY{w3~gq_%h-PnUtRIFhyUdBG`#{nF~A^30@ zNAL=c;uv1VYj_=R;5gpITX-Aq-~>+M6yC*qcps_!wvK2|mSHoWp1M9OrQX zU*Jnz#8>zl-{4z(hwr`R^Dmvf;XQM@tO1FzN7B@#s0CpvEUzp*_6fcT(G<5KZ@syc&>`)C-M9&o?pasO+44d z^Q(A%6VLDBxgnlE#B)I*|p4*E(TCqoi6*l<69|5R_Km;Ke)e(YFgdrReh(r{k zVMh#VAQo|mM@`g10%}7?A{?lLB-Diy^-v!T&=8H#7)_9jrf7!dNI@!Epe0(NHQJyp z+MzuWNFrWN^j~(^VkvQH zG%DBL`T3gDcYtz&rXBW`H^|rar)#&&!GV2>3-h(&!UD`kAr?STgoRjy#drcwVhM`z z6qaHcN?>9+p2i9&ti&ojgJ-cCYp@nBtiyV2z(%;S37hd8w%~cZfUVeu7vaHn?7&Od ziCx%@Jt&12d+{>%VLuMwAP&KY!#ILha1_VzDqh3ucmv1rCf>r^cn2qN5~uJk-oyJi zjSui4KElU1gHP}&&f*+C!{<1U3-|(G;v&An*Z2nC;yZkgODMx-{D2>E1y}JCe#S4j zhU@qhzu|Y>z#q7Ya@@jgZE>NsxKM)?Hu%9G0jP#R1R)sJ5rR;JAsi8iL=>W7M+|Bp z)_SNg&bn`sZ(r|tYj3Tzuxz;IOCe*oXqAcki|h3AnpTIOglZOF-1Ru?w`(+?>l~?> z=>JBDW;yQDmd9H^(zG;R`P1=M+bylD>l}qd|GVhX*QL?>r0*Aw$um1ud^-p8*rYl_ z5Q>VraLy5kL=>W7M+|Bp7OsqtTGkZbZjSvm9uqVy4y$D?4og67=tzVEb&!O*aH1aS zqX8PC5gMZjlF<~+&>Sg9MGLe9+p2i9&ti&ojgJ-cCYp@nBtiyV2z(%;S37hd8w%~cZfUVeu7vaHn?7&Od ziCx%@Jt&12d+{>%VLuMwAP&KY!#ILha1_VzDqh3ucmv1rCf>r^cn2qN5~uJk-oyJi zjSui4KElU1gHP}&&f*+C!{<1U3-|(G;v&An*Z2nC;yZkgODMx-{D2>E1y}JCe#S4j zhU@qhzu|Y>z#q7Ya@@jg>*6q5ahL`xZ196W0#FTs2tqKbBLtzS=ogL%L?Q~&up;ol-PwMF~Nr!}$GmZ^U}s;TR0lL33%A~(F`qDc( VZM$^UZ$^~;uS@(-D0BZJ{s-)$M%MrU diff --git a/src/data/download_using_xapi.py b/src/data/download_using_xapi.py index 6fe3fe9..3347424 100644 --- a/src/data/download_using_xapi.py +++ b/src/data/download_using_xapi.py @@ -1,89 +1,91 @@ # Import system modules and arcpy # -import arcpy, sys, urllib, urllib2 +import arcpy, urllib, urllib2 import locale + def xapidownload(): - try: - # get the input XAPI url - # - in_xapi_url = arcpy.GetParameterAsText(0) - - # get the request extent - # - request_extent = arcpy.GetParameterAsText(1) - AddMsgAndPrint(request_extent) - - # if no extent was set and the default is passed in -- meaning "#" then set an empty string - if (request_extent == '#'): - request_extent = '' - elif (request_extent == 'DEFAULT'): - request_extent = '' - else: - coordinates = request_extent.split(' ') - request_extent = str(locale.atof(coordinates[0])) + ',' + str(locale.atof(coordinates[1])) + ',' + str(locale.atof(coordinates[2])) + ',' + str(locale.atof(coordinates[3])) - request_extent = CheckForBrackets('bbox=' + request_extent) - request_extent = urllib.quote_plus(request_extent) - - # get the type setting - # this can one of the following parameters - # * - meaning all - # node - # way - # relation - # - request_type = arcpy.GetParameterAsText(2) - #request_type = urllib.quote(request_type) - - # get the predicate string - # - request_predicate = arcpy.GetParameterAsText(3) - if (len(request_predicate) != 0): - request_predicate = CheckForBrackets(request_predicate) - request_predicate = urllib.quote(request_predicate) - - # get the location for the downloaded file - # - xapi_osm_file = arcpy.GetParameterAsText(4) - - # assemble the request url - # sample: http://jxapi.openstreetmap.org/xapi/api/0.6/*%5Bname=Sylt%5D - # - request_url = in_xapi_url + request_type + request_predicate + request_extent - AddMsgAndPrint(request_url) - - # issue the request against the XAPI endpoint - # - try: - xapi_response = urllib2.urlopen(request_url) - except urllib2.URLError, e: - if hasattr(e, 'reason'): - AddMsgAndPrint('Unable to reach the server.', 2) - AddMsgAndPrint(e.reason, 2) - elif hasattr(e, 'code'): - AddMsgAndPrint('The server was unable to fulfill the request.', 2) - AddMsgAndPrint(e.code, 2) - - else: - # write the content into a file on disk - # - with open(xapi_osm_file,'w') as xapifile: - xapifile.write(xapi_response.read()) - - except Exception as err: - AddMsgAndPrint(err.message, 2) + try: + # get the input XAPI url + # + in_xapi_url = arcpy.GetParameterAsText(0) + + # get the request extent + # + request_extent = arcpy.GetParameterAsText(1) + AddMsgAndPrint(request_extent) + + # if no extent was set and the default is passed in -- meaning "#" then set an empty string + if request_extent == '#': + request_extent = '' + elif request_extent == 'DEFAULT': + request_extent = '' + else: + coordinates = request_extent.split(' ') + request_extent = str(locale.atof(coordinates[0])) + ',' + str(locale.atof(coordinates[1])) + ',' + str( + locale.atof(coordinates[2])) + ',' + str(locale.atof(coordinates[3])) + request_extent = CheckForBrackets('bbox=' + request_extent) + request_extent = urllib.quote_plus(request_extent) + + # get the type setting + # this can one of the following parameters + # * - meaning all + # node + # way + # relation + # + request_type = arcpy.GetParameterAsText(2) + # request_type = urllib.quote(request_type) + + # get the predicate string + # + request_predicate = arcpy.GetParameterAsText(3) + if len(request_predicate) != 0: + request_predicate = CheckForBrackets(request_predicate) + request_predicate = urllib.quote(request_predicate) + + # get the location for the downloaded file + # + xapi_osm_file = arcpy.GetParameterAsText(4) + + # assemble the request url + # sample: http://jxapi.openstreetmap.org/xapi/api/0.6/*%5Bname=Sylt%5D + # + request_url = in_xapi_url + request_type + request_predicate + request_extent + AddMsgAndPrint(request_url) + + # issue the request against the XAPI endpoint + # + try: + xapi_response = urllib2.urlopen(request_url) + except urllib2.URLError, e: + if hasattr(e, 'reason'): + AddMsgAndPrint('Unable to reach the server.', 2) + AddMsgAndPrint(e.reason, 2) + elif hasattr(e, 'code'): + AddMsgAndPrint('The server was unable to fulfill the request.', 2) + AddMsgAndPrint(e.code, 2) + + else: + # write the content into a file on disk + # + with open(xapi_osm_file, 'w') as xapifile: + xapifile.write(xapi_response.read()) + + except Exception as err: + AddMsgAndPrint(err.message, 2) def CheckForBrackets(inputString): - paddedString = inputString + paddedString = inputString - if (paddedString[0] != '['): - paddedString = '[' + paddedString + if paddedString[0] != '[': + paddedString = '[' + paddedString - if (paddedString[-1] != ']'): - paddedString = paddedString + ']' + if paddedString[-1] != ']': + paddedString += ']' - return paddedString + return paddedString def AddMsgAndPrint(msg, severity=0): @@ -107,6 +109,6 @@ def AddMsgAndPrint(msg, severity=0): except: pass + if __name__ == '__main__': xapidownload() -