package com.revolsys.geometry.model.coordinates;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.model.coordinates.list.CoordinatesListUtil;
import com.revolsys.geometry.model.impl.PointDouble;
import com.revolsys.geometry.model.impl.PointDoubleXY;
import com.revolsys.util.MathUtil;
import com.revolsys.util.Trig;
import com.revolsys.util.number.Doubles;
public interface CoordinatesUtil {
static Point average(final Point c1, final Point c2) {
final int axisCount = Math.min(c1.getAxisCount(), c2.getAxisCount());
final double[] coordinates = new double[axisCount];
for (int i = 0; i < axisCount; i++) {
final double value1 = c1.getCoordinate(i);
final double value2 = c2.getCoordinate(i);
double value;
if (Double.isNaN(value1) || Double.isNaN(value1)) {
value = value2;
} else if (Double.isNaN(value2) || Double.isNaN(value2)) {
value = value1;
} else {
value = MathUtil.avg(value1, value2);
}
coordinates[i] = value;
}
return new PointDouble(coordinates);
}
static int compare(final double x1, final double y1, final double x2, final double y2) {
if (x1 < x2) {
return -1;
} else if (x1 > x2) {
return 1;
} else {
if (y1 < y2) {
return -1;
} else if (y1 > y2) {
return 1;
} else {
return 0;
}
}
}
static int compareArcDistance(final double x1, final double y1, final double x2,
final double y2) {
// min is the minimum of all coordinates. This is used to normalize the x,y
// values to calculate the distance
double min = x1;
if (x2 < min) {
min = x2;
}
if (y1 < min) {
min = y1;
}
if (x2 < min) {
min = x2;
}
final double distance1 = MathUtil.distance(min, min, x1, y1);
final double distance2 = MathUtil.distance(min, min, x2, y2);
final int distanceCompare = Double.compare(distance1, distance2);
if (distanceCompare == 0) {
final int xCompare = Double.compare(x1, x2);
return xCompare;
} else {
return distanceCompare;
}
}
static int compareArcDistance(final Point point1, final Point point2) {
final double x1 = point1.getX();
final double y1 = point1.getY();
final double x2 = point2.getX();
final double y2 = point2.getY();
return compareArcDistance(x1, y1, x2, y2);
}
static int compareToOrigin(final Point point1, final Object other) {
if (other instanceof Point) {
final Point point2 = (Point)other;
return compareToOrigin(point1, point2);
} else {
return -1;
}
}
static int compareToOrigin(final Point point1, final Point point2) {
final double x1 = point1.getX();
final double y1 = point1.getY();
final double x2 = point2.getX();
final double y2 = point2.getY();
final double distance1 = MathUtil.distance(0, 0, x1, y1);
final double distance2 = MathUtil.distance(0, 0, x2, y2);
final int distanceCompare = Double.compare(distance1, distance2);
if (distanceCompare == 0) {
final int yCompare = Double.compare(y1, y2);
return yCompare;
} else {
return distanceCompare;
}
}
static boolean contains(final Iterable<? extends Point> points, final Point point) {
for (final Point point1 : points) {
if (point1.equals(point)) {
return true;
}
}
return false;
}
/**
* Computes the 3-dimensional Euclidean distance to another location.
*
* @param c a coordinate
* @return the 3-dimensional Euclidean distance between the locations
*/
static double distance3d(final Point point1, final Point point2) {
final double dx = point1.getX() - point2.getX();
final double dy = point1.getY() - point2.getY();
final double dz = point1.getZ() - point2.getZ();
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
static boolean equals(final double x1, final double y1, final double x2, final double y2) {
return x1 == x2 && y1 == y2;
}
static int getAxisCount(final Point... points) {
int axisCount = 2;
for (final Point point : points) {
axisCount = Math.max(axisCount, point.getAxisCount());
}
return axisCount;
}
static double getElevation(final double x1, final double y1, final double z1, final double x2,
final double y2, final double z2, final double x, final double y) {
final double fraction = MathUtil.distance(x, y, x1, y1) / MathUtil.distance(x1, y1, x2, y2);
final double z = z1 + (z2 - z1) * fraction;
return z;
}
static double getElevation(final LineString line, final Point coordinate) {
final LineString coordinates = line;
Point previousCoordinate = coordinates.getPoint(0);
for (int i = 1; i < coordinates.getVertexCount(); i++) {
final Point currentCoordinate = coordinates.getPoint(i);
if (LineSegmentUtil.distanceLinePoint(previousCoordinate, currentCoordinate,
coordinate) < 1) {
return LineSegmentUtil.getElevation(previousCoordinate, currentCoordinate, coordinate);
}
previousCoordinate = currentCoordinate;
}
return Double.NaN;
}
static double getElevation(final Point point, final Point point1, final Point point2) {
final double x1 = point1.getX();
final double y1 = point1.getY();
final double z1 = point1.getZ();
final double x2 = point2.getX();
final double y2 = point2.getY();
final double z2 = point2.getZ();
final double x = point.getX();
final double y = point.getY();
return getElevation(x1, y1, z1, x2, y2, z2, x, y);
}
static Point getPrecise(final double scale, final Point point) {
if (scale <= 0) {
return point;
} else {
final double[] coordinates = point.getCoordinates();
coordinates[0] = Doubles.makePrecise(scale, coordinates[0]);
coordinates[1] = Doubles.makePrecise(scale, coordinates[1]);
return new PointDouble(coordinates);
}
}
static boolean isAcute(final Point point1, final Point point2, final Point point3) {
final double x1 = point1.getX();
final double y1 = point1.getY();
final double x2 = point2.getX();
final double y2 = point2.getY();
final double x3 = point3.getX();
final double y3 = point3.getY();
return MathUtil.isAcute(x1, y1, x2, y2, x3, y3);
}
/**
* Methods for computing and working with octants of the Cartesian plane
* Octants are numbered as follows:
*
* <pre>
* \2|1/
* 3 \|/ 0
* ---+--
* 4 /|\ 7
* /5|6\
*
* <pre>
* If line segments lie along a coordinate axis, the octant is the lower of the two
* possible values.
*
* Returns the octant of a directed line segment (specified as x and y
* displacements, which cannot both be 0).
*/
static int octant(final double dx, final double dy) {
if (dx == 0.0 && dy == 0.0) {
throw new IllegalArgumentException(
"Cannot compute the octant for point ( " + dx + ", " + dy + " )");
}
final double adx = Math.abs(dx);
final double ady = Math.abs(dy);
if (dx >= 0) {
if (dy >= 0) {
if (adx >= ady) {
return 0;
} else {
return 1;
}
} else { // dy < 0
if (adx >= ady) {
return 7;
} else {
return 6;
}
}
} else { // dx < 0
if (dy >= 0) {
if (adx >= ady) {
return 3;
} else {
return 2;
}
} else { // dy < 0
if (adx >= ady) {
return 4;
} else {
return 5;
}
}
}
}
/**
* Returns the octant of a directed line segment from p0 to p1.
*/
static int octant(final Point p0, final Point p1) {
final double dx = p1.getX() - p0.getX();
final double dy = p1.getY() - p0.getY();
if (dx == 0.0 && dy == 0.0) {
throw new IllegalArgumentException(
"Cannot compute the octant for two identical points " + p0);
}
return octant(dx, dy);
}
static Point offset(final Point coordinate, final double angle, final double distance) {
final double newX = coordinate.getX() + distance * Math.cos(angle);
final double newY = coordinate.getY() + distance * Math.sin(angle);
final Point newCoordinate = new PointDoubleXY(newX, newY);
return newCoordinate;
}
static int orientationIndex(final Point p1, final Point p2, final Point q) {
// travelling along p1->p2, turn counter clockwise to get to q return 1,
// travelling along p1->p2, turn clockwise to get to q return -1,
// p1, p2 and q are colinear return 0.
final double x1 = p1.getX();
final double y1 = p1.getY();
final double x2 = p2.getX();
final double y2 = p2.getY();
final double x = q.getX();
final double y = q.getY();
return CoordinatesListUtil.orientationIndex(x1, y1, x2, y2, x, y);
}
/**
* Return the first point of points1 not in points2
* @param points1
* @param points2
* @return
*/
static Point pointNotInList(final LineString line1, final LineString line2) {
final int vertexCount = line1.getVertexCount();
for (int vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) {
final double x = line1.getX(vertexIndex);
final double y = line1.getY(vertexIndex);
if (!line2.hasVertex(x, y)) {
return new PointDoubleXY(x, y);
}
}
return null;
}
static Point setElevation(final Point newLocation, final Point originalLocation) {
if (originalLocation.getAxisCount() > 2) {
final double z = originalLocation.getZ();
if (Double.isNaN(z)) {
return newLocation;
} else {
final double[] points = originalLocation.getCoordinates();
points[2] = z;
final Point newCoordinates = new PointDouble(points);
return newCoordinates;
}
} else {
return newLocation;
}
}
static Point translate(final Point point, final double angle, final double length) {
final double x = point.getX();
final double y = point.getY();
final double newX = Trig.adjacent(x, angle, length);
final double newY = Trig.opposite(y, angle, length);
final Point newPoint = new PointDoubleXY(newX, newY);
return newPoint;
}
}