Class FuzzyPointLocator

  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.List;
 17  
 18 import org.locationtech.jts.algorithm.PointLocator;
 19 import org.locationtech.jts.geom.Coordinate;
 20 import org.locationtech.jts.geom.CoordinateSequence;
 21 import org.locationtech.jts.geom.Geometry;
 22 import org.locationtech.jts.geom.GeometryFactory;
 23 import org.locationtech.jts.geom.GeometryFilter;
 24 import org.locationtech.jts.geom.LineSegment;
 25 import org.locationtech.jts.geom.LineString;
 26 import org.locationtech.jts.geom.Location;
 27 import org.locationtech.jts.geom.MultiLineString;
 28 import org.locationtech.jts.geom.Polygon;
 29  
 30 /**
 31  * Finds the most likely {@link Location} of a point relative to
 32  * the polygonal components of a geometry, using a tolerance value.
 33  * If a point is not clearly in the Interior or Exterior,
 34  * it is considered to be on the Boundary.
 35  * In other words, if the point is within the tolerance of the Boundary,
 36  * it is considered to be on the Boundary; otherwise, 
 37  * whether it is Interior or Exterior is determined directly.
 38  *
 39  * @author Martin Davis
 40  * @version 1.7
 41  */
 42 public class FuzzyPointLocator
 43 {
 44   private Geometry g;
 45   private double boundaryDistanceTolerance;
 46   private MultiLineString linework;
 47   private PointLocator ptLocator = new PointLocator();
 48   private LineSegment seg = new LineSegment();
 49   
 50   public FuzzyPointLocator(Geometry g, double boundaryDistanceTolerance)
 51   {
 52     this.g = g;
 53     this.boundaryDistanceTolerance = boundaryDistanceTolerance;
 54     linework = extractLinework(g);
 55   }
 56  
 57   public int getLocation(Coordinate pt)
 58   {
 59     if (isWithinToleranceOfBoundary(pt))
 60             return Location.BOUNDARY;
 61     /*
 62     double dist = linework.distance(point);
 63
 64     // if point is close to boundary, it is considered to be on the boundary
 65     if (dist < tolerance)
 66       return Location.BOUNDARY;
 67      */
 68     
 69     // now we know point must be clearly inside or outside geometry, so return actual location value
 70     return ptLocator.locate(pt, g);
 71   }
 72  
 73   /**
 74    * Extracts linework for polygonal components.
 75    * 
 76    * @param g the geometry from which to extract
 77    * @return a lineal geometry containing the extracted linework
 78    */
 79   private MultiLineString extractLinework(Geometry g)
 80   {
 81       PolygonalLineworkExtracter extracter = new PolygonalLineworkExtracter();
 82       g.apply(extracter);
 83       List linework = extracter.getLinework();
 84       LineString[] lines = GeometryFactory.toLineStringArray(linework);
 85       return g.getFactory().createMultiLineString(lines);
 86   }
 87   
 88   private boolean isWithinToleranceOfBoundary(Coordinate pt)
 89   {
 90       for (int i = 0; i < linework.getNumGeometries(); i++) {
 91           LineString line = (LineString) linework.getGeometryN(i);
 92           CoordinateSequence seq = line.getCoordinateSequence();
 93           for (int j = 0; j < seq.size() - 1; j++) {
 94                seq.getCoordinate(j, seg.p0);
 95                seq.getCoordinate(j + 1, seg.p1);
 96                double dist = seg.distance(pt);
 97                if (dist <= boundaryDistanceTolerance)
 98                    return true;
 99           }
100       }
101       return false;
102   }
103 }
104  
105 /**
106  * Extracts the LineStrings in the boundaries 
107  * of all the polygonal elements in the target {@link Geometry}.
108  * 
109  * @author Martin Davis
110  */
111 class PolygonalLineworkExtracter 
112     implements GeometryFilter
113 {
114     private List linework
115     
116     public PolygonalLineworkExtracter()
117     {
118         linework = new ArrayList();
119     }
120     
121     /**
122      * Filters out all linework for polygonal elements
123      */
124     public void filter(Geometry g)
125     {
126         if (g instanceof Polygon) {
127             Polygon poly = (Polygon) g;
128             linework.add(poly.getExteriorRing());
129             for (int i = 0; i < poly.getNumInteriorRing(); i++) {
130                 linework.add(poly.getInteriorRingN(i));
131             }
132         }
133     }
134     
135     /**
136      * Gets the list of polygonal linework.
137      * 
138      * @return a List of LineStrings
139      */
140     public List getLinework() { return linework; }
141 }
142