diff --git a/Helper/HelperGdb.cs b/Helper/HelperGdb.cs index bb16e53..cc93146 100644 --- a/Helper/HelperGdb.cs +++ b/Helper/HelperGdb.cs @@ -310,6 +310,62 @@ namespace OliviaAddInPro.Helper } + //Crea un filtro espacial a partir de una consulta y en todo caso, una geometría + public static ArcGIS.Core.Data.QueryFilter CreateFiler(string consulta, ArcGIS.Core.Geometry.Geometry geom, SpatialRelationship rel= SpatialRelationship.Intersects) + { + ArcGIS.Core.Data.QueryFilter filt=null; + if (geom != null) + { + SpatialQueryFilter filtSpat = new SpatialQueryFilter + { + WhereClause = consulta, + FilterGeometry = geom, + SpatialRelationship = rel, + }; + filt = (ArcGIS.Core.Data.QueryFilter)filtSpat; + + } + else + { + filt = new ArcGIS.Core.Data.QueryFilter(); + filt.WhereClause = consulta; + } + return filt; + } + + //Devuelve la lista de IDs de la clase que cumplen la consulta + public static Task> GetIds(FeatureClass fc, ArcGIS.Core.Data.QueryFilter filt) + { + ReiniciaOutStr(); + List ids = new List(); + Selection sel=null; + return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run((Func>)(() => + { + if (fc == null) + return null; + try + { + if (filt == null) + filt = new ArcGIS.Core.Data.QueryFilter(); + sel = fc.Select(filt, SelectionType.ObjectID, SelectionOption.Normal); + int nsel = sel.GetCount(); + IReadOnlyList ids_= sel.GetObjectIDs(); + ids = ids_.ToList(); + return ids; + } + catch (Exception ex) + { + HelperGdb.OutStr = "Error al conseguir IDs " + fc.GetName() + ": " + ex.Message; + return ids; + } + finally + { + Free(sel); + } + + })); + } + //Devuelve una lista con los campos de una feature class public static Task> GetFields(FeatureClass fc) { @@ -421,7 +477,8 @@ namespace OliviaAddInPro.Helper /** * Devuelve una geometría que es la suma de la inicial y la que se añade Add */ - public static ArcGIS.Core.Geometry.Geometry IntersectGeom(ArcGIS.Core.Geometry.Geometry geomIni, ArcGIS.Core.Geometry.Geometry geomInters) + public static ArcGIS.Core.Geometry.Geometry IntersectGeom(ArcGIS.Core.Geometry.Geometry geomIni, ArcGIS.Core.Geometry.Geometry geomInters, + GeometryDimension resultDimension= GeometryDimension.esriGeometryNoDimension) { if (geomIni == null) return geomInters; @@ -430,7 +487,11 @@ namespace OliviaAddInPro.Helper ArcGIS.Core.Geometry.Geometry geomSal = null; try { - geomSal=GeometryEngine.Instance.Intersection(geomIni, geomInters); + if(resultDimension== GeometryDimension.esriGeometryNoDimension) + geomSal =GeometryEngine.Instance.Intersection(geomIni, geomInters); + else + geomSal = GeometryEngine.Instance.Intersection(geomIni, geomInters, resultDimension); + return geomSal; } catch @@ -870,64 +931,121 @@ namespace OliviaAddInPro.Helper return true; } + /** + * Elimina las filas indicadas del shp + **/ + public static bool RemoveRowsFromShp(string shp_path, List quita) + { + FeatureClass fc = HelperGdb.GetFtClassFromShp(shp_path).Result; + if (fc == null) + return false; + + string message = String.Empty; + bool deletionResult = false; + + ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() => { + string shpname = System.IO.Path.GetFileNameWithoutExtension(shp_path); + var shapeFileConnPath = new FileSystemConnectionPath(new Uri(shp_path), FileSystemDatastoreType.Shapefile); + var shapefile = new FileSystemDatastore(shapeFileConnPath); + using (Table table = shapefile.OpenDataset(shp_path)) + { + EditOperation editOperation = new EditOperation(); + editOperation.Callback(context => + { + ArcGIS.Core.Data.QueryFilter openCutFilter = new ArcGIS.Core.Data.QueryFilter { WhereClause = "ACTION = 'Open Cut'" }; + + using (RowCursor rowCursor = table.Search(openCutFilter, false)) + { + while (rowCursor.MoveNext()) + { + using (Row row = rowCursor.Current) + { + // In order to update the Map and/or the attribute table. Has to be called before the delete. + context.Invalidate(row); + + row.Delete(); + } + } + } + }, table); + + try + { + deletionResult = editOperation.Execute(); + if (!deletionResult) + { + message = editOperation.ErrorMessage; + } + } + catch (GeodatabaseException exObj) + { + message = exObj.Message; + } + } + }); + + if (!string.IsNullOrEmpty(message)) + { + OutStr = message; + return false; + } + else + return true; + } + /** * Recorre los ámbitos lineales del shp viendo qué longitud tienen dentro de la geometría, y si * es menos de un porcentaje, lo quitan del shp **/ public static bool RemoveRowsGeom(string shp_path, ArcGIS.Core.Geometry.Geometry geom_zon, double porc) { - - /*int[] ids = null; - IFeature f = null; - IFeatureClass fc = null; - IGeometry geom_aux = null; - ITopologicalOperator union = null; - IPolyline poli = null; + FeatureClass fc = HelperGdb.GetFtClassFromShp(shp_path).Result; + if (fc == null) + return false; + ArcGIS.Core.Geometry.Geometry geom = null; + ArcGIS.Core.Geometry.Polyline line = null; + Feature f = null; double longi_zon = 0, longi_tot = 0; - List quita = new List(); - int j; + List quita = new List(); + int j=0; + List ids; try { - ids = FunGDB.dame_ids_consulta(shp_path, ""); //consulta todos - if (ids == null) - return false; - fc = FunGDB.abre_ftclass(shp_path); - if (fc == null) - return false; - for (j = 0; j < ids.Length; j++) + //Obtiene los IDs + ids = GetIds(fc, null).Result; + //Recorre las features de la capa + RowCursor cursor = fc.Search(); + while(cursor.MoveNext()) { - f = fc.GetFeature(ids[j]); - geom_aux = f.Shape; - poli = (IPolyline)geom_aux; - longi_tot = poli.Length; - union = (ITopologicalOperator)geom_zon; - if (geom_aux == null) - return false; - geom_aux = union.Intersect(geom_aux, esriGeometryDimension.esriGeometry1Dimension);//se realiza la interseccion entre ámbito (linea) y nivel (poligono) - poli = (IPolyline)geom_aux; - longi_zon = poli.Length;//se consigue la longitud de ámbito (linea) que interseca con el nivel) - + f = (Feature)cursor.Current; + geom = f.GetShape(); + line = (ArcGIS.Core.Geometry.Polyline)geom; + longi_tot = line.Length; + geom= IntersectGeom(geom_zon, line,GeometryDimension.esriGeometry1Dimension); + line =(ArcGIS.Core.Geometry.Polyline)geom; + longi_zon = line.Length;//se consigue la longitud de ámbito (linea) que interseca con el nivel) if ((longi_zon / longi_tot) < porc) { //quita esa línea quita.Add(ids[j]); } - FunGDB.libera(f); + j++; + Free(f); } - - - FunGDB.libera(fc); - FunGDB.libera(f); - + Free(f); + Free(fc); + Free(cursor); + if (quita.Count > 0) { //borra las líneas que se han indicado - if (!FunGDB.quita_filas(shp_path, quita)) + if (!RemoveRowsFromShp(shp_path, quita)) return false; } return true; + } catch (Exception) { @@ -935,10 +1053,10 @@ namespace OliviaAddInPro.Helper } finally { - FunGDB.libera(fc); - FunGDB.libera(f); - }*/ - return true; + HelperGdb.Free(fc); + HelperGdb.Free(f); + } + } } diff --git a/Model/OliviaConf.cs b/Model/OliviaConf.cs index f1f17db..a66008a 100644 --- a/Model/OliviaConf.cs +++ b/Model/OliviaConf.cs @@ -12,6 +12,15 @@ namespace OliviaAddInPro.Model [Serializable] class OliviaConf { + public enum OpsRecoCont + { + [Description("Contenedor lleno")] + LlenoUsaDensidad, + [Description("Lee campo 'kg a recoger'")] + LeeCampoTabla, + [Description("Usa 'kg defecto'")] + UsaKgDef + } private string m2s(int min) { var val = min; @@ -994,13 +1003,57 @@ namespace OliviaAddInPro.Model [Description("Indica los kg a utilizar para todos los contenedores")] public int kgrec_val { get; set; } [Category("Campos Recogida")] + [Browsable(false)] [DisplayName("¿Lleno?")] [Description("Indica si se debe considerar que todos los contenedores están llenos")] public bool is_lleno { get; set; } [Category("Campos Recogida")] + [Browsable(false)] [DisplayName("¿Lee el campo de kg?")] [Description("Indica si se deben leer los kg de cada contenedor del campo 'Kg a recoger'")] public bool is_campo { get; set; } + [Category("Campos Recogida")] + [DisplayName("Kg contenedor")] + [JsonIgnore] + [Description("Indica si se usa contenedor lleno, en cuyo caso se emplea la densidad de la " + + "fracción en contenedor y su capacidad, o bien si se debe usar el valor por defecto 'Kg defecto' o bien se deben leer los kg de cada contenedor del campo 'Kg a recoger'")] + public OpsRecoCont opsRecoCont + { + get + { + if(is_lleno) + { + return OpsRecoCont.LlenoUsaDensidad; + } + else if(is_campo) + { + return OpsRecoCont.LeeCampoTabla; + } + else + { + return OpsRecoCont.UsaKgDef; + } + } + set + { + switch(value) + { + case OpsRecoCont.LlenoUsaDensidad: + is_lleno = true; + is_campo = false; + break; + case OpsRecoCont.LeeCampoTabla: + is_lleno = false; + is_campo = true; + break; + case OpsRecoCont.UsaKgDef: + is_lleno = false; + is_campo = false; + break; + } + } + } + #endregion #region AtributosRecogida diff --git a/Services/EjecServ.cs b/Services/EjecServ.cs index 05c7aaa..1d45902 100644 --- a/Services/EjecServ.cs +++ b/Services/EjecServ.cs @@ -60,48 +60,72 @@ namespace OliviaAddInPro.Services fue_mal = true; } } - // cps.Value = 80; //crea el filtro de exportación if (!fue_mal) { //mira spatialreference de los datos de entrada spatRef = geom_export.SpatialReference; - filtroEspacial = CreaFiltro(com.ConsultaAmbs, geom_export); + filtroEspacial = (SpatialQueryFilter) HelperGdb.CreateFiler(com.ConsultaAmbs, geom_export); fue_mal = filtroEspacial == null; if (fue_mal) - ErrStr = "error al crear el filtro de exportacion"; - - cps.Value = 80; + ErrStr = "Error al crear el filtro de exportacion"; if (!fue_mal) - fue_mal = Exporta(modo, cps, out ErrStr); //Falta pasar el filtro espacial - + fue_mal = Exporta(modo, cps, out ErrStr); + if (!fue_mal) + { + //Guarda el nombre + OliviaGlob.Paths.PathData = OliviaGlob.Paths.DirData + com.NombreShpExport; + } } + cps.Value = 80; if (!fue_mal) { - OliviaGlob.Paths.PathData = OliviaGlob.Paths.DirData + com.NombreShpExport; //hace intersecciones espaciales en caso de ámbitos lineales para quitar los que tienen más parte fuera de la zona que dentro if (geom_export != null && (OliviaGlob.IsReco() || (OliviaGlob.IsLimp() && (com.TipoTto < (int)LimpiezaDef.TiposTto.TtoPapeVaci)))) - { - //FALTA RELLENAR + { if (!HelperGdb.RemoveRowsGeom(OliviaGlob.Paths.PathData, geom_export, 0.4)) { - ErrStr = "Error al quitar los ámbitos que sobresalen"; + ErrStr = "Error al quitar los ámbitos que sobresalen: "+HelperGdb.OutStr; return false; } } } //comprueba que no se haya quedado sin ámbitos + using (FeatureClass fc = HelperGdb.GetFtClassFromShp(OliviaGlob.Paths.PathData).Result) + { + if (fc.GetCount() <= 0) + { + ErrStr = "No quedan ámbitos que cumplan la geometría seleccionada."; + return false; + } - /////////////////////////////////////////////////////////////////////////// - //amplia la geom para englobar las instalaciones + /////////////////////////////////////////////////////////////////////////// + //amplia la geom para englobar las instalaciones + geom_export = HelperGdb.GetGeomConvexHull(fc, null, cps).Result; + /*if (limp.coords_instala[0] != 0 && limp.coords_instala[1] != 0) + { + //hay instalación + if (!FunGDB.is_pto_in_geom(limp.coords_instala[0], limp.coords_instala[1], geom_ambits)) + geom_ambits = FunGDB.amplia_geom_convexhull(geom_ambits, limp.coords_instala[0], limp.coords_instala[1]); - /////////////////////////////////////////////////////////////////////////// - //exporta la red navegable + //comprueba, si hay restricciones de circulación, que la instalación no está en ellas + if (limp.geom_rest_acces != null) + { + if (FunGDB.is_pto_in_geom(limp.coords_instala[0], limp.coords_instala[1], limp.geom_rest_acces)) + { + err_st = "Error, la instalación sal/lleg está en la zona restringida a la circulación"; + return false; + } + } + }*/ + } + /////////////////////////////////////////////////////////////////////////// + //exporta la red navegable (buffer, le quita las restr...) - //guarda los nombres del shape - OliviaGlob.Paths.PathNW = OliviaGlob.Paths.DirData + com.NombreShpExportNw; + //guarda los nombres del shape + OliviaGlob.Paths.PathNW = OliviaGlob.Paths.DirData + com.NombreShpExportNw; return fue_mal; } @@ -147,11 +171,11 @@ namespace OliviaAddInPro.Services cps.Value = 30; //prepara el filtro con consulta y espacial - SpatialQueryFilter filtro = CreaFiltro(com.ConsultaAmbs, geomAux); + SpatialQueryFilter filtro = (SpatialQueryFilter)HelperGdb.CreateFiler(com.ConsultaAmbs, geomAux); //Ahora hace la geometría de los ámbitos que cumplen la consulta geomAmbits = HelperGdb.GetGeomConvexHull(fc, filtro, cps).Result; - if (geomAux == null || geomAux.IsEmpty) + if (geomAmbits == null || geomAmbits.IsEmpty) { ErrStr = "No se ha podido generar geometría de los ámbitos" + com.ConsultaAmbs + HelperGdb.OutStr; return null; @@ -173,17 +197,6 @@ namespace OliviaAddInPro.Services return geomAux; } - public SpatialQueryFilter CreaFiltro(string consulta, Geometry geom) - { - SpatialQueryFilter filtSpac = new SpatialQueryFilter - { - WhereClause = consulta, - FilterGeometry = geom, - SpatialRelationship = SpatialRelationship.Contains, - }; - return filtSpac; - } - /** * Devuelve el string a concatenar en el nombre del path dependiendo de los polígonos seleccionados (zonas, turnos... etc) */ diff --git a/Services/RecogidaServ.cs b/Services/RecogidaServ.cs index 64e4ea2..9c1289d 100644 --- a/Services/RecogidaServ.cs +++ b/Services/RecogidaServ.cs @@ -88,7 +88,7 @@ namespace OliviaAddInPro.Services //se consigue el tiempo en este instante para añadirlo a los nombres de los archivos de salida (shapefiles) fechaHora = DateTime.Now.ToString("yyyyMMdd_Hmmss"); //Pone nombre al shape en función de los ámbitos, el tratamiento, y los polígonos + timestamp - //reco.NombreShpExport = prefNameExport + "T" + reco.TipoTto.ToString("00") + nombFileAmbs + DameStrPoligs() + "_" + fechaHora + extShp; + reco.NombreShpExport = prefNameExport + "T" + reco.TipoTto.ToString("00") + nombFileAmbs + DameStrPoligs() + "_" + fechaHora + extShp; string msg = ""; //comienza ejecucion diff --git a/View/Limpieza/PaneLimpiezaSub1.xaml b/View/Limpieza/PaneLimpiezaSub1.xaml index 79788b8..a33a061 100644 --- a/View/Limpieza/PaneLimpiezaSub1.xaml +++ b/View/Limpieza/PaneLimpiezaSub1.xaml @@ -5,7 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:extensions="clr-namespace:ArcGIS.Desktop.Extensions;assembly=ArcGIS.Desktop.Extensions" xmlns:ui="clr-namespace:OliviaAddInPro" - mc:Ignorable="d" d:DesignWidth="300" Height="350" + mc:Ignorable="d" d:DesignWidth="300" Height="396" d:DataContext="{Binding Path=ui.PaneLimpiezaSub1ViewModel}" Loaded="UserControl_Loaded" Unloaded="UserControl_Unloaded" > @@ -14,7 +14,7 @@ - + diff --git a/View/Limpieza/PaneLimpiezaSub1.xaml.cs b/View/Limpieza/PaneLimpiezaSub1.xaml.cs index 00fdccd..891153a 100644 --- a/View/Limpieza/PaneLimpiezaSub1.xaml.cs +++ b/View/Limpieza/PaneLimpiezaSub1.xaml.cs @@ -41,6 +41,10 @@ namespace OliviaAddInPro { e.Handled = !PanelGlobal.IsValid(((TextBox)sender).Text + e.Text, 1, 100); } + private void txtBox_ancho_via_PreviewTextInput(object sender, TextCompositionEventArgs e) + { + e.Handled = !PanelGlobal.IsValid(((TextBox)sender).Text + e.Text, 1, 50); + } private void Button_Click(object sender, RoutedEventArgs e) { @@ -98,5 +102,6 @@ namespace OliviaAddInPro { } + } } diff --git a/ViewModel/Limpieza/PaneLimpiezaSub1ViewModel.cs b/ViewModel/Limpieza/PaneLimpiezaSub1ViewModel.cs index 38a1d09..c8eb17a 100644 --- a/ViewModel/Limpieza/PaneLimpiezaSub1ViewModel.cs +++ b/ViewModel/Limpieza/PaneLimpiezaSub1ViewModel.cs @@ -160,6 +160,34 @@ namespace OliviaAddInPro base.NotifyPropertyChanged("AmbitosSel"); } } + private string textAnchoVia; + public string TextAnchoVia + { + get { return textAnchoVia; } + set { base.SetProperty(ref textAnchoVia, value, () => TextAnchoVia); } + } + private System.Windows.Visibility visTextAnchoVia = System.Windows.Visibility.Hidden; + public System.Windows.Visibility VisTextAnchoVia + { + get { return visTextAnchoVia; } + set { base.SetProperty(ref visTextAnchoVia, value, () => VisTextAnchoVia); } + } + /*private bool enableListBoxAmb; + public bool EnableListBoxAmb + { + get { return (enableListBoxAmb && CapaAbierta); } + set { base.SetProperty(ref enableListBoxAmb, value, () => EnableListBoxAmb); } + } + public override bool CapaAbierta + { + get { return base.CapaAbierta; } + set + { + base.CapaAbierta = value; + base.NotifyPropertyChanged("CapaAbierta"); + NotifyPropertyChanged("EnableListBoxAmb"); + } + }*/ #endregion Properties public PaneLimpiezaSub1ViewModel() @@ -170,6 +198,7 @@ namespace OliviaAddInPro lblUdsTimeTto = "min"; lblUdsVeloDespl = "km/h"; limpServ = new LimpiezaServ(null); //no hace falta instancia limp + textAnchoVia = LimpiezaDef.Parametros.ancho_via.ToString(); } /** @@ -181,6 +210,7 @@ namespace OliviaAddInPro CapaElems = string.Empty; OpsAmbs.Clear(); Ambitos.Clear(); + VisTextAnchoVia = System.Windows.Visibility.Hidden; OliviaGlob.AddFlagTipEjec(TiposEjecucion.Config); //lo reinicia, por si estaba después de planificar if (string.IsNullOrEmpty(capa)) return false; @@ -241,6 +271,7 @@ namespace OliviaAddInPro ////////////////////////////////////////////////////////////// //rellena el combo de opciones de los ambitos + VisTextAnchoVia = System.Windows.Visibility.Hidden; Ambitos.Clear(); OpsAmbs.Clear(); OpsAmbs.Add("Editable"); @@ -294,12 +325,37 @@ namespace OliviaAddInPro { if (opAmb < 0) return; - Ambitos.Clear(); - SelOpAmb = opAmb; - ObservableCollection lista; - lista = pon_ambitos(); - //checkea los ámbitos de esta opción - check_ambitos(SelOpAmb, lista); + try { + Ambitos.Clear(); + SelOpAmb = opAmb; + ObservableCollection lista; + lista = pon_ambitos(); + //checkea los ámbitos de esta opción + check_ambitos(SelOpAmb, lista); + + if (SelOpAmb == 1) + { + //permite visualizar los elementos del ancho de vía que se activará cuando se seleccione la opción genérica de ejes de calle siempre y cuando el tiempo de tratamiento sea en ml/h + if (UdsTTto != (int)GeneralDef.OlvTiposTto.OlvTipTtoM2h_eje) + { + VisTextAnchoVia = System.Windows.Visibility.Visible; + } + } + else + { + VisTextAnchoVia = System.Windows.Visibility.Hidden; + } + /*if (((TipoTto == (int)LimpiezaDef.TiposTto.TtoBaldMecCalz) && (SelOpAmb >= 2)) || + ((TipoTto == (int)LimpiezaDef.TiposTto.TtoCaidaHoja) && (SelOpAmb >= 2))) + EnableListBoxAmb = false; //si uno de los ámbitos es "eje de calle" no se puede combinar con los demás ámbitos + else + EnableListBoxAmb = true;*/ + } + catch (Exception) + { + //MessageBox.Show("Error al seleccionar ámbitos", "Olivia", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } } /**Checkea de la lista los ámbitos de trabajo en función del tipo de tratamiento diff --git a/ViewModel/Limpieza/PaneLimpiezaViewModel.cs b/ViewModel/Limpieza/PaneLimpiezaViewModel.cs index 29d4a74..18fa29a 100644 --- a/ViewModel/Limpieza/PaneLimpiezaViewModel.cs +++ b/ViewModel/Limpieza/PaneLimpiezaViewModel.cs @@ -131,6 +131,26 @@ namespace OliviaAddInPro limp.Ttto = _subPanel1ViewModel.TimeTto; limp.UdsTTto = _subPanel1ViewModel.UdsTTto; + //lee el ancho medio de la vía si está visible (se ha seleccionado la opción genérica Eje de calles) + limp.AnchoVia = LimpiezaDef.Parametros.ancho_via; + if (_subPanel1ViewModel.VisTextAnchoVia == System.Windows.Visibility.Visible) + { + try + { + limp.AnchoVia = Convert.ToDouble(_subPanel1ViewModel.TextAnchoVia); + if ((limp.AnchoVia == 0) || (limp.AnchoVia > LimpiezaDef.Parametros.ancho_viaM) || (limp.AnchoVia < LimpiezaDef.Parametros.ancho_viam)) + { + err_str = "El ancho de la vía no está dentro de los límites configurados"; + return false; + } + } + catch (FormatException) + { + err_str = "El formato introducido para el ancho de la vía no es válido."; + return false; + } + } + //lee las propiedades comunes a recogida if (!LeeComun(limp,out err_str)) {