Package org.locationtech.udig.tools.geometry.trim

Source Code of org.locationtech.udig.tools.geometry.trim.TrimGeometryStrategy

/* uDig - User Friendly Desktop Internet GIS client
* http://udig.refractions.net
* (C) 2012, Refractions Research Inc.
* (C) 2006, Axios Engineering S.L. (Axios)
* (C) 2006, County Council of Gipuzkoa, Department of Environment and Planning
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Axios BSD
* License v1.0 (http://udig.refractions.net/files/asd3-v10.html).
*/
package org.locationtech.udig.tools.geometry.trim;

import java.text.MessageFormat;

import com.vividsolutions.jts.algorithm.CGAlgorithms;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.Point;

import org.locationtech.udig.tools.internal.i18n.Messages;

/**
* Performs the trimming of a LineString or MultiLineString using a provided
* LineString as cutting edge.
*
* @author Aritz Davila (www.axios.es)
* @author Mauricio Pazos (www.axios.es)
* @since 1.1.0
*/
public class TrimGeometryStrategy {

  private LineString  trimmingLine;

  public TrimGeometryStrategy(LineString trimmingLine) {
    this.trimmingLine = trimmingLine;
  }

  public static Geometry trim(Geometry input, LineString trimmingLine) {
    TrimGeometryStrategy op = new TrimGeometryStrategy(trimmingLine);
    Geometry trimmed = op.trim(input);
    return trimmed;
  }

  public Geometry trim(final Geometry original) {
    Geometry trimmed;
    if (original == null || original.isEmpty()) {
      return original;
    }
    if (original instanceof LineString) {
      trimmed = trimLine((LineString) original, trimmingLine);
    } else if (original instanceof MultiLineString) {
      MultiLineString input = (MultiLineString) original;
      GeometryFactory gf = input.getFactory();

      int numGeometries = input.getNumGeometries();
      LineString[] lines = new LineString[numGeometries];
      for (int i = 0; i < numGeometries; i++) {
        LineString part = (LineString) input.getGeometryN(i);
        LineString trimmedPart = trimLine(part, trimmingLine);
        lines[i] = trimmedPart;
      }
      trimmed = gf.createMultiLineString(lines);
    } else {

      throw new IllegalArgumentException(Messages.TrimGeometryStrategy_defined_for_line_geometries);
    }
    return trimmed;
  }

  /**
   * @param original
   * @param trimmingLine
   * @return if <code>original</code> intersects <code>trimmingLine</code>
   *         at a single point, the result of cutting off the part of
   *         <code>original</code> that lies at the right of
   *         <code>trimmingLine</code>. If they do not intersect, returns
   *         <code>original</code>.
   * @throws IllegalArgumentException
   */
  private LineString trimLine(final LineString original, final LineString trimmingLine)
    throws IllegalArgumentException {
    Geometry intersectGeom = original.intersection(trimmingLine);
    if (intersectGeom.isEmpty()) {
      return original;
    }

    assert intersectGeom instanceof Point : "The intersection between trim line and the feature must be a point.";

    Point intersection = (Point) intersectGeom;
    Coordinate intersectionPoint = intersection.getCoordinate();

    final Coordinate lineFrom = getCoordinateBeforePoint(trimmingLine, intersectionPoint);
    // if it happened that the intersection point is the starting point of
    // the trimming line
    // then lineTo is the next coordinate. Otherwise it is the intersection
    // point itself
    final Coordinate lineTo = intersectionPoint.equals2D(lineFrom) ? trimmingLine.getCoordinateN(1)
          : intersectionPoint;

    // split the line at the intersection point
    Geometry difference = original.difference(trimmingLine);

    LineString splitLine1;
    LineString splitLine2;
    if (difference instanceof MultiLineString) {
      splitLine1 = (LineString) difference.getGeometryN(0);
      splitLine2 = (LineString) difference.getGeometryN(1);
    } else if (difference instanceof LineString) {
      // original touches trimmingLine but does not crosses it
      splitLine1 = (LineString) difference;
      splitLine2 = difference.getFactory().createLineString(new Coordinate[0]);
    } else {
      throw new IllegalStateException(Messages.TrimGeometryStrategy_difference_unknown_type + difference);
    }

    Coordinate firstLinePoint = getCoordinateBeforePoint(splitLine1, intersectionPoint);
    if (firstLinePoint.equals2D(intersectionPoint)) {
      // same case as the comment for line1, or computeOrientation will
      // return COLLINEAR,
      // and we'll have no way to tell wether the line is at the right or
      // the left
      firstLinePoint = splitLine1.getCoordinateN(1);
    }

    final int firstLineOrientation = CGAlgorithms.computeOrientation(lineFrom, lineTo, firstLinePoint);

    LineString lineAtTheRight;

    // return the segment at the left of the intersection point
    if (CGAlgorithms.CLOCKWISE == firstLineOrientation) {
      lineAtTheRight = splitLine2;
    } else {
      lineAtTheRight = splitLine1;
    }
    return lineAtTheRight;
  }

  /**
   * Traverses the <code>line</code> in its digitizing order and returns the
   * <code>Coordinate</code> right before the <code>intersectionPoint</code>
   * on the segment that containst it.
   *
   * @param line
   * @param pointInLine
   * @return
   */
  private Coordinate getCoordinateBeforePoint(final LineString line, final Coordinate pointInLine) {
    Coordinate[] coordinates = line.getCoordinates();
    Coordinate[] segment = new Coordinate[2];

    final GeometryFactory gf = line.getFactory();
    final double DELTA_DISTANCE = 0.0000001;
    for (int i = 1; i < coordinates.length; i++) {
      segment[0] = coordinates[i - 1];
      segment[1] = coordinates[i];
      // CGAlgorithms.isOnLine is too precise and due to round off errors
      // almost
      // never returns true, even though intersectionPoint should be
      // guaranteed
      // to be over the line as it was produced by intersecting both lines
      // so we're using little buffer to determine if the point lies over the
      // segment
      Geometry lineSegment = gf.createLineString(segment);
      lineSegment = lineSegment.buffer(DELTA_DISTANCE, 2);
      Point point = gf.createPoint(pointInLine);
      Geometry intersection = lineSegment.intersection(point);
      if (point.equals(intersection)) {
        return segment[0];
      }
    }

    final String msg = MessageFormat.format(Messages.TrimGeometryStrategy_point_not_on_line, pointInLine, line);
    throw new IllegalArgumentException(msg);
  }
}
TOP

Related Classes of org.locationtech.udig.tools.geometry.trim.TrimGeometryStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.