MonotoneChainBuilder.java

/*
 * Copyright (c) 2016 Vivid Solutions.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *
 * http://www.eclipse.org/org/documents/edl-v10.php.
 */
package org.locationtech.jts.index.chain;

import java.util.ArrayList;
import java.util.List;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Quadrant;

/**
 * Constructs {@link MonotoneChain}s
 * for sequences of {@link Coordinate}s.
 *
 * @version 1.7
 */
public class MonotoneChainBuilder {

  /**
   * Computes a list of the {@link MonotoneChain}s
   * for a list of coordinates.
   * 
   * @param pts the list of points to compute chains for
   * @return a list of the monotone chains for the points 
   */
  public static List getChains(Coordinate[] pts)
  {
    return getChains(pts, null);
  }

  /**
   * Computes a list of the {@link MonotoneChain}s
   * for a list of coordinates, 
   * attaching a context data object to each.
   * 
   * @param pts the list of points to compute chains for
   * @param context a data object to attach to each chain
   * @return a list of the monotone chains for the points 
   */
  public static List getChains(Coordinate[] pts, Object context)
  {
    List mcList = new ArrayList();
    if (pts.length == 0)
      return mcList;
    int chainStart = 0;
    do {
      int chainEnd = findChainEnd(pts, chainStart);
      MonotoneChain mc = new MonotoneChain(pts, chainStart, chainEnd, context);
      mcList.add(mc);
      chainStart = chainEnd;
    } while (chainStart < pts.length -1);
    return mcList;
  }

  /**
   * Finds the index of the last point in a monotone chain
   * starting at a given point.
   * Repeated points (0-length segments) are included
   * in the monotone chain returned.
   * 
   * @param pts the points to scan
   * @param start the index of the start of this chain
   * @return the index of the last point in the monotone chain 
   * starting at <code>start</code>.
   */
  private static int findChainEnd(Coordinate[] pts, int start)
  {
  	int safeStart = start;
  	// skip any zero-length segments at the start of the sequence
  	// (since they cannot be used to establish a quadrant)
  	while (safeStart < pts.length - 1 && pts[safeStart].equals2D(pts[safeStart + 1])) {
  		safeStart++;
  	}
  	// check if there are NO non-zero-length segments
  	if (safeStart >= pts.length - 1) {
  		return pts.length - 1;
  	}
    // determine overall quadrant for chain (which is the starting quadrant)
    int chainQuad = Quadrant.quadrant(pts[safeStart], pts[safeStart + 1]);
    int last = start + 1;
    while (last < pts.length) {
    	// skip zero-length segments, but include them in the chain
    	if (! pts[last - 1].equals2D(pts[last])) {
        // compute quadrant for next possible segment in chain
    		int quad = Quadrant.quadrant(pts[last - 1], pts[last]);
      	if (quad != chainQuad) break;
    	}
      last++;
    }
    return last - 1;
  }

}