OliviaAddInPro/Helper/HelperGdb.cs

507 lines
20 KiB
C#

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<Geodatabase> GetGdb(string pathGdb)
{
Geodatabase fileGeodatabase = null;
ReiniciaOutStr();
return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func<Geodatabase>)(() =>
{
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<FeatureClass> GetFtClass(string nameFtclss, Geodatabase gdb)
{
FeatureClass ftclss = null;
ReiniciaOutStr();
return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func<FeatureClass>)(() =>
{
try
{
ftclss = gdb.OpenDataset<FeatureClass>(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<FeatureClass> GetFtClassFromShp(string pathShp)
{
FeatureClass ftclss = null;
ReiniciaOutStr();
return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func<FeatureClass>)(() =>
{
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<FeatureClass>(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<ArcGIS.Core.Data.Field> 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<ArcGIS.Core.Data.Field>)(() =>
{
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<ObservableCollection<string>> GetFields(FeatureClass fc)
{
FeatureClassDefinition ftcldef=null;
IReadOnlyList<ArcGIS.Core.Data.Field> fields = null;
ReiniciaOutStr();
ObservableCollection<string> fields_st = new ObservableCollection<string>();
return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func<ObservableCollection<string>>)(() =>
{
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<ObservableCollection<string>> GetFieldVals(FeatureClass fc, string fieldName, bool uniquevals)
{
ObservableCollection<string> attribs_st = new ObservableCollection<string>();
ReiniciaOutStr();
return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func<ObservableCollection<string>>)(() =>
{
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<ArcGIS.Core.Geometry.Geometry> GetGeomSel(FeatureClass fclss, string fieldName, ObservableCollection<string> 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<ArcGIS.Core.Geometry.Geometry>)(() =>
{
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<int> GetNumElems(FeatureClass fc, string consulta = "")
{
int n = -1;
return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func<int>)(() =>
{
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;
}
}
}