using System; using System.Collections.Generic; using System.Linq; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using ArcGIS.Desktop.Catalog; using ArcGIS.Desktop.Core; using ArcGIS.Desktop.Framework; using System.Collections.ObjectModel; using ArcGIS.Core.Geometry; using ArcGIS.Core.Data; using ArcGIS.Desktop.Mapping; using ArcGIS.Core.Internal.CIM; namespace OliviaAddInPro.Helper { public static class HelperGdb { private static string out_str = string.Empty; public static string OutStr { get { string val = out_str; out_str = string.Empty; //lo borra cada vez que se consulta return val; } set { out_str = value; } } private static string texto_sal = string.Empty; public static string TextoSal { get { string val = texto_sal; texto_sal = string.Empty; //lo borra cada vez que se consulta return val; } set { texto_sal = value; } } [Flags] public enum TiposOpenFileDlg { OpenFtrClassLine=1, OpenFtrClassPoint=2, OpenFtrClassPolygon=4, OpenGdb=8, } private static void ReiniciaOutStr() { out_str = string.Empty; } //Dado el tipo de FtClass y una posición inicial abre un diálogo de búsqueda de ftclass //si se cancela o no es una feature class lo que se ha abierto devuelve null //si no, devuelve la featureclass directamente abierta public static FeatureClass OpenFtClassDialog(TiposOpenFileDlg tipo, string initialLoc = "") { FeatureClass fc = null; ReiniciaOutStr(); string path = OpenFileDialog( tipo, initialLoc); if(!string.IsNullOrEmpty(path)) { fc = GetFtClass(path); } return fc; } //Libera el objeto public static void Free(IDisposable obj) { if(obj!=null) obj.Dispose(); } //Devuelve el Path del archivo seleccionado o un string vacío si se ha cancelado public static string OpenFileDialog(TiposOpenFileDlg tipo, string initialLoc="") { string titulo; ReiniciaOutStr(); titulo = "Abrir Archivo"; //Create a browse filter that uses Pro's "esri_browseDialogFilters_geodatabases" filter. //The browse filter is used in an OpenItemDialog. //fuentes filtros //https://github.com/Esri/arcgis-pro-sdk-community-samples/blob/master/Map-Exploration/IdentifyWindow/Daml.cs BrowseProjectFilter filtro = new BrowseProjectFilter(); if ((tipo & TiposOpenFileDlg.OpenFtrClassLine)== TiposOpenFileDlg.OpenFtrClassLine) { filtro.AddFilter(BrowseProjectFilter.GetFilter("esri_browseDialogFilters_featureClasses_line")); titulo = "Abrir Feature Class"; } if ((tipo & TiposOpenFileDlg.OpenFtrClassPoint) == TiposOpenFileDlg.OpenFtrClassPoint) { filtro.AddFilter(BrowseProjectFilter.GetFilter("esri_browseDialogFilters_featureClasses_point")); titulo = "Abrir Feature Class"; } if ((tipo & TiposOpenFileDlg.OpenFtrClassPolygon) == TiposOpenFileDlg.OpenFtrClassPolygon) { filtro.AddFilter(BrowseProjectFilter.GetFilter("esri_browseDialogFilters_featureClasses_polygon")); titulo = "Abrir Feature Class"; } if ((tipo & TiposOpenFileDlg.OpenGdb) == TiposOpenFileDlg.OpenGdb) { filtro.AddFilter(BrowseProjectFilter.GetFilter("esri_browseDialogFilters_geodatabases")); titulo = "Abrir Geodatabase"; } if(tipo==0) { filtro.AddFilter(BrowseProjectFilter.GetFilter("")); } //Display the filter in an Open Item dialog OpenItemDialog aNewFilter = new OpenItemDialog { Title = titulo, InitialLocation = initialLoc, MultiSelect = false, //Set the BrowseFilter property to Pro's Geodatabase filter. BrowseFilter = filtro }; bool? ok = aNewFilter.ShowDialog(); if ((ok ?? true) && aNewFilter.Items.Count() > 0) return aNewFilter.Items.First().Path; else return string.Empty; } //Dado un path comprueba que sea de una gdb, termina en .gdb, o si tiene .gdb en medio lo corta ahí //y si no tiene devuelve vacío public static string GetPathGdb(string path) { string pathGdb = string.Empty; int i = 0; string gdbext = ".gdb"; if(path.Contains(gdbext)) { i = path.IndexOf(gdbext, 0, path.Length); pathGdb = path.Substring(0, i + 4); } return pathGdb; } //Dado un path aunque sea de una feature class, devuelve el path de la gdb que la contiene, o si //es de gdb directamente, y si no tiene .gdb, devuelve null public static Task GetGdb(string pathGdb) { Geodatabase fileGeodatabase = null; ReiniciaOutStr(); return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func)(() => { string path = GetPathGdb(pathGdb); if (!string.IsNullOrEmpty(path)) { try { fileGeodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(path))); } catch (Exception ex) { HelperGdb.out_str = "Error al abrir Geodatabase " + path + ": " + ex.Message; return null; } } return fileGeodatabase; })); //return fileGeodatabase; } //Dado un path de una feature class devuelve la ftclass abierta directamente, //o null si ha habido algún problema o no lo ha encontrado public static FeatureClass GetFtClass(string pathFtClss) { FeatureClass ftclss = null; Geodatabase gdb = GetGdb(pathFtClss).Result; ReiniciaOutStr(); if (gdb != null) { ftclss = GetFtClass(System.IO.Path.GetFileNameWithoutExtension(pathFtClss), gdb).Result; } else //mira a ver si es shapefile { ftclss = GetFtClassFromShp(pathFtClss).Result; } return ftclss; } //Dado el path de una gdb y el nombre de una feature class, devuelve la //feature class abierta, o null si hay algun problema public static Task GetFtClass(string nameFtclss, Geodatabase gdb) { FeatureClass ftclss = null; ReiniciaOutStr(); return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func)(() => { try { ftclss = gdb.OpenDataset(nameFtclss); } catch (Exception ex) { HelperGdb.out_str = "Error al abrir Feature Class " + nameFtclss + ": " + ex.Message; return null; } return ftclss; })); } //Abre una feature class cuando es un shapefile public static Task GetFtClassFromShp(string pathShp) { FeatureClass ftclss = null; ReiniciaOutStr(); return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func)(() => { if (pathShp.Contains(".shp")) { try { string shpname = System.IO.Path.GetFileNameWithoutExtension(pathShp); var shapeFileConnPath = new FileSystemConnectionPath(new Uri(pathShp), FileSystemDatastoreType.Shapefile); var shapefile = new FileSystemDatastore(shapeFileConnPath); ftclss = shapefile.OpenDataset(shpname); } catch (Exception ex) { HelperGdb.out_str = "Error al abrir Shapefile " + pathShp + ": " + ex.Message; return null; } } return ftclss; })); } //devuelve el campo dado el nombre private static Task GetFieldByName(FeatureClass ftClss, string fieldName) { FeatureClassDefinition ftcldef = ftClss.GetDefinition(); ReiniciaOutStr(); ArcGIS.Core.Data.Field field=null; return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func)(() => { try { field = ftcldef.GetFields().First(x => x.Name.Equals(fieldName)); } catch (Exception ex) { HelperGdb.out_str = "No se encuentra el campo " + fieldName + ": " + ex.Message; return null; } return field; })); } //Devuelve una lista con los campos de una feature class public static Task> GetFields(FeatureClass fc) { FeatureClassDefinition ftcldef=null; IReadOnlyList fields = null; ReiniciaOutStr(); ObservableCollection fields_st = new ObservableCollection(); return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func>)(() => { try { ftcldef = fc.GetDefinition(); fields = ftcldef.GetFields(); foreach (ArcGIS.Core.Data.Field f in fields) { fields_st.Add(f.Name); } } catch (Exception ex) { HelperGdb.out_str = "Error al leer los campos " + fc.GetName() + ": " + ex.Message; return fields_st; } return fields_st; })); } //Devuelve comilla simple si el campo es de texto, o nada si es númerico //var whereClause = $"{SelectedField} = {Quote(f)}{FieldValue}{Quote(f)}"; public static string Quote(ArcGIS.Core.Data.Field f) { return f.FieldType == FieldType.String ? "'" : ""; } //Dado un nombre de campo, devuelve los valores que encuentra para ese nombre de campo public static Task> GetFieldVals(FeatureClass fc, string fieldName, bool uniquevals) { ObservableCollection attribs_st = new ObservableCollection(); ReiniciaOutStr(); return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func>)(() => { try { using (FeatureClassDefinition ftcldef = fc.GetDefinition()) { ArcGIS.Core.Data.Field field = ftcldef.GetFields().First(x => x.Name.Equals(fieldName)); using (RowCursor rowCursor = fc.Search()) { string str; while (rowCursor.MoveNext()) { using (Row row = rowCursor.Current) { str = Convert.ToString(row[fieldName]); if (uniquevals) { if (attribs_st.Contains(str)) continue; } attribs_st.Add(str); } } } } } catch (Exception ex) { HelperGdb.out_str = "Error al leer los campos " + fc.GetName() + ": " + ex.Message; return attribs_st; } return attribs_st; })); } /** * Devuelve una geometría que es la suma de la inicial y la que se añade Add */ public static ArcGIS.Core.Geometry.Geometry UneGeom(ArcGIS.Core.Geometry.Geometry geomIni, ArcGIS.Core.Geometry.Geometry geomUne) { if (geomIni == null) return geomUne; return GeometryEngine.Instance.Union(geomIni, geomUne); } /** * Devuelve una geometría a la que dada una geometría inicial se le quita Excl */ public static ArcGIS.Core.Geometry.Geometry QuitaGeom(ArcGIS.Core.Geometry.Geometry geomIni, ArcGIS.Core.Geometry.Geometry geomQuita) { return GeometryEngine.Instance.Union(geomIni, geomQuita); } /** * Forma la envolvente convexa, el mínimo polígono, * que contiene los ámbitos para exportar, a partir de ahí la red navegable ampliando a un buffer */ public static ArcGIS.Core.Geometry.Geometry GetGeomConvexHull(FeatureClass fclss, ArcGIS.Core.Data.QueryFilter filter) { ArcGIS.Core.Geometry.Geometry geomIni = null; geomIni = GetGeomUnica(fclss, filter); if (geomIni != null) return GeometryEngine.Instance.ConvexHull(geomIni); else return null; } /* * A partir de una capa recorre todos los elementos que cumplen el filtro y los une en una única geometría */ public static ArcGIS.Core.Geometry.Geometry GetGeomUnica(FeatureClass fclss, ArcGIS.Core.Data.QueryFilter filtro) { ArcGIS.Core.Geometry.Geometry geomsal = null; ReiniciaOutStr(); try { using (RowCursor rowCursor = fclss.Search(filtro)) { while (rowCursor.MoveNext()) { using (Row row = rowCursor.Current) { if(row is Feature ft) geomsal = UneGeom(geomsal, ft.GetShape()); } } } } catch (Exception ex) { out_str = "Error al leer generar geometría única " + out_str + ex.Message; return geomsal; } return geomsal; } /** * Dado un campo de una feature class y el valor que se quiere para el campo * devuelve las geometrías que cumplen dicho criterio */ public static Task GetGeomSel(FeatureClass fclss, string fieldName, ObservableCollection selFieldVals) { ArcGIS.Core.Geometry.Geometry geomsal = null; ArcGIS.Core.Geometry.Geometry geomAux = null; string where = ""; ArcGIS.Core.Data.Field f; ArcGIS.Core.Data.QueryFilter filtro; bool ok = true; ReiniciaOutStr(); TextoSal = string.Empty; return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func)(() => { try { using (FeatureClassDefinition ftcldef = fclss.GetDefinition()) { f = ftcldef.GetFields().First(x => x.Name.Equals(fieldName)); //se embucla para unir las geoms for (int i = 0; i < selFieldVals.Count && ok; i++) { where = $"{fieldName} = {Quote(f)}{selFieldVals[i]}{Quote(f)}"; filtro = new ArcGIS.Core.Data.QueryFilter { WhereClause = where }; geomAux = GetGeomUnica(fclss, filtro); if(geomAux == null) { ok = false; continue; } geomsal = UneGeom(geomsal, geomAux); TextoSal = TextoSal + HelperGlobal.RevisaText(selFieldVals[i]); } } } catch (Exception ex) { HelperGdb.out_str = "Error al generar geometría en " + fclss.GetName() + " Con filtro " + where +": " + ex.Message; return geomsal; } if (!ok) HelperGdb.out_str = "Error al generar geometría en " + fclss.GetName() + " Con filtro " + where + HelperGdb.out_str; return geomsal; })); } /** * Devuelve el número de entidades de una FeatureClass que cumplen la consulta, o todos si la consulta es empty */ public static int GetNumElems(string pathGdb, string ftclssName, string consulta = "") { Geodatabase gdb = GetGdb(pathGdb).Result; FeatureClass fc = null; int n = -1; if (gdb != null) { fc = GetFtClass(ftclssName, gdb).Result; if(fc!=null) n= GetNumElems(fc, consulta).Result; } Free(fc); Free(gdb); return n; } /** * Devuelve el número de entidades de una FeatureClass que cumplen la consulta, o todos si la consulta es empty */ public static Task GetNumElems(FeatureClass fc, string consulta = "") { int n = -1; return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func)(() => { try { if (fc != null) { if (string.IsNullOrEmpty(consulta)) n = fc.GetCount(); else { //realiza consulta n = 0; using (Selection sel = fc.Select(new ArcGIS.Core.Data.QueryFilter { WhereClause = consulta }, SelectionType.ObjectID, SelectionOption.Normal)) n = sel.GetCount(); } } return n; } catch (Exception ex) { HelperGdb.out_str = "Error al contar filas en " + fc.GetName() + ": " + ex.Message; return n; } })); } /** * Devuelve el número de entidades de una FeatureClass que cumplen la consulta, o todos si la consulta es empty */ public static int GetNumElems(string pathFtClss, string consulta = "") { FeatureClass fc = GetFtClass(pathFtClss); int n=GetNumElems(fc,consulta).Result; Free(fc); return n; } } }