/* * The JTS Topology Suite is a collection of Java classes that * implement the fundamental operations required to validate a given * geo-spatial data set to a known topological specification. * * Copyright (C) 2001 Vivid Solutions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.revolsys.geometry.model; import java.util.List; import java.util.function.Function; import com.revolsys.datatype.DataTypes; import com.revolsys.geometry.graph.linemerge.LineMerger; import com.revolsys.geometry.index.LineSegmentIndex; import com.revolsys.geometry.model.editor.LinealEditor; import com.revolsys.geometry.model.editor.MultiLineStringEditor; import com.revolsys.geometry.model.segment.LineSegment; import com.revolsys.geometry.model.segment.Segment; import com.revolsys.geometry.model.vertex.Vertex; import com.revolsys.geometry.operation.simple.DuplicateVertexError; import com.revolsys.geometry.operation.simple.SelfIntersectionPointError; import com.revolsys.geometry.operation.simple.SelfIntersectionVertexError; import com.revolsys.geometry.operation.simple.SelfOverlapLineSegmentError; import com.revolsys.geometry.operation.simple.SelfOverlapSegmentError; import com.revolsys.geometry.operation.valid.GeometryValidationError; /** * Identifies {@link Geometry} subclasses which * are 1-dimensional and have components which are {@link LineString}s. * */ public interface Lineal extends Geometry { static boolean addIsSimpleErrors(final Lineal lineal, final List<GeometryValidationError> errors, final boolean shortCircuit) { final LineSegmentIndex index = new LineSegmentIndex(lineal); for (final Segment segment : lineal.segments()) { final int segmentIndex = segment.getSegmentIndex(); final int partIndex = segment.getPartIndex(); if (segment.getLength() == 0) { errors.add(new DuplicateVertexError(segment.getGeometryVertex(0))); } else { final List<LineSegment> segments = index.queryBoundingBox(segment); for (final LineSegment lineSegment : segments) { final Segment segment2 = (Segment)lineSegment; final int partIndex2 = segment2.getPartIndex(); final int segmentIndex2 = segment2.getSegmentIndex(); if (partIndex2 > partIndex || partIndex == partIndex2 && segmentIndex2 > segmentIndex) { if (segment.equals(lineSegment)) { final SelfOverlapSegmentError error = new SelfOverlapSegmentError(segment); errors.add(error); if (shortCircuit) { return false; } } else { final Geometry intersection = segment.getIntersection(lineSegment); if (intersection instanceof Point) { final Point pointIntersection = (Point)intersection; boolean isIntersection = true; // Process segments on the same linestring part if (partIndex == partIndex2) { // The end of the current segment can touch the start of the // next // segment if (segmentIndex + 1 == segmentIndex2) { if (lineSegment.equalsVertex(2, 0, pointIntersection)) { isIntersection = false; } // A loop can touch itself at the start/end } else if (segment.isLineClosed()) { if (segment.isLineStart() && segment2.isLineEnd()) { if (segment.equalsVertex(2, 0, pointIntersection)) { isIntersection = false; } } } } else { if (!segment.isLineClosed() && !segment2.isLineClosed()) { final boolean segment1EndIntersection = segment .isEndIntersection(pointIntersection); final boolean segment2EndIntersection = segment2 .isEndIntersection(pointIntersection); if (segment1EndIntersection && segment2EndIntersection) { isIntersection = false; } } } if (isIntersection) { GeometryValidationError error; if (segment.equalsVertex(2, 0, pointIntersection)) { final Vertex vertex = segment.getGeometryVertex(0); error = new SelfIntersectionVertexError(vertex); } else if (segment.equalsVertex(2, 1, pointIntersection)) { final Vertex vertex = segment.getGeometryVertex(1); error = new SelfIntersectionVertexError(vertex); } else { error = new SelfIntersectionPointError(lineal, pointIntersection); } errors.add(error); if (shortCircuit) { return false; } } } else if (intersection instanceof LineSegment) { final LineSegment lineIntersection = (LineSegment)intersection; GeometryValidationError error; if (segment.equals(lineIntersection)) { error = new SelfOverlapSegmentError(segment); } else if (lineSegment.equals(lineIntersection)) { error = new SelfOverlapSegmentError(segment2); } else { error = new SelfOverlapLineSegmentError(lineal, lineIntersection); } errors.add(error); if (shortCircuit) { return false; } } } } } } } return errors.isEmpty(); } @SuppressWarnings("unchecked") static <G extends Geometry> G newLineal(final Object value) { if (value == null) { return null; } else if (value instanceof Lineal) { final Lineal lineal = (Lineal)value; if (lineal.getGeometryCount() == 1) { return lineal.getGeometry(0); } else { return (G)value; } } else if (value instanceof Geometry) { final Geometry geometry = (Geometry)value; if (geometry.isGeometryCollection()) { if (geometry.isEmpty()) { final GeometryFactory geometryFactory = geometry.getGeometryFactory(); return (G)geometryFactory.polygon(); } else if (geometry.getGeometryCount() == 1) { final Geometry part = geometry.getGeometry(0); if (part instanceof Lineal) { final Lineal lineal = (Lineal)part; return (G)lineal; } } } throw new IllegalArgumentException( "Expecting a Lineal geometry not " + geometry.getGeometryType() + "\n" + geometry); } else { final String string = DataTypes.toString(value); final Geometry geometry = GeometryFactory.DEFAULT_3D.geometry(string, false); return (G)newLineal(geometry); } } @Override default boolean addIsSimpleErrors(final List<GeometryValidationError> errors, final boolean shortCircuit) { return addIsSimpleErrors(this, errors, shortCircuit); } Lineal applyLineal(final Function<LineString, LineString> function); double getCoordinate(int partIndex, int vertexIndex, int axisIndex); LineString getLineString(int partIndex); default double getM(final int partIndex, final int vertexIndex) { return getCoordinate(partIndex, vertexIndex, M); } default double getX(final int partIndex, final int vertexIndex) { return getCoordinate(partIndex, vertexIndex, X); } default double getY(final int partIndex, final int vertexIndex) { return getCoordinate(partIndex, vertexIndex, Y); } default double getZ(final int partIndex, final int vertexIndex) { return getCoordinate(partIndex, vertexIndex, Z); } boolean isClosed(); Iterable<LineString> lineStrings(); default Lineal mergeLines() { if (isEmpty()) { return this; } else { final LineMerger merger = new LineMerger(this); return merger.getLineal(); } } @Override Lineal newGeometry(final GeometryFactory geometryFactory); @Override default LinealEditor newGeometryEditor() { return new MultiLineStringEditor(this); } @Override default LinealEditor newGeometryEditor(final int axisCount) { final LinealEditor geometryEditor = newGeometryEditor(); geometryEditor.setAxisCount(axisCount); return geometryEditor; } default Lineal newLineal(final GeometryFactory geometryFactory, final LineString... lines) { return geometryFactory.lineal(lines); } @Override Lineal normalize(); }