/** * gvSIG. Desktop Geographic Information System. * * Copyright (C) 2007-2021 gvSIG Association. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * For any additional information, do not hesitate to contact us * at info AT gvsig.com, or visit our website www.gvsig.com. */ package org.gvsig.topology.rule; import org.gvsig.expressionevaluator.Expression; import org.gvsig.expressionevaluator.ExpressionUtils; import org.gvsig.expressionevaluator.GeometryExpressionBuilder; import org.gvsig.expressionevaluator.GeometryExpressionUtils; import org.gvsig.fmap.dal.feature.Feature; import org.gvsig.fmap.dal.feature.FeatureReference; import org.gvsig.fmap.dal.feature.FeatureSet; import org.gvsig.fmap.geom.Geometry; import org.gvsig.fmap.geom.GeometryUtils; import org.gvsig.fmap.geom.aggregate.Aggregate; import org.gvsig.fmap.geom.complex.Complex; import org.gvsig.tools.ToolsLocator; import org.gvsig.tools.dynobject.DynObject; import org.gvsig.tools.i18n.I18nManager; import org.gvsig.tools.task.SimpleTaskStatus; import org.gvsig.topology.lib.api.ExecuteTopologyRuleActionException; import org.gvsig.topology.lib.api.TopologyDataSet; import org.gvsig.topology.lib.api.TopologyReport; import org.gvsig.topology.lib.api.TopologyReportLine; import org.gvsig.topology.lib.api.TopologyRule; import org.gvsig.topology.lib.api.TopologyRuleFactory; import org.gvsig.topology.lib.spi.AbstractTopologyRule; import org.gvsig.topology.lib.spi.AbstractTopologyRuleAction; /** * * @author jjdelcerro */ @SuppressWarnings("UseSpecificCatch") public class PolygonMustNotOverlapWithPolygonRule extends AbstractTopologyRule { private class SubtractAction extends AbstractTopologyRuleAction { public SubtractAction() { super( PolygonMustNotOverlapWithPolygonRuleFactory.NAME, "Subtract", "Subtract", "The Subtract fix removes the overlapping portion of each feature that is causing the error and leaves a gap or void in its place. This fix can be applied to one or more selected Must Not Overlap With errors." ); } @Override public int execute(TopologyRule rule, TopologyReportLine line, DynObject parameters) { try { Geometry errorGeom = line.getError(); FeatureReference featRef1 = line.getFeature1(); Feature feat1 = featRef1.getFeature(); Geometry geom1 = feat1.getDefaultGeometry(); FeatureReference featRef2 = line.getFeature2(); Feature feat2 = featRef2.getFeature(); Geometry geom2 = feat2.getDefaultGeometry(); substract(featRef1, geom2, rule.getDataSet1()); substract(featRef2, geom1, rule.getDataSet2()); return EXECUTE_OK; } catch (Exception ex) { throw new ExecuteTopologyRuleActionException(ex); } } } private class MergeAction extends AbstractTopologyRuleAction { public MergeAction() { super( PolygonMustNotOverlapWithPolygonRuleFactory.NAME, "Merge", "Merge", "The Merge fix adds the portion of overlap from one feature and subtracts it from the others that are violating the rule. You need to pick the feature that receives the portion of overlap using the Merge dialog box. This fix can be applied to one Must Not Overlap With error only." ); } @Override public int execute(TopologyRule rule, TopologyReportLine line, DynObject parameters) { try { Geometry errorGeom = line.getError(); FeatureReference featRef1 = line.getFeature1(); Feature feat1 = featRef1.getFeature(); Geometry geom1 = feat1.getDefaultGeometry(); FeatureReference featRef2 = line.getFeature2(); substract(featRef2, geom1, rule.getDataSet2()); return EXECUTE_OK; } catch (Exception ex) { throw new ExecuteTopologyRuleActionException(ex); } } } private String geomName; private Expression expression = null; private GeometryExpressionBuilder expressionBuilder = null; public PolygonMustNotOverlapWithPolygonRule() { // for persistence only } public PolygonMustNotOverlapWithPolygonRule( TopologyRuleFactory factory, double tolerance, String dataSet1, String dataSet2 ) { super(factory, tolerance, dataSet1, dataSet2); this.addAction(new MergeAction()); this.addAction(new SubtractAction()); } @Override protected void check(SimpleTaskStatus taskStatus, TopologyReport report, Feature feature1) throws Exception { try { if (this.expression == null) { this.expression = ExpressionUtils.createExpression(); this.expressionBuilder = GeometryExpressionUtils.createExpressionBuilder(); this.geomName = feature1.getType().getDefaultGeometryAttributeName(); } Geometry polygon = feature1.getDefaultGeometry(); if (polygon == null) { return; } TopologyDataSet thisDataSet = this.getDataSet1(); TopologyDataSet otherDataSet = this.getDataSet2(); double theTolerance = this.getTolerance(); if (otherDataSet.getSpatialIndex() != null) { for (FeatureReference otherReference : otherDataSet.query(polygon)) { Feature otherFeature = otherReference.getFeature(); Geometry otherPolygon = otherFeature.getDefaultGeometry(); if (otherPolygon != null) { if (GeometryUtils.overlaps(polygon, otherPolygon, theTolerance)) { I18nManager i18n = ToolsLocator.getI18nManager(); Geometry error = polygon.intersection(otherPolygon); if (error != null) { if (error instanceof Complex) { error = ((Complex) error).createAggregate( Geometry.TYPES.MULTIPOLYGON, (Geometry g) -> GeometryUtils.isSubtype(Geometry.TYPES.MULTISURFACE, g.getGeometryType().getType()) || GeometryUtils.isSubtype(Geometry.TYPES.SURFACE, g.getGeometryType().getType()) ); if (((Aggregate) error).getPrimitivesNumber() == 0) { continue; } } else if (!(GeometryUtils.isSubtype(Geometry.TYPES.MULTISURFACE, error.getGeometryType().getType()) || GeometryUtils.isSubtype(Geometry.TYPES.SURFACE, error.getGeometryType().getType()))) { continue; } report.addLine(this, thisDataSet, otherDataSet, polygon, error, feature1.getReference(), otherFeature.getReference(), false, i18n.getTranslation("_The_polygon_overlay_with_other") ); } } } } } else { this.expression.setPhrase( this.expressionBuilder.ifnull( this.expressionBuilder.column(this.geomName), this.expressionBuilder.constant(false), this.expressionBuilder.ST_Overlaps( this.expressionBuilder.column(this.geomName), this.expressionBuilder.geometry(polygon) ) ).toString() ); FeatureSet otherFeatures = otherDataSet.getFeatureStore().getFeatureSet(this.expression); for (Feature otherFeature : otherFeatures) { if (otherFeature != null) { Geometry otherPolygon = otherFeature.getDefaultGeometry(); if (otherPolygon != null) { if (GeometryUtils.overlaps(polygon, otherPolygon, theTolerance)) { I18nManager i18n = ToolsLocator.getI18nManager(); Geometry error = polygon.intersection(otherPolygon); if (error != null) { if (error instanceof Complex) { error = ((Complex) error).createAggregate( Geometry.TYPES.MULTIPOLYGON, (Geometry g) -> GeometryUtils.isSubtype(Geometry.TYPES.MULTISURFACE, g.getGeometryType().getType()) || GeometryUtils.isSubtype(Geometry.TYPES.SURFACE, g.getGeometryType().getType()) ); if (((Aggregate) error).getPrimitivesNumber() == 0) { continue; } } else if (!(GeometryUtils.isSubtype(Geometry.TYPES.MULTISURFACE, error.getGeometryType().getType()) || GeometryUtils.isSubtype(Geometry.TYPES.SURFACE, error.getGeometryType().getType()))) { continue; } report.addLine(this, thisDataSet, otherDataSet, polygon, error, feature1.getReference(), otherFeature.getReference(), false, i18n.getTranslation("_The_polygon_overlay_with_other") ); } } } } } } } catch (Exception ex) { LOGGER.warn("Can't check feature.", ex); addCodeException(report, feature1, ex); } finally { } } }