OliviaAddIn/OliviaAddIn/DatosGDBReco.cs

647 lines
26 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.GeoDatabaseUI;
using ESRI.ArcGIS.Carto;
using System.Windows.Forms;
using ESRI.ArcGIS.esriSystem;
using System.IO;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.DataSourcesFile;
namespace OliviaAddIn
{
/**
* @file DatosGDBReco.cs
* Clase con funciones para lectura de GDB relacionado con la recogida de residuos.
* Contiene definiciones y funciones necesarias para exportar los datos de GDB a SHP, y viceversa
* concretados con las opciones de configuración de la recogida de residuos.
*/
/**
* Clase con funciones para lectura de GDB relacionado con la recogida de residuos.
* Contiene definiciones y funciones necesarias para exportar los datos de GDB a SHP, y viceversa
* concretados con las opciones de configuración de la recogida de residuos.
*/
public class DatosGDBReco : DatosGDB
{
//*************************************************************************************
//Variables
/**
* Otro tipo de fracción de recogida de basuras
*/
public string fra_otra = "";
/**
* otro tipo de carga en la recogida de basuras
*/
public string carg_otra = "";
//variables de la GDB de contenedores
public IWorkspaceFactory wsf_gdb_rec;
public IWorkspace gdb_ws_rec;
public IDataset gdb_data_rec;
public IName name_gdb_rec;
public IWorkspaceName name_gdb_ws_rec;
public IFeatureWorkspace feat_ws_rec;
//variables de la capa de turnos
public IWorkspaceFactory wsf_turn;
public IWorkspace ws_turn;
public IDataset data_turn;
public IName name_turn;
public IWorkspaceName name_ws_turn;
public IFeatureWorkspace feat_ws_turn;
//*************************************************************************************
//Constructor
public DatosGDBReco()
{
}
//*************************************************************************************
//Métodos
/*
* Lee la capa que se ha seleccionzdo de recogida de residuos y se comprueba que los campos que se han editado corresponden con la capa (es decir, se puede leer la capa con los campos configurados)
*/
public bool lee_capa_recogida(Recogida reco)
{
int ind_campo;
string[] camps;
int i;
int NCAMPS = 6;
ITable tabla_recog = FunGDB.dame_tabla_clase(path_class);
//se comprueba que existen todos los campos que se han configurado en la capa seleccionada para la recogida
camps = new string[NCAMPS];
camps[0]=RecogidaDef.campos_def.cons_id;
camps[1] = RecogidaDef.campos_def.cons_fracc;
camps[2] = RecogidaDef.campos_def.cons_nomrec;
camps[3] = RecogidaDef.campos_def.cons_lateral;
camps[4] = RecogidaDef.campos_def.cons_uds;
camps[5] = RecogidaDef.campos_def.cons_kgrec;
for (i = 0; i < NCAMPS; i++)
{
if ((i == (NCAMPS-1)) && (reco.rec_kgrec_cont != 0))
continue;
ind_campo = tabla_recog.FindField(camps[i]);
if (ind_campo == -1)
{
reco.err_st = "No se encuentra el campo "+ camps[i];
break;
}
}
if (i < NCAMPS)
return false;
return true;
}
/*
* A partir de los datos leidos de la capa de recogida se rellena el desplegable de fracción a partir de los datos existentes en la capa.
*/
public void lee_frac_gdb(Recogida reco)
{
string[] valores;
int err=0;
int i, j, k;
bool encontrado;
valores = FunGDB.dame_valunic_consulta(path_class, RecogidaDef.campos_def.cons_fracc, "", out err);
//se redimensionan los arrays de nuevo por si se ha pinchado varias veces en el botón de leer tabla
System.Array.Resize(ref RecogidaDef.tipos_fracc_str, (int)RecogidaDef.TiposFracción.N - 1);
System.Array.Resize(ref reco.tipos_fracc_bool, (int)RecogidaDef.TiposFracción.N - 1);
for (i = 0; i < valores.Length; i++)
{
//para que ponga '-' si es un campo vacío
if (valores[i] == "")
valores[i] = "-";
encontrado = false;
for (j = 0; j < (int)RecogidaDef.TiposFracción.N - 1; j++)
{
if (RecogidaDef.tipos_fracc_str[j] == valores[i])
{
reco.tipos_fracc_bool[j] = true;
encontrado = true;
break;
}
}
if (encontrado == false)
{
System.Array.Resize(ref RecogidaDef.tipos_fracc_str, RecogidaDef.tipos_fracc_str.Length + 1);
System.Array.Resize(ref reco.tipos_fracc_bool, reco.tipos_fracc_bool.Length + 1);
RecogidaDef.tipos_fracc_str[RecogidaDef.tipos_fracc_str.Length - 1] = valores[i];
reco.tipos_fracc_bool[reco.tipos_fracc_bool.Length - 1] = true;
}
}
}
/*
* A partir de los datos leidos de la capa de receogida se rellena el desplegable del tipo de carga a partir de los datos existentes en la capa.
*/
public bool lee_tipocarga_gdb(Recogida reco)
{
string[] valores;
int err = 0;
int i, j, k;
bool encontrado;
valores = FunGDB.dame_valunic_consulta(path_class, RecogidaDef.campos_def.cons_nomrec, "", out err);
//se redimensionan los arrays de nuevo por si se ha pinchado varias veces en el botón de leer tabla
System.Array.Resize(ref RecogidaDef.tipos_carg_str, (int)RecogidaDef.TiposCarga.N - 1);
System.Array.Resize(ref reco.tipos_carg_bool, (int)RecogidaDef.TiposCarga.N - 1);
for (i = 0; i < valores.Length; i++)
{
//para que ponga '-' si es un campo vacío
if (valores[i] == "")
valores[i] = "-";
encontrado = false;
for (j = 0; j < (int)RecogidaDef.TiposCarga.N - 1; j++)
{
if (RecogidaDef.tipos_carg_str[j] == valores[i])
{
reco.tipos_carg_bool[j] = true;
encontrado = true;
break;
}
}
if (encontrado == false)
{
System.Array.Resize(ref RecogidaDef.tipos_carg_str, RecogidaDef.tipos_carg_str.Length + 1);
System.Array.Resize(ref reco.tipos_carg_bool, reco.tipos_carg_bool.Length + 1);
//reco.tipos_carg_bool[i] = false;
RecogidaDef.tipos_carg_str[RecogidaDef.tipos_carg_str.Length - 1] = valores[i];
reco.tipos_carg_bool[reco.tipos_carg_bool.Length - 1] = true;
}
}
return true;
}
/*
* Crea la consulta que hay que realizar a la capa de recogida de residuos para la exportación de los datos de interés.
* Devuelve también la abreviatura que se le añadirá a la capa exportada (se identifica la fracción y el tipo de carga del vehículo)
*/
public string dame_consulta(Recogida rec, out string cap_abrev)
{
string consulta, orstr, aux;
consulta = null;
cap_abrev = "";
aux = "";
orstr = null;
if (rec.tipo_frac != -1)
{
consulta = consulta + orstr + "(" + RecogidaDef.filtro_str[rec.tipo_frac] + ")";
cap_abrev = rec.tipo_frac.ToString("00");
cap_abrev = "F" + cap_abrev + "_";
if (consulta == "()")
consulta = "";
}
if (orstr == null)
orstr = " AND ";
if (rec.tipo_carg != -1)
{
consulta = consulta + orstr + "(" + RecogidaDef.filtro_str[rec.tipos_fracc_bool.Length + rec.tipo_carg] + ")";
aux = rec.tipo_carg.ToString("00");
cap_abrev = cap_abrev + "C" + aux;
if (consulta == "()")
consulta = "";
}
if (rec.lateralidad > 0)
{
consulta = consulta + orstr + "(" + RecogidaDef.campos_def.cons_lateral + " = '" + RecogidaDef.tipos_lateralidad[rec.lateralidad] + "'" + ")";
if (consulta == "()")
consulta = "";
}
return consulta;
}
/*
* Dado un nombre de featureclass, una consulta y una geometría, interseca entre un poligono dado (geom) y una capa lineal (fc1)
*/
public IQueryFilter dame_filt_inter(string ftclass, string consulta, IGeometry geom)
{
IQueryFilter fil = null;
IFeatureClass fc = FunGDB.abre_ftclass(ftclass);
if (fc == null)
return null;
fil = base.dame_filt_inter(fc, consulta, geom);
FunGDB.libera(fc);
return fil;
}
/**
* Realiza las intersecciones espaciales de los ámbitos
*/
public IQueryFilter crea_filtro(Recogida rec, string consulta, IGeometry geom1)
{
IQueryFilter filtro;
//crea el filtro espacial y el añadido de consulta de atributos si fuera necesario
filtro = dame_filt_inter(path_class, consulta, geom1);
if (filtro == null)
{
err_st = "Error al intersecar el ámbito de limpieza con la zona de estudio";
return null;
}
//FALTA REDEFINIR - elena jun 18
//Cuando se trate del vaciado de papeleras habrá que verificar si está marcado el checkbox que indica si sólo van a recogerse los que superen el umbral de carga.
//De modo que la secotrizacion y la planificacion se realizará sólo sobre los contenedores que superan un porcetaje de carga en la basura.
//Se conocen esos contenedores por el nombre de un campo que indicará si SI(hay que ir a recogerlos) o NO (no tienen suficiente carga y se pueden recoger en otro momento)
if ((rec.carga_max > 0) && (rec.id == null) && (rec.id_sens == null))
{
if (filtro.WhereClause == "")
filtro.WhereClause = carga_conten + " >= " + rec.carga_max;
else
filtro.WhereClause = "(" + filtro.WhereClause + ") AND (" + carga_conten + " >= " + rec.carga_max + ")";
}
return filtro;
}
/**
* Descodifica el nombre del sahpefile de entrada identificando el tipo de fracción y la carga para la recogida de residuos
*/
public void decode_gdb(string shapefile, out string fraccion, out string carga)
{
int aux, auxl, carg, indice, fracc;
string auxili, fra, auxi;
indice = shapefile.IndexOf("_");
indice = indice + 2;//para saltarse la F que va antes del identificador del tipo de fracción
auxili = shapefile.Substring(indice, 2);
fracc = Convert.ToInt32(auxili);
fraccion = RecogidaDef.tipos_fracc_str[fracc];
indice = shapefile.IndexOf("_", indice);
indice = indice + 2;//para saltarse la C que va antes del identificador de los tipos de carga de los vehículos
aux = shapefile.IndexOf("_", indice);
auxi = "";
fra = shapefile.Substring(indice, 2);
carg = Convert.ToInt32(fra);
carga = RecogidaDef.tipos_fracc_str[fracc] + "_" + RecogidaDef.tipos_carg_str[carg];
//quita los espacios
fraccion = fraccion.Replace(" ", "_");
carga = carga.Replace(" ", "_");
////////////////////////
auxi = shapefile;
for (int i = 0; i < 2; i++)
{
indice = auxi.LastIndexOf("_");
auxi = auxi.Substring(0, indice);
}
auxl = indice - aux;
if (auxl <= 0)
return;
auxili = shapefile.Substring(aux, auxl);
carga = carga + auxili;
}
/**
* Exporta a shapefile las red navegable y los ámbitos de trabajo seleccionados.
* El archivo de salida será el nombre del tratamiento escogido con el timestampo de la fecha hora
*/
public bool exporta(Recogida rec, bool comp_planif)
{
int cont = 0;
string fecha_hora = "", ambitos = "";
string consulta = "";
IQueryFilter filtro = null;
IGeometry geom_zontur = null;
IGeometry geom_ambits = null;
IDatasetName datasetn = null;
if (rec == null)
{
err_st = "No se han recibido correctamente los datos para la exportación";
return false;
}
/////////////////////////////////////////////
//elabora la consulta a realizar con los parámertos de fracción y tipo de recogida
consulta = dame_consulta(rec, out ambitos);
if (consulta == null)
{
err_st = "Error al configurar consulta";
return false;
}
/////////////////////////////////////////////
//si va a planificar antes comprueba que estén las columnas de sector y secuencia
if (comp_planif)
{
if (!comprueba_planif(path_class, null))
{
err_st = "No existen en la tabla " + path_class + " columna de SECTOR y/o SECUENCIA, necesarias para planificar";
return false;
}
}
cont = FunGDB.cuenta_filas_ftclass(path_class, consulta);
if (cont <= 0)
{
err_st = "No existen elementos geométricos que cumplan las condiciones introducidas para la exportación";
return false;
}
/////////////////////////////////////////////
//consigue el polígono común a las dos geometrías: zonas y turnos
//si no hay zonas ni turnos, es null
geom_zontur = FunGDB.une_geoms(rec.geom_zonas, rec.geom_turnos);
//además, le quita las restricciones
if (geom_zontur != null && rec.geom_rest_acces != null)
{
geom_zontur = FunGDB.diferencia_geoms(geom_zontur, rec.geom_rest_acces);
}
if (geom_zontur != null && geom_zontur.IsEmpty)
{
err_st = "Error, la geometría resultado de intersecar zonas, turnos y restricciones de circulación está vacía";
return false;
}
/////////////////////////////////////////////
//crea el filtro en base a las consultas configuradas
filtro = crea_filtro(rec, consulta, geom_zontur);
if (filtro == null)
{
err_st = "Error al crear el filtro para la exportación";
return false;
}
/////////////////////////////////////////////
//se consigue el tiempo en este instante para añadirlo a los nombres de los archivos de salida (shapefiles)
fecha_hora = DateTime.Now.ToString("yyyyMMdd_Hmmss");
//exporta los ámbitos
if (!exporta_data(rec, filtro, ambitos, fecha_hora, out datasetn))
{
err_st = "Error al exportar data. " + err_st;
return false;
}
OliviaGlob.Paths.PathData = OliviaGlob.Paths.DirData + datasetn.Name;
//quita los contenedores que caen en la zona de restricciones, si es que no había zonas y no se ha quitado ya
if (geom_zontur == null && rec.geom_rest_acces != null)
{
if (!quita_amb_restric(OliviaGlob.Paths.PathData, rec.geom_rest_acces, false))
{
err_st = "Error al quitar los ámbitos en zona de restricción";
return false;
}
}
//comprueba que sigue habiendo ámbitos exportados
cont = FunGDB.cuenta_filas_ftclass(OliviaGlob.Paths.PathData, "");
if (cont <= 0)
{
err_st = "No existen ámbitos que cumplan las condiciones geométricas introducidas";
return false;
}
if (rec.id != null)
{
int err = 0;
FunGDB.add_campo(OliviaGlob.Paths.PathData, RecogidaDef.campos.cons_kgrec, esriFieldType.esriFieldTypeDouble, out err);
if (!pon_datos_csv(rec, OliviaGlob.Paths.PathData))
{
err_st = "Error al consultar el CSV con los datos de los contenedores.";
return false;
}
}
//ahora si está en modo planificación exporta la sectorización
if (comp_planif && (path_secto != null))
{
if (!actualiza_secto(OliviaGlob.Paths.PathData, path_secto))
{
err_st = "Error al exportar campos de SECTOR y/o SECUENCIA de la capa " + path_secto + " " + err_st;
return false;
}
}
///////////////////////////////////////////////////////////////////////////
//obtiene el polígono que engloba los ámbitos
geom_ambits = FunGDB.dame_geom_envelope(OliviaGlob.Paths.PathData);
if (geom_ambits == null)
{
err_st = "Error al obtener polígono de datos";
return false;
}
///////////////////////////////////////////////////////////////////////////
//amplia el poligono para englobar las instalaciones
if (rec.coords_instala[0] != 0 && rec.coords_instala[1] != 0)
{
//hay instalación
if (!FunGDB.is_pto_in_geom(rec.coords_instala[0], rec.coords_instala[1], geom_ambits))
{
geom_ambits = FunGDB.amplia_geom_convexhull(geom_ambits, rec.coords_instala[0], rec.coords_instala[1]);
if (geom_ambits == null)
{
err_st = "Error al obtener envolvente convexa con instalación";
return false;
}
}
//comprueba, si hay restricciones de circulación, que la instalación no está en ellas
if (rec.geom_rest_acces != null)
{
if (FunGDB.is_pto_in_geom(rec.coords_instala[0], rec.coords_instala[1], rec.geom_rest_acces))
{
err_st = "Error, la instalación sal/lleg está en la zona restringida a la circulación";
return false;
}
}
}
if (rec.coords_descarg[0] != 0 && rec.coords_descarg[1] != 0)
{
//hay instalación de descarga
if (!FunGDB.is_pto_in_geom(rec.coords_descarg[0], rec.coords_descarg[1], geom_ambits))
{
geom_ambits = FunGDB.amplia_geom_convexhull(geom_ambits, rec.coords_descarg[0], rec.coords_descarg[1]);
if (geom_ambits == null)
{
err_st = "Error al obtener envolvente convexa con instalación";
return false;
}
}
//comprueba, si hay restricciones de circulación, que la instalación no está en ellas
if (rec.geom_rest_acces != null)
{
if (FunGDB.is_pto_in_geom(rec.coords_descarg[0], rec.coords_descarg[1], rec.geom_rest_acces))
{
err_st = "Error, la planta de descarga está en la zona restringida a la circulación";
return false;
}
}
}
///////////////////////////////////////////////////////////////////////////
//exporta la red navegable
if (!exporta_nw(geom_ambits, rec.geom_rest_acces, true, fecha_hora, out datasetn))
{
return false;
}
//guarda los nombres del shape
OliviaGlob.Paths.PathNW = OliviaGlob.Paths.DirData + datasetn.Name;
//Guarda el nombre que lo escribirá en el shp resultado
OliviaGlob.nomb_tto = RecogidaDef.tipos_fracc_str[rec.tipo_frac];
return true;
}
/**
* Devuelve el string a concatenar en el nombre del path dependiendo de los polígonos seleccionados (zonas, turnos... etc)
*/
public string dame_str_poligs(Recogida rec)
{
string str = "";
if (rec.text_turnos != "" && rec.geom_turnos != null)
str += "_T" + rec.text_turnos;
if (rec.text_zon != "" && rec.geom_zonas != null)
str += "_Z" + rec.text_zon;
if (rec.text_restr != "" && rec.geom_rest_acces != null)
str += "_R" + rec.text_restr;
return str;
}
/**
* Exporta los ámbitos de la gdb a un shape en datasetname
*/
public bool exporta_data(Recogida rec, IQueryFilter filtro, string ambitos, string fecha_hora, out IDatasetName shp_data_name)
{
string name = "", err_str = "";
IDatasetName shp_dsn = null;
shp_data_name = null;
//Pone nombre al shape en función de los ámbitos, el tratamiento, y los polígonos + timestamp
name = name_export_amb + ambitos + dame_str_poligs(rec) + "_" + fecha_hora + ext_shp;
inicia_coords(path_class, null);
if (!FunGDB.exporta(path_class, null, OliviaGlob.Paths.DirData, name, filtro, out shp_dsn, out err_str))
{
err_st = err_str;
return false;
}
shp_data_name = (IDatasetName)shp_dsn;
return true;
}
/*
* REVISAR
* Modifica el shapefile exportado de modo que elimina aquellos elementos (contenedores) que no contengan un porcentaje de cargaigual o superior al indicado en la ventana de recogida (rec.carga_max).
*/
public bool pon_datos_csv(Recogida rec, string capa)
{
int col_kg = -1, col_capa;
object obj, capacidad;
IFeature feat = null;
IFeatureClass fc = null;
IFeatureCursor cursor = null;
IQueryFilter filtro = new QueryFilterClass();
ITable tabla = null;
IRow fila = null;
fc = FunGDB.abre_ftclass(capa);
if (fc == null)
return false;
tabla = FunGDB.dame_tabla_clase(capa);
if (tabla == null)
return false;
col_kg = tabla.FindField(RecogidaDef.campos.cons_kgrec);
col_capa = tabla.FindField(RecogidaDef.campos.cons_capac);
for (int i = 0; i < rec.id.Count; i++)
{
filtro.WhereClause = RecogidaDef.campos.cons_id + "=" + rec.id[i];
cursor = fc.Search(filtro, false);
feat = cursor.NextFeature();
if (feat == null)
{
//libera
FunGDB.libera(fila);
FunGDB.libera(cursor);
FunGDB.libera(feat);
break;
}
fila = tabla.GetRow(feat.OID);
//si el procentaje de carga indicado es superior al indicado por el archivo CSV se omite ese elemento a exportar, por lo que se elimina de la lista
if (rec.carga_max > rec.cargas[i])
{
fila.Delete();
//libera
FunGDB.libera(fila);
FunGDB.libera(cursor);
FunGDB.libera(feat);
continue;
}
capacidad = fila.get_Value(col_capa);
if (rec.dens_cont >= 0)
fila.set_Value(col_kg, rec.cargas[i] * rec.dens_cont * (int)capacidad / 1000);
else
fila.set_Value(col_kg, rec.cargas[i] * RecogidaDef.dens_frac_cont[rec.tipo_frac] * (int)capacidad / 1000);
fila.Store();
//libera
FunGDB.libera(fila);
FunGDB.libera(cursor);
FunGDB.libera(feat);
}
cursor = fc.Search(null, false);
feat = cursor.NextFeature();
while (feat != null)
{
fila = tabla.GetRow(feat.OID);
obj = fila.get_Value(col_kg);
capacidad = fila.get_Value(col_capa);
if ((Double)obj == 0.0)
{
fila.set_Value(col_kg, rec.dens_cont * (int)capacidad/1000);
fila.Store();
//libera
FunGDB.libera(fila);
FunGDB.libera(feat);
}
//libera
FunGDB.libera(fila);
FunGDB.libera(feat);
feat = cursor.NextFeature();
}
//libera
FunGDB.libera(fila);
FunGDB.libera(cursor);
FunGDB.libera(feat);
FunGDB.libera(filtro);
FunGDB.libera(tabla);
FunGDB.libera(fc);
return true;
}
}
}