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

com.vividsolutions.jts.index.chain.MonotoneChain Maven / Gradle / Ivy

The newest version!


/*
 * 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.vividsolutions.jts.index.chain;

import com.vividsolutions.jts.geom.*;


/**
 * Monotone Chains are a way of partitioning the segments of a linestring to
 * allow for fast searching of intersections.
 * They have the following properties:
 * 
    *
  1. the segments within a monotone chain never intersect each other *
  2. the envelope of any contiguous subset of the segments in a monotone chain * is equal to the envelope of the endpoints of the subset. *
* Property 1 means that there is no need to test pairs of segments from within * the same monotone chain for intersection. *

* Property 2 allows * an efficient binary search to be used to find the intersection points of two monotone chains. * For many types of real-world data, these properties eliminate a large number of * segment comparisons, producing substantial speed gains. *

* One of the goals of this implementation of MonotoneChains is to be * as space and time efficient as possible. One design choice that aids this * is that a MonotoneChain is based on a subarray of a list of points. * This means that new arrays of points (potentially very large) do not * have to be allocated. *

* * MonotoneChains support the following kinds of queries: *

    *
  • Envelope select: determine all the segments in the chain which * intersect a given envelope *
  • Overlap: determine all the pairs of segments in two chains whose * envelopes overlap *
* * This implementation of MonotoneChains uses the concept of internal iterators * ({@link MonotoneChainSelectAction} and {@link MonotoneChainOverlapAction}) * to return the results for queries. * This has time and space advantages, since it * is not necessary to build lists of instantiated objects to represent the segments * returned by the query. * Queries made in this manner are thread-safe. * * @version 1.7 */ public class MonotoneChain { private Coordinate[] pts; private int start, end; private Envelope env = null; private Object context = null;// user-defined information private int id;// useful for optimizing chain comparisons public MonotoneChain(Coordinate[] pts, int start, int end, Object context) { this.pts = pts; this.start = start; this.end = end; this.context = context; } public void setId(int id) { this.id = id; } public int getId() { return id; } public Object getContext() { return context; } public Envelope getEnvelope() { if (env == null) { Coordinate p0 = pts[start]; Coordinate p1 = pts[end]; env = new Envelope(p0, p1); } return env; } public int getStartIndex() { return start; } public int getEndIndex() { return end; } /** * Gets the line segment starting at index * * @param index index of segment * @param ls line segment to extract into */ public void getLineSegment(int index, LineSegment ls) { ls.p0 = pts[index]; ls.p1 = pts[index + 1]; } /** * Return the subsequence of coordinates forming this chain. * Allocates a new array to hold the Coordinates */ public Coordinate[] getCoordinates() { Coordinate coord[] = new Coordinate[end - start + 1]; int index = 0; for (int i = start; i <= end; i++) { coord[index++] = pts[i]; } return coord; } /** * Determine all the line segments in the chain whose envelopes overlap * the searchEnvelope, and process them. *

* The monotone chain search algorithm attempts to optimize * performance by not calling the select action on chain segments * which it can determine are not in the search envelope. * However, it *may* call the select action on segments * which do not intersect the search envelope. * This saves on the overhead of checking envelope intersection * each time, since clients may be able to do this more efficiently. * * @param searchEnv the search envelope * @param mcs the select action to execute on selected segments */ public void select(Envelope searchEnv, MonotoneChainSelectAction mcs) { computeSelect(searchEnv, start, end, mcs); } private void computeSelect( Envelope searchEnv, int start0, int end0, MonotoneChainSelectAction mcs ) { Coordinate p0 = pts[start0]; Coordinate p1 = pts[end0]; mcs.tempEnv1.init(p0, p1); //Debug.println("trying:" + p0 + p1 + " [ " + start0 + ", " + end0 + " ]"); // terminating condition for the recursion if (end0 - start0 == 1) { //Debug.println("computeSelect:" + p0 + p1); mcs.select(this, start0); return; } // nothing to do if the envelopes don't overlap if (! searchEnv.intersects(mcs.tempEnv1)) return; // the chains overlap, so split each in half and iterate (binary search) int mid = (start0 + end0) / 2; // Assert: mid != start or end (since we checked above for end - start <= 1) // check terminating conditions before recursing if (start0 < mid) { computeSelect(searchEnv, start0, mid, mcs); } if (mid < end0) { computeSelect(searchEnv, mid, end0, mcs); } } /** * Determine all the line segments in two chains which may overlap, and process them. *

* The monotone chain search algorithm attempts to optimize * performance by not calling the overlap action on chain segments * which it can determine do not overlap. * However, it *may* call the overlap action on segments * which do not actually interact. * This saves on the overhead of checking intersection * each time, since clients may be able to do this more efficiently. * * @param searchEnv the search envelope * @param mco the overlap action to execute on selected segments */ public void computeOverlaps(MonotoneChain mc, MonotoneChainOverlapAction mco) { computeOverlaps(start, end, mc, mc.start, mc.end, mco); } private void computeOverlaps( int start0, int end0, MonotoneChain mc, int start1, int end1, MonotoneChainOverlapAction mco) { Coordinate p00 = pts[start0]; Coordinate p01 = pts[end0]; Coordinate p10 = mc.pts[start1]; Coordinate p11 = mc.pts[end1]; //Debug.println("computeIntersectsForChain:" + p00 + p01 + p10 + p11); // terminating condition for the recursion if (end0 - start0 == 1 && end1 - start1 == 1) { mco.overlap(this, start0, mc, start1); return; } // nothing to do if the envelopes of these chains don't overlap mco.tempEnv1.init(p00, p01); mco.tempEnv2.init(p10, p11); if (! mco.tempEnv1.intersects(mco.tempEnv2)) return; // the chains overlap, so split each in half and iterate (binary search) int mid0 = (start0 + end0) / 2; int mid1 = (start1 + end1) / 2; // Assert: mid != start or end (since we checked above for end - start <= 1) // check terminating conditions before recursing if (start0 < mid0) { if (start1 < mid1) computeOverlaps(start0, mid0, mc, start1, mid1, mco); if (mid1 < end1) computeOverlaps(start0, mid0, mc, mid1, end1, mco); } if (mid0 < end0) { if (start1 < mid1) computeOverlaps(mid0, end0, mc, start1, mid1, mco); if (mid1 < end1) computeOverlaps(mid0, end0, mc, mid1, end1, mco); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy