All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vividsolutions.jtstest.testbuilder.topostretch.StretchedVertexFinder Maven / Gradle / Ivy

The newest version!
package com.vividsolutions.jtstest.testbuilder.topostretch;

import java.util.*;
import com.vividsolutions.jts.algorithm.*;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.geom.util.*;

class StretchedVertexFinder 
{
	public static List findNear(Collection linestrings, double tolerance, Envelope mask)
	{
		StretchedVertexFinder finder = new StretchedVertexFinder(linestrings, tolerance, mask);
		return finder.getNearVertices();
	}
	
	private Collection linestrings;
	private double tolerance = 0.0;
	private Envelope limitEnv = null;
	private List nearVerts = new ArrayList();
	
	public StretchedVertexFinder(Collection linestrings, double tolerance)
	{
		this.linestrings = linestrings;
		this.tolerance = tolerance;
	}
	
	public StretchedVertexFinder(Collection linestrings, double tolerance, Envelope limitEnv)
	{
		this(linestrings, tolerance);
		this.limitEnv = limitEnv;
	}
	
	public List getNearVertices()
	{
		findNearVertices();
		return nearVerts;
	}
	
	private void findNearVertices()
	{
		for (Iterator i = linestrings.iterator(); i.hasNext(); ) {
			LineString line = (LineString) i.next();
			findNearVertices(line);
		}
		
	}
	
  private static int geomPointsLen(Coordinate[] pts)
  {
    int n = pts.length;
    // don't process the last point of a ring twice
    if (CoordinateArrays.isRing(pts))
      n = pts.length - 1;
    return n;
  }
  
	private void findNearVertices(LineString targetLine)
	{
		Coordinate[] pts = targetLine.getCoordinates();
    // don't process the last point of a ring twice
    int n = geomPointsLen(pts);
		for (int i = 0; i < n; i++) {
      if (limitEnv.intersects(pts[i]))
        findNearVertex(pts, i);
		}
	}
	
	private void findNearVertex(Coordinate[] linePts, int index)
	{
		for (Iterator i = linestrings.iterator(); i.hasNext(); ) {
			LineString testLine = (LineString) i.next();
			findNearVertex(linePts, index, testLine);
		}
	}

  /**
   * Finds a single near vertex.
   * This is simply the first one found, not necessarily 
   * the nearest.  
   * This choice may sub-optimal, resulting 
   * in odd result geometry.
   * It's not clear that this can be done better, however.
   * If there are several near points, the stretched
   * geometry is likely to be distorted anyway.
   * 
   * @param targetPts
   * @param index
   * @param testLine
   */
	private void findNearVertex(Coordinate[] targetPts, int index, LineString testLine)
	{
    Coordinate targetPt = targetPts[index];
		Coordinate[] testPts = testLine.getCoordinates();
    // don't process the last point of a ring twice
    int n = geomPointsLen(testPts);
		for (int i = 0; i < n; i++) {
			Coordinate testPt = testPts[i];
      
			StretchedVertex stretchVert = null;
	
			// is near to vertex?
			double dist = testPt.distance(targetPt);
			if (dist <= tolerance && dist != 0.0) {
				stretchVert = new StretchedVertex(targetPt, targetPts, index, testPt, testPts, i);
			}
      // is near segment?
			else if (i < testPts.length - 1) {
				Coordinate segEndPt = testPts[i + 1];
				
				/**
				 * Check whether pt is near or equal to other segment endpoint.
				 * If near, it will be handled by the near vertex case code.
				 * If equal, don't record it at all
				 */
				double distToOther = segEndPt.distance(targetPt);
				if (distToOther <= tolerance)
					// will be handled as a point-vertex case
					continue;
				
				// Here we know point is not near the segment endpoints.
				// Check if it is near the segment at all.
				if (isPointNearButNotOnSeg(targetPt, testPt, segEndPt, tolerance)) {
					stretchVert = new StretchedVertex(targetPt, targetPts, i, new LineSegment(testPt, testPts[i + 1]));
				}
			}
			if (stretchVert != null)
				nearVerts.add(stretchVert);
		}
	}
	
  private static boolean contains(Envelope env, Coordinate p0, Coordinate p1)
  {
    if (! env.contains(p0)) return false;
    if (! env.contains(p1)) return false;
    return true;
  }
  
	private static boolean isPointNearButNotOnSeg(Coordinate p, Coordinate p0, Coordinate p1, double distTol)
	{
		// don't rely on segment distance algorithm to correctly compute zero distance
		// on segment
		if (CGAlgorithms.computeOrientation(p0, p1, p) == CGAlgorithms.COLLINEAR)
			return false;

		// compute actual distance
		distSeg.p0 = p0;
		distSeg.p1 = p1;
		double segDist = distSeg.distance(p);
		if (segDist > distTol)
			return false;
		return true;
	}

	private static LineSegment distSeg = new LineSegment();
	
	private static double distanceToSeg(Coordinate p, Coordinate p0, Coordinate p1)
	{
		distSeg.p0 = p0;
		distSeg.p1 = p1;
		double segDist = distSeg.distance(p);
		
		// robust calculation of zero distance
		if (CGAlgorithms.computeOrientation(p0, p1, p) == CGAlgorithms.COLLINEAR)
			segDist = 0.0;
		
		return segDist;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy