/* * $Id$ * This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc * * Copyright (c) 2000-2012 Stephane GALLAND. * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports, * Universite de Technologie de Belfort-Montbeliard. * Copyright (c) 2013-2016 The original authors, and other authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.arakhne.afc.math.geometry.d2; import org.eclipse.xtext.xbase.lib.Inline; import org.eclipse.xtext.xbase.lib.Pure; import org.arakhne.afc.math.MathUtil; import org.arakhne.afc.math.extensions.xtext.Tuple2DExtensions; import org.arakhne.afc.math.geometry.coordinatesystem.CoordinateSystem2D; import org.arakhne.afc.vmutil.annotations.ScalaOperator; import org.arakhne.afc.vmutil.annotations.XtextOperator; import org.arakhne.afc.vmutil.asserts.AssertMessages; /** 2D Point. * * @param <RP> is the type of point that can be returned by this tuple. * @param <RV> is the type of vector that can be returned by this tuple. * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ * @since 13.0 */ @SuppressWarnings("checkstyle:methodcount") public interface Point2D<RP extends Point2D<? super RP, ? super RV>, RV extends Vector2D<? super RV, ? super RP>> extends Tuple2D<RP> { /** * Replies if three points are colinear, ie. one the same line. * * <p>Trival approach is: points are collinear iff |AB| + |AC| = |BC|, where A B C are the three points. * * <p>This function uses the equal-to-zero test with the error {@link Math#ulp(double)}. * * @param x1 * is the X coordinate of the first point * @param y1 * is the Y coordinate of the first point * @param x2 * is the X coordinate of the second point * @param y2 * is the Y coordinate of the second point * @param x3 * is the X coordinate of the third point * @param y3 * is the Y coordinate of the third point * @return <code>true</code> if the three given points are colinear. * @since 3.0 * @see MathUtil#isEpsilonZero(double) */ @Pure @Inline(value = "MathUtil.isEpsilonZero(($1) * (($4) - ($6)) + ($3) * (($6) - ($2)) + ($5) * (($2) - ($4)))", imported = {MathUtil.class}) static boolean isCollinearPoints(double x1, double y1, double x2, double y2, double x3, double y3) { // Test if three points are colinears // iff det( [ x1 x2 x3 ] // [ y1 y2 y3 ] // [ 1 1 1 ] ) = 0 // Do not invoked MathUtil.determinant() to limit computations. return MathUtil.isEpsilonZero(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)); } /** Compute the distance between 2 points. * * @param x1 horizontal position of the first point. * @param y1 vertical position of the first point. * @param x2 horizontal position of the second point. * @param y2 vertical position of the second point. * @return the distance between given points. * @see #getDistanceSquaredPointPoint(double, double, double, double) * @see #getDistanceL1PointPoint(double, double, double, double) */ @Pure @Inline(value = "Math.hypot(($1) - ($3), ($2) - ($4))", imported = {Math.class}) static double getDistancePointPoint(double x1, double y1, double x2, double y2) { return Math.hypot(x1 - x2, y1 - y2); } /** Compute the squared distance between 2 points. * * @param x1 horizontal position of the first point. * @param y1 vertical position of the first point. * @param x2 horizontal position of the second point. * @param y2 vertical position of the second point. * @return the squared distance between given points. * @see #getDistancePointPoint(double, double, double, double) * @see #getDistanceL1PointPoint(double, double, double, double) */ @Pure @Inline(value = "(($1)-($3))*(($1)-($3)) + (($2)-($4))*(($2)-($4))") static double getDistanceSquaredPointPoint(double x1, double y1, double x2, double y2) { final double dx = x1 - x2; final double dy = y1 - y2; return dx * dx + dy * dy; } /** Compute the L-1 (Manhattan) distance between 2 points. * The L-1 distance is equal to abs(x1-x2) + abs(y1-y2). * * @param x1 horizontal position of the first point. * @param y1 vertical position of the first point. * @param x2 horizontal position of the second point. * @param y2 vertical position of the second point. * @return the distance between given points. * @see #getDistancePointPoint(double, double, double, double) * @see #getDistanceSquaredPointPoint(double, double, double, double) */ @Pure @Inline(value = "Math.abs(($1) - ($3)) + Math.abs(($2) - ($4))", imported = {Math.class}) static double getDistanceL1PointPoint(double x1, double y1, double x2, double y2) { return Math.abs(x1 - x2) + Math.abs(y1 - y2); } /** Compute the L-infinite distance between 2 points. * The L-infinite distance is equal to * MAX[abs(x1-x2), abs(y1-y2)]. * * @param x1 horizontal position of the first point. * @param y1 vertical position of the first point. * @param x2 horizontal position of the second point. * @param y2 vertical position of the second point. * @return the distance between given points. * @see #getDistancePointPoint(double, double, double, double) * @see #getDistanceSquaredPointPoint(double, double, double, double) */ @Pure @Inline(value = "Math.max(Math.abs(($1) - ($3)), Math.abs(($2) - ($4)))", imported = {Math.class}) static double getDistanceLinfPointPoint(double x1, double y1, double x2, double y2) { return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2)); } /** * Computes the square of the distance between this point and point p1. * @param point the other point * @return the distance. */ @Pure default double getDistanceSquared(Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(); return getDistanceSquaredPointPoint(getX(), getY(), point.getX(), point.getY()); } /** * Computes the distance between this point and point p1. * @param point the other point * @return the distance. */ @Pure default double getDistance(Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(); return getDistancePointPoint(getX(), getY(), point.getX(), point.getY()); } /** * Computes the L-1 (Manhattan) distance between this point and * point p1. The L-1 distance is equal to abs(x1-x2) + abs(y1-y2). * @param point the other point * @return the distance. */ @Pure default double getDistanceL1(Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(); return getDistanceL1PointPoint(getX(), getY(), point.getX(), point.getY()); } /** * Computes the L-infinite distance between this point and * point p1. The L-infinite distance is equal to * MAX[abs(x1-x2), abs(y1-y2)]. * @param point the other point * @return the distance. */ @Pure default double getDistanceLinf(Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(); return getDistanceLinfPointPoint(getX(), getY(), point.getX(), point.getY()); } /** * Computes the L-1 (Manhattan) distance between this point and * point p1. The L-1 distance is equal to abs(x1-x2) + abs(y1-y2). * @param point the other point * @return the distance. */ @Pure default int getIdistanceL1(Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(); return Math.abs(ix() - point.ix()) + Math.abs(iy() - point.iy()); } /** * Computes the L-infinite distance between this point and * point p1. The L-infinite distance is equal to * MAX[abs(x1-x2), abs(y1-y2)]. * @param point the other point * @return the distance. */ @Pure default int getIdistanceLinf(Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(); return Math.max(Math.abs(ix() - point.ix()), Math.abs(iy() - point.iy())); } /** * Sets the value of this tuple to the sum of tuples t1 and t2. * @param point the first tuple * @param vector the second tuple */ default void add(Point2D<?, ?> point, Vector2D<?, ?> vector) { assert point != null : AssertMessages.notNullParameter(0); assert vector != null : AssertMessages.notNullParameter(1); set(point.getX() + vector.getX(), point.getY() + vector.getY()); } /** * Sets the value of this tuple to the sum of tuples t1 and t2. * @param vector the first tuple * @param point the second tuple */ default void add(Vector2D<?, ?> vector, Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(0); assert vector != null : AssertMessages.notNullParameter(1); set(vector.getX() + point.getX(), vector.getY() + point.getY()); } /** * Sets the value of this tuple to the sum of itself and t1. * @param vector the other tuple */ default void add(Vector2D<?, ?> vector) { assert vector != null : AssertMessages.notNullParameter(); set(getX() + vector.getX(), getY() + vector.getY()); } /** * Sets the value of this tuple to the scalar multiplication * of tuple t1 plus tuple t2 (this = s*vector + point). * @param scale the scalar value * @param vector the tuple to be multipled * @param point the tuple to be added */ default void scaleAdd(int scale, Vector2D<?, ?> vector, Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(1); assert vector != null : AssertMessages.notNullParameter(2); set(scale * vector.getX() + point.getX(), scale * vector.getY() + point.getY()); } /** * Sets the value of this tuple to the scalar multiplication * of tuple t1 plus tuple t2 (this = s*vector + point). * @param scale the scalar value * @param vector the tuple to be multipled * @param point the tuple to be added */ default void scaleAdd(double scale, Vector2D<?, ?> vector, Point2D<?, ?> point) { assert point != null : AssertMessages.notNullParameter(1); assert vector != null : AssertMessages.notNullParameter(2); set(scale * vector.getX() + point.getX(), scale * vector.getY() + point.getY()); } /** * Sets the value of this tuple to the scalar multiplication * of tuple t1 plus tuple t2 (this = s*point + vector). * @param scale the scalar value * @param point the tuple to be multipled * @param vector the tuple to be added */ default void scaleAdd(int scale, Point2D<?, ?> point, Vector2D<?, ?> vector) { assert point != null : AssertMessages.notNullParameter(1); assert vector != null : AssertMessages.notNullParameter(2); set(scale * point.getX() + vector.getX(), scale * point.getY() + vector.getY()); } /** * Sets the value of this tuple to the scalar multiplication * of tuple t1 plus tuple t2 (this = s*point + vector). * @param scale the scalar value * @param point the tuple to be multipled * @param vector the tuple to be added */ default void scaleAdd(double scale, Point2D<?, ?> point, Vector2D<?, ?> vector) { assert point != null : AssertMessages.notNullParameter(1); assert vector != null : AssertMessages.notNullParameter(2); set(scale * point.getX() + vector.getX(), scale * point.getY() + vector.getY()); } /** * Sets the value of this tuple to the scalar multiplication * of itself and then adds tuple t1 (this = s*this + vector). * @param scale the scalar value * @param vector the tuple to be added */ default void scaleAdd(int scale, Vector2D<?, ?> vector) { assert vector != null : AssertMessages.notNullParameter(1); set(scale * getX() + vector.getX(), scale * getY() + vector.getY()); } /** * Sets the value of this tuple to the scalar multiplication * of itself and then adds tuple t1 (this = s*this + vector). * @param scale the scalar value * @param vector the tuple to be added */ default void scaleAdd(double scale, Vector2D<?, ?> vector) { assert vector != null : AssertMessages.notNullParameter(1); set(scale * getX() + vector.getX(), scale * getY() + vector.getY()); } /** * Sets the value of this tuple to the difference * of tuples point and vector (this = point - vector). * @param point the first tuple * @param vector the second tuple */ default void sub(Point2D<?, ?> point, Vector2D<?, ?> vector) { assert point != null : AssertMessages.notNullParameter(0); assert vector != null : AssertMessages.notNullParameter(1); set(point.getX() - vector.getX(), point.getY() - vector.getY()); } /** * Sets the value of this tuple to the difference * of itself and the given vector (this = this - vector). * @param vector the other tuple */ default void sub(Vector2D<?, ?> vector) { assert vector != null : AssertMessages.notNullParameter(); set(getX() - vector.getX(), getY() - vector.getY()); } /** Replies an unmodifiable copy of this point. * * @return an unmodifiable copy. */ @Pure UnmodifiablePoint2D<RP, RV> toUnmodifiable(); /** Replies the geometry factory associated to this point. * * @return the factory. */ @Pure GeomFactory2D<RV, RP> getGeomFactory(); /** Sum of this point and a vector: {@code this + v}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param v the vector to add * @return the result. * @see #add(Point2D, Vector2D) */ @Pure @XtextOperator("+") default RP operator_plus(Vector2D<?, ?> v) { assert v != null : AssertMessages.notNullParameter(); return getGeomFactory().newPoint(getX() + v.getX(), getY() + v.getY()); } /** Sum of this point and a scalar: {@code this + scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * <p>The operation {@code v + this} is supported by {@link Tuple2DExtensions#operator_plus(double, Point2D)}. * * @param scalar the scalar * @return the result. * @see #add(Point2D, Vector2D) * @see Tuple2DExtensions#operator_plus(double, Point2D) */ @Pure @XtextOperator("+") default RP operator_plus(double scalar) { return getGeomFactory().newPoint(getX() + scalar, getY() + scalar); } /** Increment this point with the given vector: {@code this += v}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param v the vector to add * @see #add(Vector2D) */ @XtextOperator("+=") default void operator_add(Vector2D<?, ?> v) { add(v); } /** Subtract the v vector to this point: {@code this - v}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param v the vector to substract. * @return the result. * @see #sub(Point2D, Vector2D) */ @Pure @XtextOperator("-") default RP operator_minus(Vector2D<?, ?> v) { assert v != null : AssertMessages.notNullParameter(); return getGeomFactory().newPoint(getX() - v.getX(), getY() - v.getY()); } /** Subtract the scalar to this point: {@code this - scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * <p>The operation {@code scalar - this} is supported by {@link Tuple2DExtensions#operator_minus(double, Point2D)}. * * @param scalar the scalar. * @return the result. * @see #sub(Point2D, Vector2D) * @see Tuple2DExtensions#operator_minus(double, Point2D) */ @Pure @XtextOperator("-") default RP operator_minus(double scalar) { return getGeomFactory().newPoint(getX() - scalar, getY() - scalar); } /** Subtract the p point to this point: {@code this - p}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param pt the point to substract * @return the vector from the p to this. * @see Vector2D#sub(Point2D, Point2D) */ @Pure @XtextOperator("-") default RV operator_minus(Point2D<?, ?> pt) { assert pt != null : AssertMessages.notNullParameter(); return getGeomFactory().newVector(getX() - pt.getX(), getY() - pt.getY()); } /** Subtract the v vector to this: {@code this -= v}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param v the vector to substract. * @see #sub(Vector2D) */ @XtextOperator("-=") default void operator_remove(Vector2D<?, ?> v) { sub(v); } /** Replies if the given vector is equal to this vector: {@code this == v}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param v the vector. * @return test result. * @see #equals(Tuple2D) */ @Pure @XtextOperator("==") default boolean operator_equals(Tuple2D<?> v) { return equals(v); } /** Replies if the given vector is different than this vector: {@code this != v}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param v the vector. * @return test result. * @see #equals(Tuple2D) */ @Pure @XtextOperator("!=") default boolean operator_notEquals(Tuple2D<?> v) { return !equals(v); } /** Replies if the distance between this and the p point: {@code this .. p}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param pt the point. * @return the distance. * @see #getDistance(Point2D) */ @Pure @XtextOperator("..") default double operator_upTo(Point2D<?, ?> pt) { return getDistance(pt); } /** Replies the distance between this point and the given shape: {@code this .. s}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param shape the shape to test. * @return the distance. * @see Shape2D#getDistance(Point2D) */ @Pure @XtextOperator("..") default double operator_upTo(Shape2D<?, ?, ?, ?, ?, ?> shape) { return shape.getDistance(this); } /** If this point is epsilon equal to zero then reply p else reply this: {@code this ?: p}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param pt the point. * @return the point. */ @Pure @XtextOperator("?:") default Point2D<? extends RP, ? extends RV> operator_elvis(Point2D<? extends RP, ? extends RV> pt) { if (MathUtil.isEpsilonZero(getX()) && MathUtil.isEpsilonZero(getY())) { return pt; } return this; } /** Replies if the this point is inside the given shape: {@code this && s}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param shape the shape to test. * @return <code>true</code> if the point is inside the shape. Otherwise, <code>false</code>. * @see Shape2D#contains(Point2D) */ @Pure @XtextOperator("&&") default boolean operator_and(Shape2D<?, ?, ?, ?, ?, ?> shape) { return shape.contains(this); } /** Sum of this point and a vector: {@code this + v}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @param v the vector to add * @return the result. * @see #add(Point2D, Vector2D) */ @Pure @ScalaOperator("+") default RP $plus(Vector2D<?, ?> v) { return operator_plus(v); } /** Sum of this point and a scalar: {@code this + scalar}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * <p>The operation {@code v + this} is supported by * {@link org.arakhne.afc.math.extensions.scala.Tuple2DExtensions#$plus(double, Point2D)}. * * @param scalar the scalar * @return the result. * @see #add(Point2D, Vector2D) * @see org.arakhne.afc.math.extensions.scala.Tuple2DExtensions#$plus(double, Point2D) */ @Pure @ScalaOperator("+") default RP $plus(double scalar) { return operator_plus(scalar); } /** Subtract the v vector to this point: {@code this - v}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @param v the vector to substract. * @return the result. * @see #sub(Point2D, Vector2D) */ @Pure @ScalaOperator("-") default RP $minus(Vector2D<?, ?> v) { return operator_minus(v); } /** Subtract the scalar to this point: {@code this - scalar}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * <p>The operation {@code scalar - this} is supported by * {@link org.arakhne.afc.math.extensions.scala.Tuple2DExtensions#$minus(double, Point2D)}. * * @param scalar the scalar. * @return the result. * @see #sub(Point2D, Vector2D) * @see org.arakhne.afc.math.extensions.scala.Tuple2DExtensions#$minus(double, Point2D) */ @Pure @ScalaOperator("-") default RP $minus(double scalar) { return operator_minus(scalar); } /** Subtract the p point to this point: {@code this - p}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @param pt the point to substract * @return the vector from the p to this. * @see Vector2D#sub(Point2D, Point2D) */ @Pure @ScalaOperator("-") default RV $minus(Point2D<?, ?> pt) { return operator_minus(pt); } /** Replies if the this point is inside the given shape: {@code this && s}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @param shape the shape to test. * @return <code>true</code> if the point is inside the shape. Otherwise, <code>false</code>. * @see Shape2D#contains(Point2D) */ @Pure @ScalaOperator("&&") default boolean $amp$amp(Shape2D<?, ?, ?, ?, ?, ?> shape) { return operator_and(shape); } /** Turn this point about the given rotation angle around the origin point. * * <p>The rotation is done according to the trigonometric coordinate. * A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @see #turn(double, Point2D, Point2D) * @see #turnLeft(double) * @see #turnRight(double) */ default void turn(double angle) { turn(angle, this); } /** Turn the given point about the given rotation angle around the origin point, and set this * point with the result. * * <p>The rotation is done according to the trigonometric coordinate. * A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @param pointToTurn the point to turn. * @see #turn(double, Point2D, Point2D) * @see #turn(double) * @see #turnLeft(double) * @see #turnRight(double) */ default void turn(double angle, Point2D<?, ?> pointToTurn) { assert pointToTurn != null : AssertMessages.notNullParameter(1); final double sin = Math.sin(angle); final double cos = Math.cos(angle); final double x = cos * pointToTurn.getX() - sin * pointToTurn.getY(); final double y = sin * pointToTurn.getX() + cos * pointToTurn.getY(); set(x, y); } /** Turn the given point about the given rotation angle around the origin point, and set this * point with the result. * * <p>The rotation is done according to the trigonometric coordinate. * A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @param pointToTurn the point to turn. * @param origin the origin point. * @see #turn(double, Point2D) * @see #turn(double) * @see #turnLeft(double) * @see #turnRight(double) */ default void turn(double angle, Point2D<?, ?> pointToTurn, Point2D<?, ?> origin) { assert pointToTurn != null : AssertMessages.notNullParameter(1); assert origin != null : AssertMessages.notNullParameter(2); final double sin = Math.sin(angle); final double cos = Math.cos(angle); final double vx = pointToTurn.getX() - origin.getX(); final double vy = pointToTurn.getY() - origin.getY(); final double x = cos * vx - sin * vy; final double y = sin * vx + cos * vy; set(x + origin.getX(), y + origin.getY()); } /** Turn this vector on the left around the origin when the given rotation angle is positive. * * <p>A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @see CoordinateSystem2D * @see #turnLeft(double, Point2D, Point2D) * @see #turn(double) * @see #turnRight(double) */ default void turnLeft(double angle) { turnLeft(angle, this); } /** Turn the given vector on the left, and set this * vector with the result. * * <p>A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @param pointToTurn the vector to turn. * @see CoordinateSystem2D * @see #turnLeft(double, Point2D, Point2D) * @see #turn(double) * @see #turnRight(double) */ default void turnLeft(double angle, Point2D<?, ?> pointToTurn) { assert pointToTurn != null : AssertMessages.notNullParameter(1); final double sin = Math.sin(angle); final double cos = Math.cos(angle); final double x; final double y; if (CoordinateSystem2D.getDefaultCoordinateSystem().isRightHanded()) { x = cos * pointToTurn.getX() - sin * pointToTurn.getY(); y = sin * pointToTurn.getX() + cos * pointToTurn.getY(); } else { x = cos * pointToTurn.getX() + sin * pointToTurn.getY(); y = -sin * pointToTurn.getX() + cos * pointToTurn.getY(); } set(x, y); } /** Turn the given vector on the left, and set this * vector with the result. * * <p>A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @param pointToTurn the vector to turn. * @param origin the origin point. * @see CoordinateSystem2D * @see #turnLeft(double, Point2D) * @see #turn(double) * @see #turnRight(double) */ default void turnLeft(double angle, Point2D<?, ?> pointToTurn, Point2D<?, ?> origin) { assert pointToTurn != null : AssertMessages.notNullParameter(1); assert origin != null : AssertMessages.notNullParameter(2); final double sin = Math.sin(angle); final double cos = Math.cos(angle); final double vx = pointToTurn.getX() - origin.getX(); final double vy = pointToTurn.getY() - origin.getY(); final double x; final double y; if (CoordinateSystem2D.getDefaultCoordinateSystem().isRightHanded()) { x = cos * vx - sin * vy; y = sin * vx + cos * vy; } else { x = cos * vx + sin * vy; y = -sin * vx + cos * vy; } set(x + origin.getX(), y + origin.getY()); } /** Turn this vector on the right around the origin when the given rotation angle is positive. * * <p>A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @see CoordinateSystem2D * @see #turn(double) * @see #turnLeft(double) */ default void turnRight(double angle) { turnLeft(-angle, this); } /** Turn this vector on the right around the origin when the given rotation angle is positive. * * <p>A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @param pointToTurn the vector to turn. * @see CoordinateSystem2D * @see #turn(double) * @see #turnLeft(double) */ default void turnRight(double angle, Point2D<?, ?> pointToTurn) { turnLeft(-angle, pointToTurn); } /** Turn this vector on the right around the origin when the given rotation angle is positive. * * <p>A positive rotation angle corresponds to a left or right rotation * according to the current {@link CoordinateSystem2D}. * * @param angle is the rotation angle in radians. * @param pointToTurn the vector to turn. * @param origin the origin point. * @see CoordinateSystem2D * @see #turn(double) * @see #turnLeft(double) */ default void turnRight(double angle, Point2D<?, ?> pointToTurn, Point2D<?, ?> origin) { turnLeft(-angle, pointToTurn, origin); } }