Class CoordinateSequenceComparator

  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.geom;
 14  
 15 import java.util.Comparator;
 16  
 17 /**
 18  * Compares two {@link CoordinateSequence}s.
 19  * For sequences of the same dimension, the ordering is lexicographic.
 20  * Otherwise, lower dimensions are sorted before higher.
 21  * The dimensions compared can be limited; if this is done
 22  * ordinate dimensions above the limit will not be compared.
 23  * <p>
 24  * If different behaviour is required for comparing size, dimension, or
 25  * coordinate values, any or all methods can be overridden.
 26  *
 27  */
 28 public class CoordinateSequenceComparator
 29     implements Comparator
 30 {
 31   /**
 32    * Compare two <code>double</code>s, allowing for NaN values.
 33    * NaN is treated as being less than any valid number.
 34    *
 35    * @param a a <code>double</code>
 36    * @param b a <code>double</code>
 37    * @return -1, 0, or 1 depending on whether a is less than, equal to or greater than b
 38    */
 39   public static int compare(double a, double b)
 40   {
 41     if (a < b) return -1;
 42     if (a > b) return 1;
 43  
 44     if (Double.isNaN(a)) {
 45       if (Double.isNaN(b)) return 0;
 46       return -1;
 47     }
 48  
 49     if (Double.isNaN(b)) return 1;
 50     return 0;
 51   }
 52  
 53   /**
 54    * The number of dimensions to test
 55    */
 56   protected int dimensionLimit;
 57  
 58   /**
 59    * Creates a comparator which will test all dimensions.
 60    */
 61   public CoordinateSequenceComparator()
 62   {
 63     dimensionLimit = Integer.MAX_VALUE;
 64   }
 65  
 66   /**
 67    * Creates a comparator which will test only the specified number of dimensions.
 68    *
 69    * @param dimensionLimit the number of dimensions to test
 70    */
 71   public CoordinateSequenceComparator(int dimensionLimit)
 72   {
 73     this.dimensionLimit = dimensionLimit;
 74   }
 75  
 76   /**
 77    * Compares two {@link CoordinateSequence}s for relative order.
 78    *
 79    * @param o1 a {@link CoordinateSequence}
 80    * @param o2 a {@link CoordinateSequence}
 81    * @return -1, 0, or 1 depending on whether o1 is less than, equal to, or greater than o2
 82    */
 83   public int compare(Object o1, Object o2)
 84   {
 85     CoordinateSequence s1 = (CoordinateSequence) o1;
 86     CoordinateSequence s2 = (CoordinateSequence) o2;
 87  
 88     int size1 = s1.size();
 89     int size2 = s2.size();
 90  
 91     int dim1 = s1.getDimension();
 92     int dim2 = s2.getDimension();
 93  
 94     int minDim = dim1;
 95     if (dim2 < minDim)
 96       minDim = dim2;
 97     boolean dimLimited = false;
 98     if (dimensionLimit <= minDim) {
 99       minDim = dimensionLimit;
100       dimLimited = true;
101     }
102  
103     // lower dimension is less than higher
104     if (! dimLimited) {
105       if (dim1 < dim2) return -1;
106       if (dim1 > dim2) return 1;
107     }
108  
109     // lexicographic ordering of point sequences
110     int i = 0;
111     while (i < size1 && i < size2) {
112       int ptComp = compareCoordinate(s1, s2, i, minDim);
113       if (ptComp != 0return ptComp;
114       i++;
115     }
116     if (i < size1) return 1;
117     if (i < size2) return -1;
118  
119     return 0;
120   }
121  
122   /**
123    * Compares the same coordinate of two {@link CoordinateSequence}s
124    * along the given number of dimensions.
125    *
126    * @param s1 a {@link CoordinateSequence}
127    * @param s2 a {@link CoordinateSequence}
128    * @param i the index of the coordinate to test
129    * @param dimension the number of dimensions to test
130    * @return -1, 0, or 1 depending on whether s1[i] is less than, equal to, or greater than s2[i]
131    */
132   protected int compareCoordinate(CoordinateSequence s1, CoordinateSequence s2, int i, int dimension)
133   {
134     for (int d = 0; d < dimension; d++) {
135       double ord1 = s1.getOrdinate(i, d);
136       double ord2 = s2.getOrdinate(i, d);
137       int comp = compare(ord1, ord2);
138       if (comp != 0return comp;
139     }
140     return 0;
141   }
142 }
143