/** * 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 PolygonMustNotOverlapPolygonRule extends AbstractTopologyRule { private class CreateFetureAction extends AbstractTopologyRuleAction { public CreateFetureAction() { super( PolygonMustNotOverlapPolygonRuleFactory.NAME, "CreateFeature", "Create Feature", "The Create Feature fix creates a new polygon feature out " + "of the error shape and removes the portion of " + "overlap from each of the features, causing the " + "error to create a planar representation of the " + "feature geometry. This fix can be applied to " + "one or more selected Must Not Overlap errors." ); } @Override public int execute(TopologyRule rule, TopologyReportLine line, DynObject parameters) { try { Geometry errorGeom = line.getError(); TopologyDataSet dataSet = rule.getDataSet1(); FeatureReference featRef1 = line.getFeature1(); Feature feat1 = featRef1.getFeature(); Geometry geom1 = feat1.getDefaultGeometry(); FeatureReference featRef2 = line.getFeature2(); Feature feat2 = featRef2.getFeature(); Geometry geom2 = feat2.getDefaultGeometry(); createNewFeature(featRef1, dataSet, errorGeom); substract(featRef1, geom2, rule.getDataSet1()); substract(featRef2, geom1, rule.getDataSet1()); return EXECUTE_OK; } catch (Exception ex) { throw new ExecuteTopologyRuleActionException(ex); } } } private class SubtractAction extends AbstractTopologyRuleAction { public SubtractAction() { super( PolygonMustNotOverlapPolygonRuleFactory.NAME, "Subtract", "Subtract", "The Subtract fix removes the overlapping portion of " + "geometry from 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 errors." ); } @Override public int execute(TopologyRule rule, TopologyReportLine line, DynObject parameters) { try { Geometry errorGeom = line.getError(); TopologyDataSet dataSet = rule.getDataSet1(); 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.getDataSet1()); return EXECUTE_OK; } catch (Exception ex) { throw new ExecuteTopologyRuleActionException(ex); } } } private class MergeAction extends AbstractTopologyRuleAction { public MergeAction() { super( PolygonMustNotOverlapPolygonRuleFactory.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 error only." ); } @Override public int execute(TopologyRule rule, TopologyReportLine line, DynObject parameters) { try { Geometry errorGeom = line.getError(); TopologyDataSet dataSet = rule.getDataSet1(); FeatureReference featRef1 = line.getFeature1(); Feature feat1 = featRef1.getFeature(); Geometry geom1 = feat1.getDefaultGeometry(); FeatureReference featRef2 = line.getFeature2(); substract(featRef2, geom1, rule.getDataSet1()); return EXECUTE_OK; } catch (Exception ex) { throw new ExecuteTopologyRuleActionException(ex); } } } private String geomName; private Expression expression = null; private GeometryExpressionBuilder expressionBuilder = null; public PolygonMustNotOverlapPolygonRule() { // for persistence only } public PolygonMustNotOverlapPolygonRule( TopologyRuleFactory factory, double tolerance, String dataSet1 ) { super(factory, tolerance, dataSet1); this.addAction(new CreateFetureAction()); 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; } double theTolerance = this.getTolerance(); TopologyDataSet theDataSet = this.getDataSet1(); if (theDataSet.getSpatialIndex() != null) { for (FeatureReference otherReference : theDataSet.query(polygon)) { if (otherReference.equals(feature1.getReference())) { continue; } 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, theDataSet, null, polygon, error, feature1.getReference(), otherReference, 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 features = theDataSet.getFeatureStore().getFeatureSet(this.expression); for (Feature feature : features) { if ( feature != null) { Geometry otherPolygon = feature.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, theDataSet, null, polygon, error, feature1.getReference(), feature.getReference(), false, i18n.getTranslation("_The_polygon_overlay_with_other") ); } } } } } } } catch (Exception ex) { LOGGER.warn("Can't check feature.", ex); addCodeException(report, feature1, ex); } finally { } } // private boolean overlaps(Geometry polygon, Geometry otherPolygon, double theTolerance) throws GeometryOperationNotSupportedException, GeometryOperationException { // Geometry polygon1 = polygon.buffer(-theTolerance); // Geometry otherPolygon1 = otherPolygon.buffer(-theTolerance); // boolean overlaps = false; // if (polygon1 != null) { // overlaps = polygon1.overlaps(otherPolygon); // } else if (otherPolygon1 != null) { // overlaps = polygon.overlaps(otherPolygon1); // } // return overlaps; // } }