/*
* 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.revolsys.geometry.model;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.geometry.cs.projection.CoordinatesOperation;
import com.revolsys.geometry.model.editor.PointEditor;
import com.revolsys.geometry.model.impl.BaseBoundingBox;
import com.revolsys.geometry.model.impl.PointDoubleXY;
import com.revolsys.geometry.model.segment.Segment;
import com.revolsys.geometry.model.vertex.PointVertex;
import com.revolsys.geometry.model.vertex.Vertex;
import com.revolsys.geometry.util.NumberUtil;
import com.revolsys.math.Angle;
import com.revolsys.util.MathUtil;
import com.revolsys.util.Property;
import com.revolsys.util.number.Doubles;
/**
* Represents a single point.
*
* A <code>Point</code> is topologically valid if and only if:
* <ul>
* <li>the coordinate which defines it (if any) is a valid coordinate
* (i.e does not have an <code>NaN</code> X or Y ordinate)
* </ul>
*
*@version 1.7
*/
public interface Point extends Punctual, Serializable {
@SuppressWarnings("unchecked")
static <G extends Geometry> G newPoint(final Object value) {
if (value == null) {
return null;
} else if (value instanceof Point) {
return (G)value;
} else if (value instanceof Geometry) {
throw new IllegalArgumentException(
((Geometry)value).getGeometryType() + " cannot be converted to a Point");
} else {
final String string = DataTypes.toString(value);
return (G)GeometryFactory.DEFAULT_3D.geometry(string, false);
}
}
default Point add(final Point point) {
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x2 = convertedPoint.getX();
final double y2 = convertedPoint.getY();
final double x1 = getX();
final double y1 = getY();
return newPoint(x1 + x2, y1 + y2);
}
/**
* Returns the angle that the vector from (0,0) to p,
* relative to the positive X-axis.
* The angle is normalized to be in the range ( -Pi, Pi ].
*
* @return the normalized angle (in radians) that p makes with the positive x-axis.
*/
default double angle() {
final double x = getX();
final double y = getY();
return Angle.angle(x, y);
}
/**
* Calculate the counter clockwise angle in radians of the vector from this
* point to another point. The angle is relative to the positive x-axis
* relative to the positive X-axis. The angle will be in the range -PI -> PI
* where negative values have a clockwise orientation.
*
* @return The angle in radians.
*/
default double angle2d(final Point other) {
final double x1 = this.getX();
final double y1 = this.getY();
final double x2 = other.getX();
final double y2 = other.getY();
return Angle.angle2d(x1, y1, x2, y2);
}
@Override
@SuppressWarnings("unchecked")
default <V extends Geometry> V appendVertex(final Point newPoint, final int... geometryId) {
final GeometryFactory geometryFactory = getGeometryFactory();
if (newPoint == null || newPoint.isEmpty()) {
return (V)this;
} else if (isEmpty()) {
return newPoint.convertGeometry(geometryFactory);
} else if (newPoint.isEmpty()) {
return (V)this;
} else {
return (V)geometryFactory.lineString(this, newPoint);
}
}
@Override
Point clone();
@Override
default int compareTo(final Object other) {
if (other instanceof Point) {
final Point point = (Point)other;
return compareTo(point);
} else if (other instanceof Geometry) {
final Geometry geometry = (Geometry)other;
return compareTo(geometry);
} else {
return -1;
}
}
/**
* Compares this {@link Coordinates} with the specified {@link Coordinates} for order.
* This method ignores the z value when making the comparison.
* Returns:
* <UL>
* <LI> -1 : this.x < other.x || ((this.x == other.x) && (this.y <
* other.y))
* <LI> 0 : this.x == other.x && this.y = other.y
* <LI> 1 : this.x > other.x || ((this.x == other.x) && (this.y > other.y))
*
* </UL>
* Note: This method assumes that ordinate values
* are valid numbers. NaN values are not handled correctly.
*
*@param o the <code>Coordinate</code> with which this <code>Coordinate</code>
* is being compared
*@return -1, zero, or 1 as this <code>Coordinate</code>
* is less than, equal to, or greater than the specified <code>Coordinate</code>
*/
default int compareTo(final Point point) {
final boolean otherEmpty = point.isEmpty();
if (isEmpty()) {
if (otherEmpty) {
return 0;
} else {
return -1;
}
} else if (otherEmpty) {
return 1;
} else {
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x1 = this.getX();
final double x2 = convertedPoint.getX();
if (x1 < x2) {
return -1;
} else if (x1 > x2) {
return 1;
} else {
final double y1 = this.getY();
final double y2 = convertedPoint.getY();
if (y1 < y2) {
return -1;
} else if (y1 > y2) {
return 1;
} else {
return 0;
}
}
}
}
@Override
default int compareToSameClass(final Geometry other) {
final Point point = (Point)other;
return getPoint().compareTo(point.getPoint());
}
@Override
default boolean contains(final double x, final double y) {
return equalsVertex(x, y);
}
default double[] convertCoordinates(GeometryFactory geometryFactory) {
final GeometryFactory sourceGeometryFactory = getGeometryFactory();
final double[] coordinates = getCoordinates();
if (isEmpty()) {
return coordinates;
} else {
geometryFactory = getNonZeroGeometryFactory(geometryFactory);
double[] targetCoordinates;
final CoordinatesOperation coordinatesOperation = sourceGeometryFactory
.getCoordinatesOperation(geometryFactory);
if (coordinatesOperation == null) {
return coordinates;
} else {
final int sourceAxisCount = getAxisCount();
targetCoordinates = new double[sourceAxisCount * getVertexCount()];
coordinatesOperation.perform(sourceAxisCount, coordinates, sourceAxisCount,
targetCoordinates);
return targetCoordinates;
}
}
}
default Point convertPoint2d(final GeometryFactory geometryFactory) {
if (isEmpty()) {
return this;
} else {
final CoordinatesOperation coordinatesOperation = getGeometryFactory()
.getCoordinatesOperation(geometryFactory);
if (coordinatesOperation == null) {
return this;
} else {
final double sourceX = getX();
final double sourceY = getY();
final double[] targetCoordinates = new double[] {
sourceX, sourceY
};
coordinatesOperation.perform(2, targetCoordinates, 2, targetCoordinates);
final double targetX = targetCoordinates[X];
final double targetY = targetCoordinates[Y];
return new PointDoubleXY(targetX, targetY);
}
}
}
default void copyCoordinates(final double[] coordinates) {
for (int i = 0; i < coordinates.length; i++) {
final double value = getCoordinate(i);
coordinates[i] = value;
}
}
/**
* Copy the coordinates in this point to the coordinates array parameter and convert them to the geometry factory.
*
* @param geometryFactory
* @param coordinates
*/
@Deprecated
default void copyCoordinates(GeometryFactory geometryFactory, final double[] coordinates) {
final GeometryFactory sourceGeometryFactory = getGeometryFactory();
if (geometryFactory == null) {
} else if (isEmpty()) {
Arrays.fill(coordinates, Double.NaN);
} else {
copyCoordinates(coordinates);
if (geometryFactory != null) {
geometryFactory = getNonZeroGeometryFactory(geometryFactory);
final CoordinatesOperation coordinatesOperation = sourceGeometryFactory
.getCoordinatesOperation(geometryFactory);
if (coordinatesOperation != null) {
final int sourceAxisCount = getAxisCount();
final int targetAxisCount = geometryFactory.getAxisCount();
coordinatesOperation.perform(sourceAxisCount, coordinates, targetAxisCount, coordinates);
}
}
}
}
default int copyCoordinates(final int axisCount, final double nanValue,
final double[] destCoordinates, int destOffset) {
if (isEmpty()) {
return destOffset;
} else {
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
double coordinate = getCoordinate(axisIndex);
if (Double.isNaN(coordinate)) {
coordinate = nanValue;
}
destCoordinates[destOffset++] = coordinate;
}
return destOffset;
}
}
default double cross(final Point point) {
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x2 = convertedPoint.getX();
final double y2 = convertedPoint.getY();
return getX() * y2 - getY() * x2;
}
@Override
@SuppressWarnings("unchecked")
default <V extends Geometry> V deleteVertex(final int... vertexId) {
final GeometryFactory geometryFactory = getGeometryFactory();
return (V)geometryFactory.point();
}
@Override
default double distance(final double x, final double y) {
final double x1 = this.getX();
final double y1 = this.getY();
return MathUtil.distance(x1, y1, x, y);
}
@Override
default double distance(final double x, final double y, final double terminateDistance) {
final double x1 = this.getX();
final double y1 = this.getY();
return MathUtil.distance(x1, y1, x, y);
}
@Override
default double distance(final Geometry geometry, final double terminateDistance) {
if (geometry instanceof Point) {
final Point point = (Point)geometry;
return distancePoint(point);
} else if (isEmpty()) {
return Double.POSITIVE_INFINITY;
} else if (Property.isEmpty(geometry)) {
return Double.POSITIVE_INFINITY;
} else {
return geometry.distance(this, terminateDistance);
}
}
/**
* Computes the 3-dimensional Euclidean distance to another location.
*
* @param c a coordinate
* @return the 3-dimensional Euclidean distance between the locations
*/
default double distance3d(final Point point) {
final double x = getX();
final double y = getY();
final double z = getZ();
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x2 = convertedPoint.getX();
final double y2 = convertedPoint.getY();
final double z2 = point.getZ();
final double dx = x - x2;
final double dy = y - y2;
final double dz = z - z2;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
default double distanceOrigin() {
final double distanceOriginSquared = distanceOriginSquared();
return Math.sqrt(distanceOriginSquared);
}
default double distanceOriginSquared() {
return dot(this);
}
@Override
default double distancePoint(Point point) {
if (isEmpty()) {
return Double.POSITIVE_INFINITY;
} else if (Property.isEmpty(point)) {
return Double.POSITIVE_INFINITY;
} else {
final GeometryFactory geometryFactory = getGeometryFactory();
point = point.convertPoint2d(geometryFactory);
final double x = point.getX();
final double y = point.getY();
final double x1 = this.getX();
final double y1 = this.getY();
return MathUtil.distance(x1, y1, x, y);
}
}
default double distanceSquared(final double x, final double y) {
final double x1 = this.getX();
final double y1 = this.getY();
final double dx = x - x1;
final double dy = y - y1;
final double distanceSquared = dx * dx + dy * dy;
return distanceSquared;
}
default double dot(final Point point) {
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x2 = convertedPoint.getX();
final double y2 = convertedPoint.getY();
final double x1 = getX();
final double y1 = getY();
return x1 * x2 + y1 * y2;
}
@Override
default boolean equals(final int axisCount, final Geometry geometry) {
if (geometry instanceof Point) {
final Point point = (Point)geometry;
return equals(axisCount, point);
} else {
return false;
}
}
default boolean equals(final int axisCount, final Point point) {
if (point == this) {
return true;
} else if (point == null) {
return false;
} else if (axisCount < 2) {
throw new IllegalArgumentException("Axis Count must be >=2");
} else {
if (isEmpty()) {
return point.isEmpty();
} else if (point.isEmpty()) {
return false;
} else if (equals(point)) {
for (int axisIndex = 2; axisIndex < axisCount; axisIndex++) {
final double value = getCoordinate(axisIndex);
final double value2 = point.getCoordinate(axisIndex);
if (!Doubles.equal(value, value2)) {
return false;
}
}
return true;
} else {
return false;
}
}
}
default boolean equals(final Point point) {
if (point == null) {
return false;
} else if (isEmpty()) {
return point.isEmpty();
} else if (point.isEmpty()) {
return false;
} else {
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x2 = convertedPoint.getX();
final double y2 = convertedPoint.getY();
return equalsVertex(x2, y2);
}
}
@Override
default boolean equalsExact(final Geometry other, final double tolerance) {
if (other instanceof Point) {
final Point point = (Point)other;
if (isEmpty() && other.isEmpty()) {
return true;
} else if (isEmpty() != other.isEmpty()) {
return false;
} else {
return equal(point, getPoint(), tolerance);
}
} else {
return false;
}
}
default boolean equalsVertex(final double... coordinates) {
for (int i = 0; i < coordinates.length; i++) {
final double coordinate2 = coordinates[i];
final double coordinate = getCoordinate(i);
if (!Doubles.equal(coordinate, coordinate2)) {
return false;
}
}
return true;
}
default boolean equalsVertex(final double x, final double y) {
if (Double.compare(x, getX()) == 0) {
if (Double.compare(y, getY()) == 0) {
return true;
}
}
return false;
}
/**
* Tests if another coordinate has the same values for the X and Y ordinates.
* The Z ordinate is ignored.
*
*@param other a <code>Coordinate</code> with which to do the 2D comparison.
*@return true if <code>other</code> is a <code>Coordinate</code>
* with the same values for X and Y.
*/
default boolean equalsVertex2d(final Point point, final double tolerance) {
if (point == null) {
return false;
} else if (isEmpty()) {
return point.isEmpty();
} else if (point.isEmpty()) {
return false;
} else {
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x2 = convertedPoint.getX();
final double y2 = convertedPoint.getY();
final double x = getX();
final double y = getY();
if (NumberUtil.equalsWithTolerance(x, x2, tolerance)) {
if (NumberUtil.equalsWithTolerance(y, y2, tolerance)) {
return true;
}
}
return false;
}
}
/**
* Gets the boundary of this geometry.
* Zero-dimensional geometries have no boundary by definition,
* so an empty GeometryCollection is returned.
*
* @return an empty GeometryCollection
* @see Geometry#getBoundary
*/
@Override
default Geometry getBoundary() {
return getGeometryFactory().geometryCollection();
}
@Override
default int getBoundaryDimension() {
return Dimension.FALSE;
}
@Override
default Point getCentroid() {
return newGeometry(2);
}
/**
* Gets the ordinate value for the given index.
* The supported values for the index are
* {@link #X}, {@link #Y}, and {@link #Z}.
*
* @param axisIndex the ordinate index
* @return the value of the ordinate
* @throws IllegalArgumentException if the index is not valid
*/
double getCoordinate(int axisIndex);
@Override
default double getCoordinate(final int partIndex, final int axisIndex) {
if (partIndex == 0) {
return getCoordinate(axisIndex);
} else {
return Double.NaN;
}
}
default double[] getCoordinates() {
final int axisCount = getAxisCount();
return getCoordinates(axisCount);
}
default double[] getCoordinates(final int axisCount) {
final double[] coordinates = new double[axisCount];
for (int i = 0; i < axisCount; i++) {
coordinates[i] = getCoordinate(i);
}
return coordinates;
}
@Override
default DataType getDataType() {
return DataTypes.POINT;
}
@Override
default int getDimension() {
return 0;
}
@Override
default Point getInteriorPoint() {
return this;
}
default double getM() {
return getCoordinate(3);
}
@Override
default Point getPoint() {
if (isEmpty()) {
return null;
} else {
return this;
}
}
@Override
default Point getPoint(final int i) {
if (i == 0) {
return this;
} else {
return null;
}
}
@Override
default Point getPointWithin() {
return newPoint2D();
}
@Override
default Segment getSegment(final int... segmentId) {
return null;
}
default long getTime() {
return (long)getM();
}
@Override
default Vertex getToVertex(final int... vertexId) {
return getVertex(vertexId);
}
@Override
default Vertex getVertex(final int... vertexId) {
if (isEmpty()) {
return null;
} else {
return new PointVertex(this);
}
}
@Override
default int getVertexCount() {
return isEmpty() ? 0 : 1;
}
default double getX() {
if (isEmpty()) {
return Double.NaN;
} else {
return getCoordinate(0);
}
}
default double getY() {
if (isEmpty()) {
return Double.NaN;
} else {
return getCoordinate(1);
}
}
default double getZ() {
return getCoordinate(2);
}
@Override
default boolean hasInvalidXyCoordinates() {
final double x = getX();
if (!Double.isFinite(x)) {
return true;
}
final double y = getY();
if (!Double.isFinite(y)) {
return true;
}
return false;
}
@Override
@SuppressWarnings("unchecked")
default <V extends Geometry> V insertVertex(final Point newPoint, final int... vertexId) {
if (vertexId.length == 1) {
final int vertexIndex = vertexId[0];
final GeometryFactory geometryFactory = getGeometryFactory();
if (newPoint == null || newPoint.isEmpty()) {
return (V)this;
} else if (isEmpty()) {
return newPoint.convertGeometry(geometryFactory);
} else if (newPoint.isEmpty()) {
return (V)this;
} else if (vertexIndex == 0) {
return (V)geometryFactory.lineString(newPoint, this);
} else {
return (V)geometryFactory.lineString(this, newPoint);
}
} else {
throw new IllegalArgumentException("Vertex id's for " + getGeometryType()
+ " must have length 1. " + Arrays.toString(vertexId));
}
}
@Override
default boolean intersects(final BoundingBox boundingBox) {
if (isEmpty() || boundingBox.isEmpty()) {
return false;
} else {
final GeometryFactory geometryFactory = boundingBox.getGeometryFactory();
final Point convertedPoint = convertPoint2d(geometryFactory);
final double x = convertedPoint.getX();
final double y = convertedPoint.getY();
return boundingBox.intersects(x, y);
}
}
@Override
default boolean intersects(final Geometry geometry) {
if (geometry instanceof Point) {
final Point point = (Point)geometry;
return intersects(point);
} else {
final BoundingBox boundingBox = geometry.getBoundingBox();
if (intersects(boundingBox)) {
return geometry.locate(this) != Location.EXTERIOR;
} else {
return false;
}
}
}
@Override
default boolean intersects(final Point point) {
if (isEmpty()) {
return false;
} else {
return equals(point);
}
}
/**
* Tests if a point is contained in the boundary of the target rectangle.
*
* contains = false iff the point is properly contained in the rectangle.
*
* This code assumes that the point lies in the rectangle envelope
* @param point the point to test
* @return true if the point is contained in the boundary
*/
@Override
default boolean isContainedInBoundary(final BoundingBox boundingBox) {
final double x = getX();
final double y = getY();
final double minX = boundingBox.getMinX();
final double minY = boundingBox.getMinY();
final double maxX = boundingBox.getMaxX();
final double maxY = boundingBox.getMaxY();
return x == minX || x == maxX || y == minY || y == maxY;
}
@Override
default boolean isEquivalentClass(final Geometry other) {
return other instanceof Point;
}
@Override
default boolean isSimple() {
return true;
}
@Override
default boolean isValid() {
if (isEmpty()) {
return true;
} else {
final double x = getX();
final double y = getY();
if (Double.isFinite(x) && Double.isFinite(y)) {
return true;
} else {
return false;
}
}
}
@Override
default Location locate(final Point point) {
if (equals(2, point)) {
return Location.INTERIOR;
} else {
return Location.EXTERIOR;
}
}
@Override
default Point move(final double... deltas) {
final GeometryFactory geometryFactory = getGeometryFactory();
if (deltas == null || isEmpty()) {
return this;
} else {
final double[] coordinates = getCoordinates();
final int axisCount = Math.min(deltas.length, getAxisCount());
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
coordinates[axisIndex] += deltas[axisIndex];
}
return geometryFactory.point(coordinates);
}
}
@Override
@SuppressWarnings("unchecked")
default <V extends Geometry> V moveVertex(final Point newPoint, final int... vertexId) {
if (newPoint == null || newPoint.isEmpty()) {
return (V)this;
} else {
final GeometryFactory geometryFactory = getGeometryFactory();
return (V)newPoint.newGeometry(geometryFactory);
}
}
default Point multiply(final double s) {
final double x = getX();
final double y = getY();
return newPoint(x * s, y * s);
}
@Override
default BoundingBox newBoundingBox() {
final GeometryFactory geometryFactory = getGeometryFactory();
if (isEmpty()) {
return geometryFactory.newBoundingBoxEmpty();
} else {
return new BaseBoundingBox() {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public int getAxisCount() {
return Point.this.getAxisCount();
}
@Override
public GeometryFactory getGeometryFactory() {
return Point.this.getGeometryFactory();
}
@Override
public double getMax(final int axisIndes) {
return Point.this.getCoordinate(axisIndes);
}
@Override
public double getMaxX() {
return Point.this.getX();
}
@Override
public double getMaxY() {
return Point.this.getY();
}
@Override
public double getMin(final int axisIndes) {
return Point.this.getCoordinate(axisIndes);
}
@Override
public double getMinX() {
return Point.this.getX();
}
@Override
public double getMinY() {
return Point.this.getY();
}
};
}
}
@Override
default Point newGeometry(GeometryFactory geometryFactory) {
final GeometryFactory sourceGeometryFactory = getGeometryFactory();
if (geometryFactory == null) {
return this.clone();
} else if (isEmpty()) {
return geometryFactory.point();
} else {
geometryFactory = getNonZeroGeometryFactory(geometryFactory);
double[] targetCoordinates;
final CoordinatesOperation coordinatesOperation = sourceGeometryFactory
.getCoordinatesOperation(geometryFactory);
final double[] coordinates = getCoordinates();
if (coordinatesOperation == null) {
targetCoordinates = coordinates;
} else {
final int sourceAxisCount = getAxisCount();
final int targetAxisCount = geometryFactory.getAxisCount();
targetCoordinates = new double[targetAxisCount];
coordinatesOperation.perform(sourceAxisCount, coordinates, targetAxisCount,
targetCoordinates);
}
return geometryFactory.point(targetCoordinates);
}
}
@Override
default PointEditor newGeometryEditor() {
return new PointEditor(this);
}
@Override
default PointEditor newGeometryEditor(final int axisCount) {
final PointEditor geometryEditor = newGeometryEditor();
geometryEditor.setAxisCount(axisCount);
return geometryEditor;
}
default Point newPoint() {
GeometryFactory geometryFactory = getGeometryFactory();
if (geometryFactory == null) {
geometryFactory = GeometryFactory.DEFAULT_3D;
}
return geometryFactory.point(this);
}
default Point newPoint(final double x, final double y) {
return new PointDoubleXY(x, y);
}
default Point newPoint(final GeometryFactory geometryFactory, final double... coordinates) {
return geometryFactory.point(coordinates);
}
default Point newPoint2D() {
final double x = getX();
final double y = getY();
return newPoint(x, y);
}
@SuppressWarnings("unchecked")
@Override
default <G> G newUsingGeometryFactory(final GeometryFactory factory) {
if (factory == getGeometryFactory()) {
return (G)this;
} else if (isEmpty()) {
return (G)factory.point();
} else {
final double[] coordinates = getCoordinates();
return (G)factory.point(coordinates);
}
}
@Override
default Point normalize() {
return this;
}
/*
* Does this vector lie on the left or right of ab? -1 = left 0 = on 1 = right
*/
default int orientation(final Point point1, final Point point2) {
final double x = getX();
final double y = getY();
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint1 = point1.convertPoint2d(geometryFactory);
final double x1 = convertedPoint1.getX();
final double y1 = convertedPoint1.getY();
final Point convertedPoint2 = point2.convertPoint2d(geometryFactory);
final double x2 = convertedPoint2.getX();
final double y2 = convertedPoint2.getY();
final double det = (x1 - x) * (y2 - y) - (x2 - x) * (y1 - y);
return Double.compare(det, 0.0);
}
@Override
default List<Vertex> pointVertices() {
if (isEmpty()) {
return Collections.emptyList();
} else {
return Collections.singletonList(new PointVertex(this, 0));
}
}
@Override
default Point prepare() {
return this;
}
@Override
default Point removeDuplicatePoints() {
return this;
}
@Override
default Point reverse() {
return this;
}
default Point subtract(final Point point) {
final GeometryFactory geometryFactory = getGeometryFactory();
final Point convertedPoint = point.convertPoint2d(geometryFactory);
final double x2 = convertedPoint.getX();
final double y2 = convertedPoint.getY();
final double x1 = getX();
final double y1 = getY();
return newPoint(x1 - x2, y1 - y2);
}
@Override
default Point union() {
return this;
}
@Override
default PointVertex vertices() {
return new PointVertex(this, -1);
}
}