Class OffsetPointGenerator

  1 /*
  2  * Copyright (c) 2016 Vivid Solutions.
  3  *
  4  * All rights reserved. This program and the accompanying materials
  5  * are made available under the terms of the Eclipse Public License 2.0
  6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
  7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
  8  * and the Eclipse Distribution License is available at
  9  *
 10  * http://www.eclipse.org/org/documents/edl-v10.php.
 11  */
 12  
 13 package org.locationtech.jts.operation.overlay.validate;
 14  
 15 import java.util.ArrayList;
 16 import java.util.Iterator;
 17 import java.util.List;
 18  
 19 import org.locationtech.jts.geom.Coordinate;
 20 import org.locationtech.jts.geom.Geometry;
 21 import org.locationtech.jts.geom.LineString;
 22 import org.locationtech.jts.geom.util.LinearComponentExtracter;
 23  
 24 /**
 25  * Generates points offset by a given distance 
 26  * from both sides of the midpoint of
 27  * all segments in a {@link Geometry}.
 28  * Can be used to generate probe points for
 29  * determining whether a polygonal overlay result
 30  * is incorrect.
 31  * The input geometry may have any orientation for its rings,
 32  * but {@link #setSidesToGenerate(boolean, boolean)} is
 33  * only meaningful if the orientation is known.
 34  *
 35  * @author Martin Davis
 36  * @version 1.7
 37  */
 38 public class OffsetPointGenerator
 39 {
 40   private Geometry g;
 41   private boolean doLeft = true
 42   private boolean doRight = true;
 43   
 44   public OffsetPointGenerator(Geometry g)
 45   {
 46     this.g = g;
 47   }
 48  
 49   /**
 50    * Set the sides on which to generate offset points.
 51    * 
 52    * @param doLeft
 53    * @param doRight
 54    */
 55   public void setSidesToGenerate(boolean doLeft, boolean doRight)
 56   {
 57     this.doLeft = doLeft;
 58     this.doRight = doRight;
 59   }
 60   
 61   /**
 62    * Gets the computed offset points.
 63    *
 64    * @return List<Coordinate>
 65    */
 66   public List getPoints(double offsetDistance)
 67   {
 68     List offsetPts = new ArrayList();
 69     List lines = LinearComponentExtracter.getLines(g);
 70     for (Iterator i = lines.iterator(); i.hasNext(); ) {
 71       LineString line = (LineString) i.next();
 72       extractPoints(line, offsetDistance, offsetPts);
 73     }
 74     //System.out.println(toMultiPoint(offsetPts));
 75     return offsetPts;
 76   }
 77  
 78   private void extractPoints(LineString line, double offsetDistance, List offsetPts)
 79   {
 80     Coordinate[] pts = line.getCoordinates();
 81     for (int i = 0; i < pts.length - 1; i++) {
 82         computeOffsetPoints(pts[i], pts[i + 1], offsetDistance, offsetPts);
 83     }
 84   }
 85  
 86   /**
 87    * Generates the two points which are offset from the 
 88    * midpoint of the segment <tt>(p0, p1)</tt> by the
 89    * <tt>offsetDistance</tt>.
 90    * 
 91    * @param p0 the first point of the segment to offset from
 92    * @param p1 the second point of the segment to offset from
 93    */
 94   private void computeOffsetPoints(Coordinate p0, Coordinate p1, double offsetDistance, List offsetPts)
 95   {
 96     double dx = p1.x - p0.x;
 97     double dy = p1.y - p0.y;
 98     double len = Math.sqrt(dx * dx + dy * dy);
 99     // u is the vector that is the length of the offset, in the direction of the segment
100     double ux = offsetDistance * dx / len;
101     double uy = offsetDistance * dy / len;
102  
103     double midX = (p1.x + p0.x) / 2;
104     double midY = (p1.y + p0.y) / 2;
105  
106     if (doLeft) {
107       Coordinate offsetLeft = new Coordinate(midX - uy, midY + ux);
108       offsetPts.add(offsetLeft);
109     }
110     
111     if (doRight) {
112       Coordinate offsetRight = new Coordinate(midX + uy, midY - ux);
113       offsetPts.add(offsetRight);
114     }
115   }
116  
117 }
118