Skip to content
Commits on Source (7)
......@@ -34,9 +34,11 @@ See also:
## Documentation
* Javadoc: [https://locationtech.github.io/jts/javadoc](https://locationtech.github.io/jts/javadoc)
* [**Javadoc**](https://locationtech.github.io/jts/javadoc)
* Frequently Asked Questions are documented in the [**FAQ**](https://locationtech.github.io/jts/jts-faq.html)
* Installing and using JTS is described in the [**User Guide**](USING.md).
* Building and developing with JTS is described in the [**Developing Guide**](DEVELOPING.md).
* Migrating from previous versions of JTS is described in the [**Upgrade Guide**](MIGRATION.md).
## Contributing
......
......@@ -82,3 +82,18 @@ Older versions of JTS are available on Maven Central.
<version>1.13</version>
</dependency>
```
## Using JTS with Jigsaw
JTS uses [#ModuleNameInManifest](http://openjdk.java.net/projects/jigsaw/spec/issues/#ModuleNameInManifest) to export a module name for each of the JARs published for use as a library. In this way, you can depend on the various JTS modules in your `module-info.java` in the following way:
```java
// module-info.java for project org.foo.baz
module org.foo.baz {
requires org.locationtech.jts; // jts-core
requires org.locationtech.jts.io; // jts-io-common
requires org.locationtech.jts.io.oracle; // jts-io-ora
requires org.locationtech.jts.io.sde; // jts-io-sde
}
```
......@@ -9,20 +9,10 @@ JAVA_OPTS="-Xms256M -Xmx1024M"
APP_OPTS=""
if test "x$JTS_LIB_DIR" = "x"; then
JTS_LIB_DIR=`dirname $0`/../lib/
JTS_LIB_DIR=`dirname $0`/../modules/app/target
fi
#---------------------------------#
# dynamically build the classpath #
#---------------------------------#
CP=
for i in `ls ${JTS_LIB_DIR}/*.jar`
do
CP=${CP}:${i}
done
#---------------------------#
# run the program #
#---------------------------#
MAIN=com.vividsolutions.jtstest.testbuilder.JTSTestBuilder
java -cp ".:${CP}" $JAVA_OPTS $JAVA_LOOKANDFEEL $MAIN $APP_OPTS
java -jar ${JAVA_OPTS} ${JAVA_LOOKANDFEEL} -jar ${JTS_LIB_DIR}/JTSTestBuilder.jar ${APP_OPTS}
#!/bin/sh
if test "x$JTS_LIB_DIR" = "x"; then
JTS_LIB_DIR=`dirname $0`/../lib/
JTS_LIB_DIR=`dirname $0`/../modules/tests/target
fi
#---------------------------------#
# dynamically build the classpath #
#---------------------------------#
THE_CLASSPATH=
for i in `ls ${JTS_LIB_DIR}/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
#---------------------------#
# run the program #
#---------------------------#
java -cp ".:${THE_CLASSPATH}" \
com.vividsolutions.jtstest.testrunner.TopologyTestApp $@
java -jar ${JTS_LIB_DIR}/JTSTestRunner.jar $@
jts (1.15.0+ds-1) UNRELEASED; urgency=medium
jts (1.15.1+ds-1~exp1) experimental; urgency=medium
* Team upload.
* New upstream release.
* Switch Homepage to SourceForge, tsusiatsoftware.net is expired.
* Strip trailing whitespace from changelog, control & rules files.
......@@ -16,8 +17,10 @@ jts (1.15.0+ds-1) UNRELEASED; urgency=medium
* Update copyright-format URL to use HTTPS.
* Update Vcs-* URLs for Salsa.
* Bump Standards-Version to 4.1.4, no changes.
* Add autopkgtest to test installability.
* Add lintian override for embedded-javascript-library.
-- Bas Couwenberg <sebastic@debian.org> Sun, 10 Dec 2017 21:30:30 +0100
-- Bas Couwenberg <sebastic@debian.org> Sat, 30 Jun 2018 21:26:23 +0200
jts (1.14+ds-2) unstable; urgency=medium
......
# jQuery from libjs-jquery is not compatible
embedded-javascript-library * please use libjs-jquery
embedded-javascript-library * please use libjs-jquery-ui
......@@ -13,10 +13,3 @@ Forwarded: not-needed
<build>
<plugins>
@@ -51,4 +51,4 @@
</plugin>
</plugins>
</build>
-</project>
\ No newline at end of file
+</project>
# Test installability
Depends: @
Test-Command: /bin/true
......@@ -3,7 +3,7 @@
<parent>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-modules</artifactId>
<version>1.15.0</version>
<version>1.15.1</version>
</parent>
<artifactId>jts-app</artifactId>
<name>${project.groupId}:${project.artifactId}</name>
......
......@@ -27,7 +27,7 @@ import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.geom.util.LinearComponentExtracter;
import org.locationtech.jts.noding.BasicSegmentString;
import org.locationtech.jts.noding.FastNodingValidator;
import org.locationtech.jts.noding.InteriorIntersectionFinder;
import org.locationtech.jts.noding.NodingIntersectionFinder;
import org.locationtech.jts.noding.IntersectionAdder;
import org.locationtech.jts.noding.MCIndexNoder;
import org.locationtech.jts.noding.Noder;
......@@ -92,7 +92,7 @@ public class NodingFunctions
public static int interiorIntersectionCount(Geometry geom)
{
InteriorIntersectionFinder intCounter = InteriorIntersectionFinder
NodingIntersectionFinder intCounter = NodingIntersectionFinder
.createIntersectionCounter( new RobustLineIntersector() );
Noder noder = new MCIndexNoder( intCounter );
noder.computeNodes( SegmentStringUtil.extractNodedSegmentStrings(geom) );
......
......@@ -31,6 +31,9 @@ import org.locationtech.jts.geom.*;
public class MultiLineHandler implements ShapeHandler{
int myShapeType = -1;
private PrecisionModel precisionModel = new PrecisionModel();
private GeometryFactory geometryFactory = new GeometryFactory(precisionModel, 0);
public MultiLineHandler()
{
......@@ -60,7 +63,7 @@ public class MultiLineHandler implements ShapeHandler{
if (shapeType ==0)
{
return new MultiLineString(null,new PrecisionModel(),0); //null shape
return geometryFactory.createMultiLineString(null); //null shape
}
if (shapeType != myShapeType)
......
......@@ -37,6 +37,8 @@ import org.locationtech.jts.geom.*;
*/
public class MultiPointHandler implements ShapeHandler {
int myShapeType= -1;
private PrecisionModel precisionModel = new PrecisionModel();
private GeometryFactory geometryFactory = new GeometryFactory(precisionModel, 0);
/** Creates new MultiPointHandler */
public MultiPointHandler() {
......@@ -60,7 +62,7 @@ public class MultiPointHandler implements ShapeHandler {
actualReadWords += 2;
if (shapeType ==0)
return new MultiPoint(null,new PrecisionModel(),0);
return geometryFactory.createMultiPointFromCoords(null);
if (shapeType != myShapeType)
{
throw new InvalidShapefileException("Multipointhandler.read() - expected type code "+myShapeType+" but got "+shapeType);
......@@ -134,7 +136,7 @@ public class MultiPointHandler implements ShapeHandler {
actualReadWords += 1;
}
return geometryFactory.createMultiPoint(coords);
return geometryFactory.createMultiPointFromCoords(coords);
}
double[] zMinMax(Geometry g)
......
......@@ -41,6 +41,8 @@ import org.locationtech.jts.geom.PrecisionModel;
*/
public class PolygonHandler implements ShapeHandler{
int myShapeType;
private PrecisionModel precisionModel = new PrecisionModel();
private GeometryFactory geometryFactory = new GeometryFactory(precisionModel, 0);
public PolygonHandler()
{
......@@ -87,7 +89,7 @@ public class PolygonHandler implements ShapeHandler{
if (shapeType ==0)
{
return new MultiPolygon(null,new PrecisionModel(),0); //null shape
return geometryFactory.createMultiPolygon(null); //null shape
}
if ( shapeType != myShapeType ) {
......@@ -118,8 +120,8 @@ public class PolygonHandler implements ShapeHandler{
}
//LinearRing[] rings = new LinearRing[numParts];
ArrayList shells = new ArrayList();
ArrayList holes = new ArrayList();
ArrayList<LinearRing> shells = new ArrayList<LinearRing>();
ArrayList<LinearRing> holes = new ArrayList<LinearRing>();
Coordinate[] coords = new Coordinate[numPoints];
for(int t=0;t<numPoints;t++)
......@@ -200,12 +202,12 @@ public class PolygonHandler implements ShapeHandler{
}
}
ArrayList holesForShells = assignHolesToShells(shells, holes);
ArrayList<ArrayList<LinearRing>> holesForShells = assignHolesToShells(shells, holes);
Polygon[] polygons = new Polygon[shells.size()];
for (int i = 0; i < shells.size(); i++) {
polygons[i] = geometryFactory.createPolygon((LinearRing) shells.get(i),
(LinearRing[]) ((ArrayList) holesForShells.get(i))
(LinearRing[]) ((ArrayList<LinearRing>) holesForShells.get(i))
.toArray(new LinearRing[0]));
}
......@@ -224,12 +226,12 @@ public class PolygonHandler implements ShapeHandler{
return result;
}
private ArrayList assignHolesToShells(ArrayList shells, ArrayList holes)
private ArrayList<ArrayList<LinearRing>> assignHolesToShells(ArrayList<LinearRing> shells, ArrayList<LinearRing> holes)
{
// now we have a list of all shells and all holes
ArrayList holesForShells = new ArrayList(shells.size());
ArrayList<ArrayList<LinearRing>> holesForShells = new ArrayList<ArrayList<LinearRing>>(shells.size());
for (int i = 0; i < shells.size(); i++) {
holesForShells.add(new ArrayList());
holesForShells.add(new ArrayList<LinearRing>());
}
// find homes
......@@ -269,7 +271,7 @@ public class PolygonHandler implements ShapeHandler{
}
else {
// ((ArrayList)holesForShells.get(shells.indexOf(minShell))).add(testRing);
((ArrayList) holesForShells.get(findIndex(shells, minShell)))
((ArrayList<LinearRing>) holesForShells.get(findIndex(shells, minShell)))
.add(testHole);
}
}
......@@ -299,24 +301,16 @@ public class PolygonHandler implements ShapeHandler{
}
public int getLength(Geometry geometry){
MultiPolygon multi;
if(geometry instanceof MultiPolygon){
multi = (MultiPolygon)geometry;
}
else{
multi = new MultiPolygon(new Polygon[]{(Polygon)geometry},geometry.getPrecisionModel(),geometry.getSRID());
}
int nrings=0;
for (int t=0;t<multi.getNumGeometries();t++)
for (int t=0;t<geometry.getNumGeometries();t++)
{
Polygon p;
p = (Polygon) multi.getGeometryN(t);
p = (Polygon) geometry.getGeometryN(t);
nrings = nrings + 1 + p.getNumInteriorRing();
}
int npoints = multi.getNumPoints();
int npoints = geometry.getNumPoints();
if (myShapeType == 15)
{
......
......@@ -106,7 +106,7 @@ public class Shapefile
if(mainHeader.getVersion() > VERSION){System.err.println("Sf-->Warning, Shapefile format ("+mainHeader.getVersion()+") newer that supported ("+VERSION+"), attempting to read anyway");}
Geometry body;
ArrayList list = new ArrayList();
ArrayList<Geometry> list = new ArrayList<Geometry>();
int type=mainHeader.getShapeType();
ShapeHandler handler = getShapeHandler(type);
if(handler==null)throw new ShapeTypeNotSupportedException("Unsuported shape type:"+type);
......@@ -123,13 +123,15 @@ public class Shapefile
list.add(body);
// System.out.println("Done record: " + recordNumber);
}catch(IllegalArgumentException r2d2){
geomFactory = new GeometryFactory(null, -1);
//System.out.println("Record " +recordNumber+ " has is NULL Shape");
list.add(new GeometryCollection(null,null,-1));
list.add(geomFactory.createGeometryCollection(null));
}catch(Exception c3p0){
geomFactory = new GeometryFactory(null, -1);
System.out.println("Error processing record (a):" +recordNumber);
System.out.println(c3p0.getMessage());
c3p0.printStackTrace();
list.add(new GeometryCollection(null,null,-1));
list.add(geomFactory.createGeometryCollection(null));
}
// System.out.println("processing:" +recordNumber);
}
......@@ -184,12 +186,14 @@ public class Shapefile
// System.out.println("Done record: " + recordNumber);
}catch(IllegalArgumentException r2d2){
//System.out.println("Record " +recordNumber+ " has is NULL Shape");
geom = new GeometryCollection(null,null,-1);
geomFactory = new GeometryFactory(null, -1);
geom = geomFactory.createGeometryCollection(null);
}catch(Exception c3p0){
geomFactory = new GeometryFactory(null, -1);
System.out.println("Error processing record (a):" +recordNumber);
System.out.println(c3p0.getMessage());
c3p0.printStackTrace();
geom = new GeometryCollection(null,null,-1);
geom = geomFactory.createGeometryCollection(null);
}
// System.out.println("processing:" +recordNumber);
}
......
......@@ -11,6 +11,7 @@
*/
package org.locationtech.jtstest.testbuilder.model;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.WKTWriter;
......@@ -32,7 +33,7 @@ public class SVGTestWriter {
}
private SVGWriter writer = new SVGWriter();
private SVGWriter svgWriter = new SVGWriter();
public SVGTestWriter() {}
......@@ -45,36 +46,48 @@ public class SVGTestWriter {
Envelope env = new Envelope();
if (ga != null) env.expandToInclude(ga.getEnvelopeInternal());
if (gb != null) env.expandToInclude(gb.getEnvelopeInternal());
Coordinate centre = env.centre();
String viewBox = env.getMinX() + " " + env.getMinY() + " " + env.getMaxX() + " " + env.getMaxY();
int DIM = 1000;
String wh = "width='" + DIM + "' height='" + DIM + "'";
String viewBox = env.getMinX() + " " + env.getMinY() + " " + env.getWidth() + " " + env.getHeight();
// transform to flip the Y axis to match SVG
String trans = String.format("translate(0 %f) scale( 1 -1 ) translate(0 %f)", centre.y, -centre.y);
text.append("<?xml version='1.0' standalone='no'?>\n");
text.append("<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>\n");
text.append("<svg width='400' height='400' viewBox='" + viewBox + "' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>\n");
text.append("<svg " + wh + " viewBox='" + viewBox + "' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>\n");
String name = testable.getName() == null ? "" : testable.getName();
String description = testable.getDescription() == null ? "" : testable.getDescription();
//text.append(" \"" + name + "\",\n");
text.append(" <desc>" + description + "</desc>\n");
text.append(" <g transform='" + trans + "'>\n\n");
String a = writeGeometryStyled(ga, "#bbbbff", "#0000ff");
String b = writeGeometryStyled(gb, "#ffbbbb", "#ff0000");
text.append(a + "\n");
text.append("\n");
text.append(b + "\n");
writeGeometryElement(ga, "#bbbbff", "#0000ff", text);
writeGeometryElement(gb, "#ffbbbb", "#ff0000", text);
text.append(" </g>\n");
text.append("</svg>\n");
return text.toString();
}
private String writeGeometryStyled(Geometry g, String fillClr, String strokeClr ) {
String s = "<g fill='" + fillClr + "' stroke='" + strokeClr + "' >\n";
s += write(g);
s += "</g>";
return s;
private void writeGeometryElement(Geometry g, String fillClr, String strokeClr, StringBuffer text) {
if (g == null) return;
writeGeometryStyled(g, fillClr, strokeClr, text);
text.append("\n");
}
private void writeGeometryStyled(Geometry g, String fillClr, String strokeClr, StringBuffer text ) {
String gstyle = "<g style='fill:" + fillClr + "; fill-opacity:0.5; stroke:" + strokeClr + "; stroke-width:1; stroke-opacity:1; stroke-miterlimit:4; stroke-linejoin:miter; stroke-linecap:square' >\n";
text.append(gstyle);
text.append(write(g));
text.append("\n</g>\n");
}
private String write(Geometry geometry) {
if (geometry == null) {
return "";
}
return writer.write(geometry);
return svgWriter.write(geometry);
}
}
......@@ -345,9 +345,7 @@ public class SVGWriter
PrecisionModel precisionModel)
throws IOException
{
writer.write("(");
appendCoordinate(coordinate, writer);
writer.write(")");
writer.write("<circle cx='" + coordinate.x + "' cy='" + coordinate.y + "' r='1' />\n");
}
/**
......@@ -505,20 +503,16 @@ public class SVGWriter
throws IOException
{
if (multiPoint.isEmpty()) {
writer.write("EMPTY");
writer.write(" ");
}
else {
writer.write("(");
int level2 = level;
for (int i = 0; i < multiPoint.getNumGeometries(); i++) {
if (i > 0) {
writer.write(", ");
indentCoords(i, level + 1, writer);
level2 = level + 1;
}
writer.write("(");
appendCoordinate(((Point) multiPoint.getGeometryN(i)).getCoordinate(), writer);
writer.write(")");
appendPoint(multiPoint.getGeometryN(i).getCoordinate(), level2, writer, multiPoint.getPrecisionModel());
}
writer.write(")");
}
}
......
......@@ -3,7 +3,7 @@
<parent>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-modules</artifactId>
<version>1.15.0</version>
<version>1.15.1</version>
</parent>
<artifactId>jts-core</artifactId>
<name>${project.groupId}:${project.artifactId}</name>
......@@ -14,8 +14,11 @@
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<!--configuration>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>org.locationtech.jts</Automatic-Module-Name>
</manifestEntries>
<manifestSections>
<manifestSection>
<name>org.locationtech.jts</name>
......@@ -25,7 +28,7 @@
</manifestSection>
</manifestSections>
</archive>
</configuration-->
</configuration>
<executions>
<execution>
<phase>package</phase>
......
......@@ -12,6 +12,7 @@
package org.locationtech.jts.algorithm;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.CoordinateSequence;
/**
* Functions to compute the orientation of basic geometric structures
......@@ -56,7 +57,7 @@ public class Orientation {
/**
* Returns the orientation index of the direction of the point <code>q</code> relative to
* a directed infinite line specified by <code>p1-p2</code>.
* The index indicates whether the point lies to the {@link LEFT} or {@link #RIGHT}
* The index indicates whether the point lies to the {@link #LEFT} or {@link #RIGHT}
* of the line, or lies on it {@link #COLLINEAR}.
* The index also indicates the orientation of the triangle formed by the three points
* ( {@link #COUNTERCLOCKWISE}, {@link #CLOCKWISE}, or {@link #STRAIGHT} )
......@@ -66,12 +67,12 @@ public class Orientation {
* @param q the point to compute the direction to
*
* @return -1 ( {@link #CLOCKWISE} or {@link #RIGHT} ) if q is clockwise (right) from p1-p2;
* 1 ( {@link #COUNTERCLOCKWISE} or {@link LEFT} ) if q is counter-clockwise (left) from p1-p2;
* 1 ( {@link #COUNTERCLOCKWISE} or {@link #LEFT} ) if q is counter-clockwise (left) from p1-p2;
* 0 ( {@link #COLLINEAR} or {@link #STRAIGHT} ) if q is collinear with p1-p2
*/
public static int index(Coordinate p1, Coordinate p2, Coordinate q)
{
/**
/*
* MD - 9 Aug 2010 It seems that the basic algorithm is slightly orientation
* dependent, when computing the orientation of a point very close to a
* line. This is possibly due to the arithmetic in the translation to the
......@@ -94,6 +95,7 @@ public class Orientation {
*
*/
return CGAlgorithmsDD.orientationIndex(p1, p2, q);
// testing only
//return ShewchuksDeterminant.orientationIndex(p1, p2, q);
// previous implementation - not quite fully robust
......@@ -154,7 +156,7 @@ public class Orientation {
Coordinate prev = ring[iPrev];
Coordinate next = ring[iNext];
/**
/*
* This check catches cases where the ring contains an A-B-A configuration
* of points. This can happen if the ring does not contain 3 distinct points
* (including the case where the input array has fewer than 4 elements), or
......@@ -165,7 +167,94 @@ public class Orientation {
int disc = Orientation.index(prev, hiPt, next);
/*
* If disc is exactly 0, lines are collinear. There are two possible cases:
* (1) the lines lie along the x axis in opposite directions (2) the lines
* lie on top of one another
*
* (1) is handled by checking if next is left of prev ==> CCW (2) will never
* happen if the ring is valid, so don't check for it (Might want to assert
* this)
*/
boolean isCCW;
if (disc == 0) {
// poly is CCW if prev x is right of next x
isCCW = (prev.x > next.x);
}
else {
// if area is positive, points are ordered CCW
isCCW = (disc > 0);
}
return isCCW;
}
/**
* Computes whether a ring defined by an {@link CoordinateSequence} is
* oriented counter-clockwise.
* <ul>
* <li>The list of points is assumed to have the first and last points equal.
* <li>This will handle coordinate lists which contain repeated points.
* </ul>
* This algorithm is <b>only</b> guaranteed to work with valid rings. If the
* ring is invalid (e.g. self-crosses or touches), the computed result may not
* be correct.
*
* @param ring
* a CoordinateSequence forming a ring
* @return true if the ring is oriented counter-clockwise.
* @throws IllegalArgumentException
* if there are too few points to determine orientation (&lt; 4)
*/
public static boolean isCCW(CoordinateSequence ring)
{
// # of points without closing endpoint
int nPts = ring.size() - 1;
// sanity check
if (nPts < 3)
throw new IllegalArgumentException(
"Ring has fewer than 4 points, so orientation cannot be determined");
// find highest point
Coordinate hiPt = ring.getCoordinate(0);
int hiIndex = 0;
for (int i = 1; i <= nPts; i++) {
Coordinate p = ring.getCoordinate(i);
if (p.y > hiPt.y) {
hiPt = p;
hiIndex = i;
}
}
// find distinct point before highest point
Coordinate prev;
int iPrev = hiIndex;
do {
iPrev = iPrev - 1;
if (iPrev < 0)
iPrev = nPts;
prev = ring.getCoordinate(iPrev);
} while (prev.equals2D(hiPt) && iPrev != hiIndex);
// find distinct point after highest point
Coordinate next;
int iNext = hiIndex;
do {
iNext = (iNext + 1) % nPts;
next = ring.getCoordinate(iNext);
} while (next.equals2D(hiPt) && iNext != hiIndex);
/*
* This check catches cases where the ring contains an A-B-A configuration
* of points. This can happen if the ring does not contain 3 distinct points
* (including the case where the input array has fewer than 4 elements), or
* it contains coincident line segments.
*/
if (prev.equals2D(hiPt) || next.equals2D(hiPt) || prev.equals2D(next))
return false;
int disc = Orientation.index(prev, hiPt, next);
/*
* If disc is exactly 0, lines are collinear. There are two possible cases:
* (1) the lines lie along the x axis in opposite directions (2) the lines
* lie on top of one another
......
......@@ -138,6 +138,6 @@ public class PolygonShape implements Shape
}
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return getPathIterator(at, flatness);
return polygonPath.getPathIterator(at, flatness);
}
}
......@@ -220,4 +220,136 @@ public class CoordinateSequences {
builder.append(')');
return builder.toString();
}
/**
* Returns the minimum coordinate, using the usual lexicographic comparison.
*
*@param seq the coordinate sequence to search
*@return the minimum coordinate in the sequence, found using <code>compareTo</code>
*@see Coordinate#compareTo(Object)
*/
public static Coordinate minCoordinate(CoordinateSequence seq)
{
Coordinate minCoord = null;
for (int i = 0; i < seq.size(); i++) {
Coordinate testCoord = seq.getCoordinate(i);
if (minCoord == null || minCoord.compareTo(testCoord) > 0) {
minCoord = testCoord;
}
}
return minCoord;
}
/**
* Returns the index of the minimum coordinate of the whole
* coordinate sequence, using the usual lexicographic comparison.
*
*@param seq the coordinate sequence to search
*@return the index of the minimum coordinate in the sequence, found using <code>compareTo</code>
*@see Coordinate#compareTo(Object)
*/
public static int minCoordinateIndex(CoordinateSequence seq) {
return minCoordinateIndex(seq, 0, seq.size() - 1);
}
/**
* Returns the index of the minimum coordinate of a part of
* the coordinate sequence (defined by {@code from} and {@code to},
* using the usual lexicographic comparison.
*
*@param seq the coordinate sequence to search
*@param from the lower search index
*@param to the upper search index
*@return the index of the minimum coordinate in the sequence, found using <code>compareTo</code>
*@see Coordinate#compareTo(Object)
*/
public static int minCoordinateIndex(CoordinateSequence seq, int from, int to)
{
int minCoordIndex = -1;
Coordinate minCoord = null;
for (int i = from; i <= to; i++) {
Coordinate testCoord = seq.getCoordinate(i);
if (minCoord == null || minCoord.compareTo(testCoord) > 0) {
minCoord = testCoord;
minCoordIndex = i;
}
}
return minCoordIndex;
}
/**
* Shifts the positions of the coordinates until <code>firstCoordinate</code>
* is first.
*
*@param seq the coordinate sequence to rearrange
*@param firstCoordinate the coordinate to make first
*/
public static void scroll(CoordinateSequence seq, Coordinate firstCoordinate) {
int i = indexOf(firstCoordinate, seq);
if (i <= 0) return;
scroll(seq, i);
}
/**
* Shifts the positions of the coordinates until the coordinate at <code>firstCoordinateIndex</code>
* is first.
*
*@param seq the coordinate sequence to rearrange
*@param indexOfFirstCoordinate the index of the coordinate to make first
*/
public static void scroll(CoordinateSequence seq, int indexOfFirstCoordinate)
{
scroll(seq, indexOfFirstCoordinate, CoordinateSequences.isRing(seq));
}
/**
* Shifts the positions of the coordinates until the coordinate at <code>firstCoordinateIndex</code>
* is first.
*
*@param seq the coordinate sequence to rearrange
*@param indexOfFirstCoordinate
* the index of the coordinate to make first
*@param ensureRing
* makes sure that {@code} will be a closed ring upon exit
*/
public static void scroll(CoordinateSequence seq, int indexOfFirstCoordinate, boolean ensureRing) {
int i = indexOfFirstCoordinate;
if (i <= 0) return;
// make a copy of the sequence
CoordinateSequence copy = seq.copy();
// test if ring, determine last index
int last = ensureRing ? seq.size() - 1: seq.size();
// fill in values
for (int j = 0; j < last; j++)
{
for (int k = 0; k < seq.getDimension(); k++)
seq.setOrdinate(j, k, copy.getOrdinate((indexOfFirstCoordinate+j)%last, k));
}
// Fix the ring (first == last)
if (ensureRing) {
for (int k = 0; k < seq.getDimension(); k++)
seq.setOrdinate(last, k, seq.getOrdinate(0, k));
}
}
/**
* Returns the index of <code>coordinate</code> in a {@link CoordinateSequence}
* The first position is 0; the second, 1; etc.
*
*@param coordinate the <code>Coordinate</code> to search for
*@param seq the coordinate sequence to search
*@return the position of <code>coordinate</code>, or -1 if it is
* not found
*/
public static int indexOf(Coordinate coordinate, CoordinateSequence seq) {
for (int i = 0; i < seq.size(); i++) {
if (coordinate.x == seq.getOrdinate(i, CoordinateSequence.X) &&
coordinate.y == seq.getOrdinate(i, CoordinateSequence.Y)) {
return i;
}
}
return -1;
}}
\ No newline at end of file