/* * $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.afp; import java.util.NoSuchElementException; import org.eclipse.xtext.xbase.lib.Pure; import org.arakhne.afc.math.MathConstants; import org.arakhne.afc.math.MathUtil; import org.arakhne.afc.math.Unefficient; import org.arakhne.afc.math.geometry.CrossingComputationType; import org.arakhne.afc.math.geometry.PathWindingRule; import org.arakhne.afc.math.geometry.d2.Point2D; import org.arakhne.afc.math.geometry.d2.Transform2D; import org.arakhne.afc.math.geometry.d2.Tuple2D; import org.arakhne.afc.math.geometry.d2.Vector2D; import org.arakhne.afc.vmutil.asserts.AssertMessages; /** Fonctional interface that represented a 2D oriented rectangle on a plane. * An oriented rectangle is a parallelogram with orthogonal axes. * * @param <ST> is the type of the general implementation. * @param <IT> is the type of the implementation of this shape. * @param <IE> is the type of the path elements. * @param <P> is the type of the points. * @param <V> is the type of the vectors. * @param <B> is the type of the bounding boxes. * @author $Author: sgalland$ * @author $Author: ngaud$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public interface OrientedRectangle2afp< ST extends Shape2afp<?, ?, IE, P, V, B>, IT extends OrientedRectangle2afp<?, ?, IE, P, V, B>, IE extends PathElement2afp, P extends Point2D<? super P, ? super V>, V extends Vector2D<? super V, ? super P>, B extends Rectangle2afp<?, ?, IE, P, V, B>> extends Parallelogram2afp<ST, IT, IE, P, V, B> { /** Project the given vector on the R axis, assuming S axis is orthogonal. * * <p>This function assumes that axes are orthogonal. For a general projection on the R axis, * see {@link Parallelogram2afp#findsVectorProjectionRAxisPoint(double, double, double, double, double, double)}. * * @param rx the x coordinate of the R axis. * @param ry the y coordinate of the R axis. * @param x the x coordinate of the vector. * @param y the y coordinate of the vector. * @return the coordinate of the projection of the vector on R * @see Parallelogram2afp#findsVectorProjectionRAxisPoint(double, double, double, double, double, double) * @deprecated since 13.0, see {@link #findsVectorProjectionRAxisVector(double, double, double, double)} */ @Deprecated @Pure static double projectVectorOnOrientedRectangleRAxis(double rx, double ry, double x, double y) { return findsVectorProjectionRAxisVector(rx, ry, x, y); } /** Project the given vector on the R axis, assuming S axis is orthogonal. * * <p>This function assumes that axes are orthogonal. For a general projection on the R axis, * see {@link Parallelogram2afp#findsVectorProjectionRAxisPoint(double, double, double, double, double, double)}. * * @param rx the x coordinate of the R axis. * @param ry the y coordinate of the R axis. * @param x the x coordinate of the vector. * @param y the y coordinate of the vector. * @return the coordinate of the projection of the vector on R * @see Parallelogram2afp#findsVectorProjectionRAxisPoint(double, double, double, double, double, double) */ @Pure static double findsVectorProjectionRAxisVector(double rx, double ry, double x, double y) { assert Vector2D.isUnitVector(rx, ry) : AssertMessages.normalizedParameters(0, 1); return Vector2D.dotProduct(x, y, rx, ry); } /** Project the given vector on the S axis, assuming R axis is orthogonal. * * <p>This function assumes that axes are orthogonal. For a general projection on the S axis, * see {@link Parallelogram2afp#findsVectorProjectionSAxisVector(double, double, double, double, double, double)}. * * @param rx the x coordinate of the R axis (NOT the S axis). * @param ry the y coordinate of the R axis (NOT the S axis). * @param x the x coordinate of the vector. * @param y the y coordinate of the vector. * @return the coordinate of the projection of the vector on S * @see Parallelogram2afp#findsVectorProjectionSAxisVector(double, double, double, double, double, double) * @deprecated since 13.0, see {@link #findsVectorProjectionSAxisVector(double, double, double, double)} */ @Deprecated @Pure static double projectVectorOnOrientedRectangleSAxis(double rx, double ry, double x, double y) { return findsVectorProjectionSAxisVector(rx, ry, x, y); } /** Project the given vector on the S axis, assuming R axis is orthogonal. * * <p>This function assumes that axes are orthogonal. For a general projection on the S axis, * see {@link Parallelogram2afp#findsVectorProjectionSAxisVector(double, double, double, double, double, double)}. * * @param rx the x coordinate of the R axis (NOT the S axis). * @param ry the y coordinate of the R axis (NOT the S axis). * @param x the x coordinate of the vector. * @param y the y coordinate of the vector. * @return the coordinate of the projection of the vector on S * @see Parallelogram2afp#findsVectorProjectionSAxisVector(double, double, double, double, double, double) */ @Pure static double findsVectorProjectionSAxisVector(double rx, double ry, double x, double y) { assert Vector2D.isUnitVector(rx, ry) : AssertMessages.normalizedParameters(0, 1); return Vector2D.dotProduct(x, y, -ry, rx); } /** * Compute the center point and axis extents of an oriented rectangle from a set of points and * the oriented rectangle axes. * * <p>This function assumes orthogonal axes, in opposite to * {@link Parallelogram2afp#calculatesCenterPointAxisExtents(Iterable, Vector2D, Vector2D, Point2D, Tuple2D)}, which * assumes not constraint on the axes. * * @param points is the list of the points enclosed by the oriented rectangle. * @param raxis is the R axis of the oriented rectangle. * @param center is the point which is set with the parallogram's center coordinates. * @param extents are the extents of the parallogram for the R and S axis. * @see "MGPCG pages 222-223 (oriented bounding box)" * @see Parallelogram2afp#calculatesCenterPointAxisExtents(Iterable, Vector2D, Vector2D, Point2D, Tuple2D) * @deprecated since 13.0, see {@link #calculatesCenterPointAxisExtents(Iterable, Vector2D, Point2D, Tuple2D)} */ @Deprecated static void computeCenterPointAxisExtents( Iterable<? extends Point2D<?, ?>> points, Vector2D<?, ?> raxis, Point2D<?, ?> center, Tuple2D<?> extents) { calculatesCenterPointAxisExtents(points, raxis, center, extents); } /** * Compute the center point and axis extents of an oriented rectangle from a set of points and * the oriented rectangle axes. * * <p>This function assumes orthogonal axes, in opposite to * {@link Parallelogram2afp#calculatesCenterPointAxisExtents(Iterable, Vector2D, Vector2D, Point2D, Tuple2D)}, which * assumes not constraint on the axes. * * @param points is the list of the points enclosed by the oriented rectangle. * @param raxis is the R axis of the oriented rectangle. * @param center is the point which is set with the parallogram's center coordinates. * @param extents are the extents of the parallogram for the R and S axis. * @see "MGPCG pages 222-223 (oriented bounding box)" * @see Parallelogram2afp#calculatesCenterPointAxisExtents(Iterable, Vector2D, Vector2D, Point2D, Tuple2D) */ static void calculatesCenterPointAxisExtents( Iterable<? extends Point2D<?, ?>> points, Vector2D<?, ?> raxis, Point2D<?, ?> center, Tuple2D<?> extents) { assert points != null : AssertMessages.notNullParameter(0); assert raxis != null : AssertMessages.notNullParameter(1); assert raxis.isUnitVector() : AssertMessages.normalizedParameter(1); assert center != null : AssertMessages.notNullParameter(2); assert extents != null : AssertMessages.notNullParameter(3); double minR = Double.POSITIVE_INFINITY; double maxR = Double.NEGATIVE_INFINITY; double minS = Double.POSITIVE_INFINITY; double maxS = Double.NEGATIVE_INFINITY; final double ux = raxis.getX(); final double uy = raxis.getY(); final double vx = -uy; final double vy = ux; for (final Point2D<?, ?> tuple : points) { final double pdotr = findsVectorProjectionRAxisVector(ux, uy, tuple.getX(), tuple.getY()); final double pdots = findsVectorProjectionSAxisVector(ux, uy, tuple.getX(), tuple.getY()); if (pdotr < minR) { minR = pdotr; } if (pdotr > maxR) { maxR = pdotr; } if (pdots < minS) { minS = pdots; } if (pdots > maxS) { maxS = pdots; } } final double a = (maxR + minR) / 2.; final double b = (maxS + minS) / 2.; // Set the center of the oriented rectangle center.set( a * ux + b * vx, a * uy + b * vy); // Compute extents extents.set( (maxR - minR) / 2., (maxS - minS) / 2.); } /** Replies if a point is inside in the oriented rectangle. * * @param px * is the X coordinate of the point to test. * @param py * is the Y coordinate of the point to test. * @param centerX * is the X coordinate of the oriented rectangle center. * @param centerY * is the Y coordinate of the oriented rectangle center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent * is the extent of the axis 2 of the oriented rectangle. * @return <code>true</code> if the given point is inside the oriented rectangle; * otherwise <code>false</code>. */ @Pure @SuppressWarnings("checkstyle:magicnumber") static boolean containsOrientedRectanglePoint( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double px, double py) { assert axis1Extent >= 0 : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0 : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); final double x = px - centerX; final double y = py - centerY; double coordinate = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis1Extent || coordinate > axis1Extent) { return false; } coordinate = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); return coordinate >= -axis2Extent && coordinate <= axis2Extent; } /** Replies if a point is inside the oriented rectangle. * * @param centerX * is the X coordinate of the oriented rectangle center. * @param centerY * is the Y coordinate of the oriented rectangle center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent * is the extent of the axis 2 of the oriented rectangle. * @param rx * is the X coordinate of the lower point of the rectangle. * @param ry * is the Y coordinate of the lower point of the rectangle. * @param rwidth * is the width of the rectangle. * @param rheight * is the height of the rectangle. * @return <code>true</code> if the given rectangle is inside the oriented rectangle; * otherwise <code>false</code>. */ @Pure @Unefficient @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:returncount", "checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity", "checkstyle:magicnumber"}) static boolean containsOrientedRectangleRectangle( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double rx, double ry, double rwidth, double rheight) { assert axis1Extent >= 0 : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0 : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); assert rwidth >= 0 : AssertMessages.positiveOrZeroParameter(8); assert rheight >= 0 : AssertMessages.positiveOrZeroParameter(9); final double basex = rx - centerX; final double basey = ry - centerY; double x = basex; double y = basey; double coordinate = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis1Extent || coordinate > axis1Extent) { return false; } coordinate = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis2Extent || coordinate > axis2Extent) { return false; } x = basex + rwidth; coordinate = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis1Extent || coordinate > axis1Extent) { return false; } coordinate = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis2Extent || coordinate > axis2Extent) { return false; } y = basey + rheight; coordinate = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis1Extent || coordinate > axis1Extent) { return false; } coordinate = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis2Extent || coordinate > axis2Extent) { return false; } x = basex; coordinate = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); if (coordinate < -axis1Extent || coordinate > axis1Extent) { return false; } coordinate = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); return coordinate >= -axis2Extent && coordinate <= axis2Extent; } /** * Given a point p, this function computes the point q1 on (or in) this oriented rectangle, * closest to p; and the point q2 on the oriented rectangle, farthest to p. If there are several * points, the function will return one of those. Remember this function may * return an approximate result when points remain on oriented rectangle plane of symmetry. * * @param px * is the X coordinate of the point to test. * @param py * is the Y coordinate of the point to test. * @param centerX * is the X coordinate of the oriented rectangle center. * @param centerY * is the Y coordinate of the oriented rectangle center. * @param axis1X * is the X coordinate of the axis 1 vector. * @param axis1Y * is the Y coordinate of the axis 1 vector. * @param axis1Extent * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent * is the extent of the axis 2 of the oriented rectangle. * @param closest the closest point. If <code>null</code>, the closest point is not computed. * @param farthest the farthest point. If <code>null</code>, the farthest point is not computed. * @deprecated since 13.0, see {@link #findsClosestFarthestPointsPointOrientedRectangle(double, * double, double, double, double, double, double, double, Point2D, Point2D)} */ @Deprecated @SuppressWarnings("checkstyle:parameternumber") static void computeClosestFarthestPoints( double px, double py, double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, Point2D<?, ?> closest, Point2D<?, ?> farthest) { findsClosestFarthestPointsPointOrientedRectangle(px, py, centerX, centerY, axis1X, axis1Y, axis1Extent, axis2Extent, closest, farthest); } /** } * Given a point p, this function computes the point q1 on (or in) this oriented rectangle, * closest to p; and the point q2 on the oriented rectangle, farthest to p. If there are several * points, the function will return one of those. Remember this function may * return an approximate result when points remain on oriented rectangle plane of symmetry. * * @param px * is the X coordinate of the point to test. * @param py * is the Y coordinate of the point to test. * @param centerX * is the X coordinate of the oriented rectangle center. * @param centerY * is the Y coordinate of the oriented rectangle center. * @param axis1X * is the X coordinate of the axis 1 vector. * @param axis1Y * is the Y coordinate of the axis 1 vector. * @param axis1Extent * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent * is the extent of the axis 2 of the oriented rectangle. * @param closest the closest point. If <code>null</code>, the closest point is not computed. * @param farthest the farthest point. If <code>null</code>, the farthest point is not computed. */ @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static void findsClosestFarthestPointsPointOrientedRectangle( double px, double py, double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, Point2D<?, ?> closest, Point2D<?, ?> farthest) { assert axis1Extent >= 0. : AssertMessages.positiveOrZeroParameter(6); assert axis2Extent >= 0. : AssertMessages.positiveOrZeroParameter(7); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(4, 5); assert closest != null || farthest != null : AssertMessages.oneNotNullParameter(8, 9); final double dx = px - centerX; final double dy = py - centerY; // For each axis project d onto that axis to get the distance along // the axis of d from the parallelogram center double d1 = findsVectorProjectionRAxisVector(axis1X, axis1Y, dx, dy); double d2 = findsVectorProjectionSAxisVector(axis1X, axis1Y, dx, dy); if (closest != null) { final double clampedD1 = MathUtil.clamp(d1, -axis1Extent, axis1Extent); final double clampedD2 = MathUtil.clamp(d2, -axis2Extent, axis2Extent); // Step that distance along the axis to get world coordinate // q1 += dist * this.axis[i]; (If distance farther than the box // extents, clamp to the box) closest.set( centerX + clampedD1 * axis1X - clampedD2 * axis1Y, centerY + clampedD1 * axis1Y + clampedD2 * axis1X); } if (farthest != null) { // Clamp to the other side of the box if (d1 >= 0.) { d1 = -axis1Extent; } else { d1 = axis1Extent; } if (d2 >= 0.) { d2 = -axis2Extent; } else { d2 = axis2Extent; } // Step that distance along the axis to get world coordinate // q2 += dist * this.axis[i]; farthest.set( centerX + d1 * axis1X - d2 * axis1Y, centerY + d1 * axis1Y + d2 * axis1X); } } /** Replies if the specified rectangle intersects the specified segment. * * @param centerX * is the X coordinate of the oriented rectangle center. * @param centerY * is the Y coordinate of the oriented rectangle center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent * is the extent of the axis 2 of the oriented rectangle. * @param s1x is the X coordinate of the first point of the segment. * @param s1y is the Y coordinate of the first point of the segment. * @param s2x is the X coordinate of the second point of the segment. * @param s2y is the Y coordinate of the second point of the segment. * @return <code>true</code> if intersecting, otherwise <code>false</code> */ @Pure @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static boolean intersectsOrientedRectangleSegment( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double s1x, double s1y, double s2x, double s2y) { assert axis1Extent >= 0. : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0. : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); //Changing Segment coordinate basis. double x = s1x - centerX; double y = s1y - centerY; final double ax = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); final double ay = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); x = s2x - centerX; y = s2y - centerY; final double bx = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); final double by = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); return Rectangle2afp.intersectsRectangleSegment( -axis1Extent, -axis2Extent, axis1Extent, axis2Extent, ax, ay, bx, by); } /** Replies if the specified rectangle intersects the specified triangle. * * @param centerX * is the X coordinate of the oriented rectangle center. * @param centerY * is the Y coordinate of the oriented rectangle center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent * is the extent of the axis 2 of the oriented rectangle. * @param s1x is the X coordinate of the first point of the triangle. * @param s1y is the Y coordinate of the first point of the triangle. * @param s2x is the X coordinate of the second point of the triangle. * @param s2y is the Y coordinate of the second point of the triangle. * @param s3x is the X coordinate of the third point of the triangle. * @param s3y is the Y coordinate of the third point of the triangle. * @return <code>true</code> if intersecting, otherwise <code>false</code> */ @Pure @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static boolean intersectsOrientedRectangleTriangle( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double s1x, double s1y, double s2x, double s2y, double s3x, double s3y) { assert axis1Extent >= 0. : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0. : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); //Changing Triangle coordinate basis. double x = s1x - centerX; double y = s1y - centerY; final double ax = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); final double ay = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); x = s2x - centerX; y = s2y - centerY; final double bx = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); final double by = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); x = s3x - centerX; y = s3y - centerY; final double cx = findsVectorProjectionRAxisVector(axis1X, axis1Y, x, y); final double cy = findsVectorProjectionSAxisVector(axis1X, axis1Y, x, y); return Triangle2afp.intersectsTriangleRectangle( ax, ay, bx, by, cx, cy, -axis1Extent, -axis2Extent, 2. * axis1Extent, 2. * axis2Extent); } /** Replies if the parallelogram intersects the given ellipse. * * @param centerX * is the X coordinate of the parallelogram center. * @param centerY * is the Y coordinate of the parallelogram center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the parallelogram. * @param axis2Extent * is the extent of the axis 2 of the parallelogram. * @param ex is the coordinate of the min point of the ellipse rectangle. * @param ey is the coordinate of the min point of the ellipse rectangle. * @param ewidth is the width of the ellipse. * @param eheight is the height of the ellipse. * @return <code>true</code> if intersecting, otherwise <code>false</code> */ @Pure @Unefficient @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static boolean intersectsOrientedRectangleEllipse( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double ex, double ey, double ewidth, double eheight) { assert axis1Extent >= 0 : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0 : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); assert ewidth >= 0 : AssertMessages.positiveOrZeroParameter(7); assert eheight >= 0 : AssertMessages.positiveOrZeroParameter(8); if (ewidth <= 0 || eheight <= 0) { return false; } // Convert the oriented rectangle elements so that the ellipse is transformed to a circle centered at the origin. final double a = ewidth / 2.; final double b = eheight / 2.; final double translateX = ex + a; final double translateY = ey + b; final double transCenterX = (centerX - translateX) / a; final double transCenterY = (centerY - translateY) / b; double transAxis1X = axis1Extent * axis1X / a; double transAxis1Y = axis1Extent * axis1Y / b; final double length1 = Math.hypot(transAxis1X, transAxis1Y); transAxis1X /= length1; transAxis1Y /= length1; double transAxis2X = axis2Extent * -axis1Y / a; double transAxis2Y = axis2Extent * axis1X / b; final double length2 = Math.hypot(transAxis2X, transAxis2Y); transAxis2X /= length2; transAxis2Y /= length2; return Parallelogram2afp.intersectsParallelogramCircle( transCenterX, transCenterY, transAxis1X, transAxis1Y, length1, transAxis2X, transAxis2Y, length2, 0, 0, 1); } /** Replies if the specified parallelogram intersects the specified circle. * * @param centerX * is the X coordinate of the parallelogram center. * @param centerY * is the Y coordinate of the parallelogram center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the parallelogram. * @param axis2Extent * is the extent of the axis 2 of the parallelogram. * @param circleX is the coordinate of the circle center. * @param circleY is the coordinate of the circle center. * @param circleRadius is the radius of the circle. * @return <code>true</code> if intersecting, otherwise <code>false</code> */ @Pure @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static boolean intersectsOrientedRectangleCircle( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double circleX, double circleY, double circleRadius) { assert axis1Extent >= 0 : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0 : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); assert circleRadius >= 0 : AssertMessages.positiveOrZeroParameter(8); final Point2D<?, ?> closest = new InnerComputationPoint2afp(); findsClosestFarthestPointsPointOrientedRectangle( circleX, circleY, centerX, centerY, axis1X, axis1Y, axis1Extent, axis2Extent, closest, null); // Circle and oriented rectangle intersect if the (squared) distance from sphere // center to point p is less than the (squared) sphere radius final double squaredRadius = circleRadius * circleRadius; return Point2D.getDistanceSquaredPointPoint( circleX, circleY, closest.getX(), closest.getY()) <= squaredRadius; } /** Replies if the specified rectangles intersect. * * <p>The extents are assumed to be positive or zero. * The lengths of the given arrays are assumed to be <code>2</code>. * * <p>This function uses the "separating axis theorem" which states that * for any two oriented rectangles (AABB is a special case of oriented rectangle) * that do not touch, a separating axis can be found. * * <p>This function uses an general intersection test between two oriented rectangle. * If the first box is expected to be an MBR, please use the * optimized algorithm given by * {@link #intersectsOrientedRectangleRectangle(double, double, double, double, double, * double, double, double, double, double)}. * * @param centerX1 * is the X coordinate of the oriented rectangle center. * @param centerY1 * is the Y coordinate of the oriented rectangle center. * @param axis1X1 * is the X coordinate of the axis 1 unit vector. * @param axis1Y1 * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent1 * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent1 * is the extent of the axis 2 of the oriented rectangle. * @param centerX2 * is the X coordinate of the oriented rectangle center. * @param centerY2 * is the Y coordinate of the oriented rectangle center. * @param axis1X2 * is the X coordinate of the axis 1 unit vector. * @param axis1Y2 * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent2 * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent2 * is the extent of the axis 2 of the oriented rectangle. * @return <code>true</code> if intersecting, otherwise <code>false</code> * @see "RTCD pages 102-105" * @see <a href="http://www.jkh.me/files/tutorials/Separating%20Axis%20Theorem%20for%20Oriented%20Bounding%20Boxes.pdf">Intersection between two oriented boudning rectangles</a> */ @Pure @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static boolean intersectsOrientedRectangleOrientedRectangle( double centerX1, double centerY1, double axis1X1, double axis1Y1, double axis1Extent1, double axis2Extent1, double centerX2, double centerY2, double axis1X2, double axis1Y2, double axis1Extent2, double axis2Extent2) { assert axis1Extent1 >= 0. : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent1 >= 0. : AssertMessages.positiveOrZeroParameter(5); assert axis1Extent2 >= 0. : AssertMessages.positiveOrZeroParameter(10); assert axis2Extent2 >= 0. : AssertMessages.positiveOrZeroParameter(11); final double tx = centerX2 - centerX1; final double ty = centerY2 - centerY1; // Let A the first box and B the second one. // Let Ax and Ay the axes of A. // Let WA the extent related to Ax. // Let HA the extent related to Ay. // Let Bx and By the axes of B. // Let WB the extent related to Bx. // Let HB the extent related to By. // Case 1: // L = Ax // L is a separating axis iff: // | T.Ax | > WA + | ( WB * Bx ) . Ax | + |( HB * By ) . Ax | final double absTAx = Math.abs(findsVectorProjectionRAxisVector(axis1X1, axis1Y1, tx, ty)); final double bxx = axis1Extent2 * axis1X2; final double bxy = axis1Extent2 * axis1Y2; final double absbxax = Math.abs(findsVectorProjectionRAxisVector(axis1X1, axis1Y1, bxx, bxy)); final double byx = axis2Extent2 * -axis1Y2; final double byy = axis2Extent2 * axis1X2; final double absbyax = Math.abs(findsVectorProjectionRAxisVector(axis1X1, axis1Y1, byx, byy)); if (absTAx > (axis1Extent1 + absbxax + absbyax)) { return false; } // Case 2: // L = Ay // L is a separating axis iff: // | T.Ay | > HA + | ( WB * Bx ) . Ay | + |( HB * By ) . Ay | final double absTAy = Math.abs(findsVectorProjectionSAxisVector(axis1X1, axis1Y1, tx, ty)); final double absBxAy = Math.abs(findsVectorProjectionRAxisVector(-axis1Y1, axis1X1, bxx, bxy)); final double absByAy = Math.abs(findsVectorProjectionRAxisVector(-axis1Y1, axis1X1, byx, byy)); if (absTAy > (axis2Extent1 + absBxAy + absByAy)) { return false; } // Case 3: // L = Bx // L is a separating axis iff: // | T . Bx | > | ( WA * Ax ) . Bx | + | ( HA * Ay ) . Bx | + WB final double absTBx = Math.abs(findsVectorProjectionRAxisVector(axis1X2, axis1Y2, tx, ty)); final double axx = axis1Extent1 * axis1X1; final double axy = axis1Extent1 * axis1Y1; final double absAxBx = Math.abs(findsVectorProjectionRAxisVector(axis1X2, axis1Y2, axx, axy)); final double ayx = axis2Extent1 * -axis1Y1; final double ayy = axis2Extent1 * axis1X1; final double absAyBx = Math.abs(findsVectorProjectionRAxisVector(axis1X2, axis1Y2, ayx, ayy)); if (absTBx > (absAxBx + absAyBx + axis1Extent2)) { return false; } // Case 4: // L = By // L is a separating axis iff: // | T . By | > | ( WA * Ax ) . By | + | ( HA * Ay ) . By | + HB final double absTBy = Math.abs(findsVectorProjectionRAxisVector(-axis1Y2, axis1X2, tx, ty)); final double absAxBy = Math.abs(findsVectorProjectionRAxisVector(-axis1Y2, axis1X2, axx, axy)); final double absAyBy = Math.abs(findsVectorProjectionRAxisVector(-axis1Y2, axis1X2, ayx, ayy)); if (absTBy > (absAxBy + absAyBy + axis2Extent2)) { return false; } // No separating axis found, the two boxes are overlaping. return true; } /** Replies if the specified rectangles intersect. * * <p>This function is assuming that {@code lx1} is lower * or equal to {@code ux1}, and {@code ly1} is lower * or equal to {@code uy1}. * The extents are assumed to be positive or zero. * The lengths of the given arrays are assumed to be <code>2</code>. * * <p>This function uses the "separating axis theorem" which states that * for any two oriented rectangles (AABB is a special case of oriented rectangle) * that do not touch, a separating axis can be found. * * <p>This function uses an optimized algorithm for AABB as first parameter. * The general intersection type between two oriented rectangle is given by * {@link #intersectsOrientedRectangleOrientedRectangle}. * * @param centerX * is the X coordinate of the oriented rectangle center. * @param centerY * is the Y coordinate of the oriented rectangle center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the oriented rectangle. * @param axis2Extent * is the extent of the axis 2 of the oriented rectangle. * @param rx * is the X coordinate of the lower point of the rectangle. * @param ry * is the Y coordinate of the lower point of the rectangle. * @param rwidth * is the width of the rectangle. * @param rheight * is the height of the rectangle. * @return <code>true</code> if intersecting, otherwise <code>false</code> * @see "RTCD pages 102-105" * @see <a href="http://www.gamasutra.com/features/19991018/Gomez_5.htm">OBB collision detection on Gamasutra.com</a> */ @Pure @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static boolean intersectsOrientedRectangleRectangle( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double rx, double ry, double rwidth, double rheight) { assert rwidth >= 0. : AssertMessages.positiveOrZeroParameter(8); assert rheight >= 0. : AssertMessages.positiveOrZeroParameter(9); assert axis1Extent >= 0. : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0. : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(1, 2); final double rx2 = rx + rwidth; final double ry2 = ry + rheight; final double axis2X = -axis1Y; final double axis2Y = axis1X; // Test border intersections final double px1 = centerX + axis1Extent * axis1X + axis2Extent * axis2X; final double py1 = centerY + axis1Extent * axis1Y + axis2Extent * axis2Y; final double px2 = centerX - axis1Extent * axis1X + axis2Extent * axis2X; final double py2 = centerY - axis1Extent * axis1Y + axis2Extent * axis2Y; if (Rectangle2afp.intersectsRectangleSegment(rx, ry, rx2, ry2, px1, py1, px2, py2)) { return true; } final double px3 = centerX - axis1Extent * axis1X - axis2Extent * axis2X; final double py3 = centerY - axis1Extent * axis1Y - axis2Extent * axis2Y; if (Rectangle2afp.intersectsRectangleSegment(rx, ry, rx2, ry2, px2, py2, px3, py3)) { return true; } final double px4 = centerX + axis1Extent * axis1X - axis2Extent * axis2X; final double py4 = centerY + axis1Extent * axis1Y - axis2Extent * axis2Y; if (Rectangle2afp.intersectsRectangleSegment(rx, ry, rx2, ry2, px3, py3, px4, py4)) { return true; } if (Rectangle2afp.intersectsRectangleSegment(rx, ry, rx2, ry2, px4, py4, px1, py1)) { return true; } // The rectangle is entirely outside or entirely inside the parallelogram. // Test if one rectangle point is inside the parallelogram. // We need to test only one point from the rectangle, since if the first // point is not inside, the other three points are not too. if (containsOrientedRectanglePoint( centerX, centerY, axis1X, axis1Y, axis1Extent, axis2Extent, rx, ry)) { return true; } // Test if one parallelogram point is inside the rectangle // We need to test only one point from the rectangle, since if the first // point is not inside, the other three points are not too. return Rectangle2afp.containsRectanglePoint(rx, ry, rx2, ry2, px1, py1); } /** Replies if the oriented rectangle intersects the given rectangle. * * @param centerX * is the X coordinate of the parallelogram center. * @param centerY * is the Y coordinate of the parallelogram center. * @param axis1X * is the X coordinate of the axis 1 unit vector. * @param axis1Y * is the Y coordinate of the axis 1 unit vector. * @param axis1Extent * is the extent of the axis 1 of the parallelogram. * @param axis2Extent * is the extent of the axis 2 of the parallelogram. * @param rx * is the X coordinate of the lower point of the rectangle. * @param ry * is the Y coordinate of the lower point of the rectangle. * @param rwidth * is the width of the rectangle. * @param rheight * is the height of the rectangle. * @param rArcWidth * is the width of the rectangle arcs. * @param rArcHeight * is the height of the rectangle arcs. * @return <code>true</code> if intersecting, otherwise <code>false</code>. */ @Pure @Unefficient @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:cyclomaticcomplexity", "checkstyle:magicnumber"}) static boolean intersectsOrientedRectangleRoundRectangle( double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent, double rx, double ry, double rwidth, double rheight, double rArcWidth, double rArcHeight) { assert axis1Extent >= 0 : AssertMessages.positiveOrZeroParameter(4); assert axis2Extent >= 0 : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); assert rwidth >= 0 : AssertMessages.positiveOrZeroParameter(8); assert rheight >= 0 : AssertMessages.positiveOrZeroParameter(9); assert rArcWidth >= 0 : AssertMessages.positiveOrZeroParameter(10); assert rArcHeight >= 0 : AssertMessages.positiveOrZeroParameter(11); final double rx2 = rx + rwidth; final double ry2 = ry + rheight; final double rxmin = rx + rArcWidth; final double rxmax = rx2 - rArcWidth; final double rymin = ry + rArcHeight; final double rymax = ry2 - rArcHeight; final double ew = rArcWidth * 2; final double eh = rArcWidth * 2; final double emaxx = rxmax - rArcWidth; final double emaxy = rymax - rArcHeight; final double axis2X = -axis1Y; final double axis2Y = axis1X; // Test border intersections final double px1 = centerX + axis1Extent * axis1X + axis2Extent * axis2X; final double py1 = centerY + axis1Extent * axis1Y + axis2Extent * axis2Y; final double px2 = centerX - axis1Extent * axis1X + axis2Extent * axis2X; final double py2 = centerY - axis1Extent * axis1Y + axis2Extent * axis2Y; if (Rectangle2afp.intersectsRectangleSegment(rxmin, ry, rxmax, ry2, px1, py1, px2, py2) || Rectangle2afp.intersectsRectangleSegment(rx, rymin, rx2, rymax, px1, py1, px2, py2) || Ellipse2afp.intersectsEllipseSegment(rx, ry, ew, eh, px1, py1, px2, py2, false) || Ellipse2afp.intersectsEllipseSegment(rx, emaxy, ew, eh, px1, py1, px2, py2, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, emaxy, ew, eh, px1, py1, px2, py2, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, ry, ew, eh, px1, py1, px2, py2, false)) { return true; } final double px3 = centerX - axis1Extent * axis1X - axis2Extent * axis2X; final double py3 = centerY - axis1Extent * axis1Y - axis2Extent * axis2Y; if (Rectangle2afp.intersectsRectangleSegment(rxmin, ry, rxmax, ry2, px2, py2, px3, py3) || Rectangle2afp.intersectsRectangleSegment(rx, rymin, rx2, rymax, px2, py2, px3, py3) || Ellipse2afp.intersectsEllipseSegment(rx, ry, ew, eh, px2, py2, px3, py3, false) || Ellipse2afp.intersectsEllipseSegment(rx, emaxy, ew, eh, px2, py2, px3, py3, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, emaxy, ew, eh, px2, py2, px3, py3, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, ry, ew, eh, px2, py2, px3, py3, false)) { return true; } final double px4 = centerX + axis1Extent * axis1X - axis2Extent * axis2X; final double py4 = centerY + axis1Extent * axis1Y - axis2Extent * axis2Y; if (Rectangle2afp.intersectsRectangleSegment(rxmin, ry, rxmax, ry2, px3, py3, px4, py4) || Rectangle2afp.intersectsRectangleSegment(rx, rymin, rx2, rymax, px3, py3, px4, py4) || Ellipse2afp.intersectsEllipseSegment(rx, ry, ew, eh, px3, py3, px4, py4, false) || Ellipse2afp.intersectsEllipseSegment(rx, emaxy, ew, eh, px3, py3, px4, py4, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, emaxy, ew, eh, px3, py3, px4, py4, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, ry, ew, eh, px3, py3, px4, py4, false)) { return true; } if (Rectangle2afp.intersectsRectangleSegment(rxmin, ry, rxmax, ry2, px4, py4, px1, py1) || Rectangle2afp.intersectsRectangleSegment(rx, rymin, rx2, rymax, px4, py4, px1, py1) || Ellipse2afp.intersectsEllipseSegment(rx, ry, ew, eh, px4, py4, px1, py1, false) || Ellipse2afp.intersectsEllipseSegment(rx, emaxy, ew, eh, px4, py4, px1, py1, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, emaxy, ew, eh, px4, py4, px1, py1, false) || Ellipse2afp.intersectsEllipseSegment(emaxx, ry, ew, eh, px4, py4, px1, py1, false)) { return true; } // The rectangle is entirely outside or entirely inside the oriented rectangle. // Test if one rectangle point is inside the oriented rectangle. // We need to test only one point from the rectangle, since if the first // point is not inside, the other three points are not too. if (containsOrientedRectanglePoint( centerX, centerY, axis1X, axis1Y, axis1Extent, axis2Extent, rx, ry)) { return true; } // Test if one oriented rectangle point is inside the rectangle // We need to test only one point from the rectangle, since if the first // point is not inside, the other three points are not too. return Rectangle2afp.containsRectanglePoint(rx, ry, rx2, ry2, px1, py1); } /** * Tests if the interior of the specified {@link PathIterator2afp} * intersects the interior of a specified set of oriented rectangular * coordinates. * * @param <T> the type of the path elements to iterate on. * @param centerX the specified X coordinate of the rectangle center. * @param centerY the specified Y coordinate of the rectangle center. * @param axis1X the X coordinate of the first axis of the rectangle. * @param axis1Y the Y coordinate of the first axis of the rectangle. * @param extent1 the extent the rectangle along the first axis. * @param extent2 the extent the rectangle along the second axis. * @param pathIterator the specified {@link PathIterator2afp}. * @return <code>true</code> if the specified {@link PathIterator2afp} and * the interior of the specified set of rectangular * coordinates intersect each other; <code>false</code> otherwise. */ @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:magicnumber"}) static <T extends PathElement2afp> boolean intersectsOrientedRectanglePathIterator( double centerX, double centerY, double axis1X, double axis1Y, double extent1, double extent2, PathIterator2afp<T> pathIterator) { assert pathIterator != null : AssertMessages.notNullParameter(6); assert extent1 >= 0. : AssertMessages.positiveOrZeroParameter(4); assert extent2 >= 0. : AssertMessages.positiveOrZeroParameter(5); assert Vector2D.isUnitVector(axis1X, axis1Y) : AssertMessages.normalizedParameters(2, 3); final int mask = pathIterator.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 2; final ProjectionToOrientedRectangleLocalCoordinateSystemPathIterator<T> localIterator = new ProjectionToOrientedRectangleLocalCoordinateSystemPathIterator<>( centerX, centerY, axis1X, axis1Y, pathIterator); final int crossings = Path2afp.calculatesCrossingsPathIteratorRectangleShadow( 0, localIterator, -extent1, -extent2, extent1, extent2, CrossingComputationType.SIMPLE_INTERSECTION_WHEN_NOT_POLYGON); return crossings == MathConstants.SHAPE_INTERSECTS || (crossings & mask) != 0; } @Pure @Override @SuppressWarnings("checkstyle:booleanexpressioncomplexity") default boolean equalsToShape(IT shape) { if (shape == null) { return false; } if (shape == this) { return true; } return getCenterX() == shape.getCenterX() && getCenterY() == shape.getCenterY() && getFirstAxisX() == shape.getFirstAxisX() && getFirstAxisY() == shape.getFirstAxisY() && getFirstAxisExtent() == shape.getFirstAxisExtent() && getSecondAxisX() == shape.getSecondAxisX() && getSecondAxisY() == shape.getSecondAxisY() && getSecondAxisExtent() == shape.getSecondAxisExtent(); } @Override default void clear() { set(0, 0, 1, 0, 0, 0); } @Override default void set(IT rectangle) { assert rectangle != null : AssertMessages.notNullParameter(); set(rectangle.getCenterX(), rectangle.getCenterY(), rectangle.getFirstAxisX(), rectangle.getFirstAxisY(), rectangle.getFirstAxisExtent(), rectangle.getSecondAxisExtent()); } /** {@inheritDoc} * * <p>For an oriented rectangle, the coordinates of the second axis are ignored. * Indeed, they are automatically computed for being orthogonal to the first axis. */ @Override default void set(double centerX, double centerY, double axis1x, double axis1y, double axis1Extent, double axis2x, double axis2y, double axis2Extent) { set(centerX, centerY, axis1x, axis1y, axis1Extent, axis2Extent); } /** Set the oriented rectangle. * The second axis is automatically computed. * * @param center is the oriented rectangle center. * @param axis1 is the first axis of the oriented rectangle. * @param axis1Extent is the extent of the first axis. * @param axis2Extent is the extent of the second axis. */ default void set(Point2D<?, ?> center, Vector2D<?, ?> axis1, double axis1Extent, double axis2Extent) { assert center != null : AssertMessages.notNullParameter(0); assert axis1 != null : AssertMessages.notNullParameter(1); set(center.getX(), center.getY(), axis1.getX(), axis1.getY(), axis1Extent, axis2Extent); } /** Set the oriented rectangle. * The second axis is automatically computed. * * @param centerX is the X coordinate of the oriented rectangle center. * @param centerY is the Y coordinate of the oriented rectangle center. * @param axis1X is the X coordinate of first axis of the oriented rectangle. * @param axis1Y is the Y coordinate of first axis of the oriented rectangle. * @param axis1Extent is the extent of the first axis. * @param axis2Extent is the extent of the second axis. */ void set(double centerX, double centerY, double axis1X, double axis1Y, double axis1Extent, double axis2Extent); @Override default void setFromPointCloud(Iterable<? extends Point2D<?, ?>> pointCloud) { assert pointCloud != null : AssertMessages.notNullParameter(); final Vector2D<?, ?> r = new InnerComputationVector2afp(); Parallelogram2afp.calculatesOrthogonalAxes(pointCloud, r, null); final Point2D<?, ?> center = new InnerComputationPoint2afp(); final Vector2D<?, ?> extents = new InnerComputationVector2afp(); OrientedRectangle2afp.calculatesCenterPointAxisExtents(pointCloud, r, center, extents); set(center.getX(), center.getY(), r.getX(), r.getY(), extents.getX(), extents.getY()); } @Pure @Override default double getDistanceSquared(Point2D<?, ?> pt) { assert pt != null : AssertMessages.notNullParameter(); final Point2D<?, ?> closest = new InnerComputationPoint2afp(); findsClosestFarthestPointsPointOrientedRectangle( pt.getX(), pt.getY(), getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), closest, null); return closest.getDistanceSquared(pt); } @Pure @Override default double getDistanceL1(Point2D<?, ?> pt) { assert pt != null : AssertMessages.notNullParameter(); final Point2D<?, ?> closest = new InnerComputationPoint2afp(); findsClosestFarthestPointsPointOrientedRectangle( pt.getX(), pt.getY(), getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), closest, null); return closest.getDistanceL1(pt); } @Pure @Override default double getDistanceLinf(Point2D<?, ?> pt) { assert pt != null : AssertMessages.notNullParameter(); final Point2D<?, ?> closest = new InnerComputationPoint2afp(); findsClosestFarthestPointsPointOrientedRectangle( pt.getX(), pt.getY(), getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), closest, null); return closest.getDistanceLinf(pt); } @Override default void translate(double dx, double dy) { setCenter(getCenterX() + dx, getCenterY() + dy); } @Pure @Override default boolean contains(double x, double y) { return containsOrientedRectanglePoint( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), x, y); } @Pure @Override default boolean contains(Rectangle2afp<?, ?, ?, ?, ?, ?> rectangle) { assert rectangle != null : AssertMessages.notNullParameter(); return containsOrientedRectangleRectangle( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), rectangle.getMinX(), rectangle.getMinY(), rectangle.getWidth(), rectangle.getHeight()); } @Pure @Override default boolean intersects(Circle2afp<?, ?, ?, ?, ?, ?> circle) { assert circle != null : AssertMessages.notNullParameter(); return intersectsOrientedRectangleCircle( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), circle.getX(), circle.getY(), circle.getRadius()); } @Pure @Override default boolean intersects(Ellipse2afp<?, ?, ?, ?, ?, ?> ellipse) { assert ellipse != null : AssertMessages.notNullParameter(); return intersectsOrientedRectangleEllipse( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), ellipse.getMinX(), ellipse.getMinY(), ellipse.getMaxX() - ellipse.getMinX(), ellipse.getMaxY() - ellipse.getMinY()); } @Pure @Override default boolean intersects(OrientedRectangle2afp<?, ?, ?, ?, ?, ?> orientedRectangle) { assert orientedRectangle != null : AssertMessages.notNullParameter(); return intersectsOrientedRectangleOrientedRectangle( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), orientedRectangle.getCenterX(), orientedRectangle.getCenterY(), orientedRectangle.getFirstAxisX(), orientedRectangle.getFirstAxisY(), orientedRectangle.getFirstAxisExtent(), orientedRectangle.getSecondAxisExtent()); } @Pure @Override default boolean intersects(Parallelogram2afp<?, ?, ?, ?, ?, ?> parallelogram) { assert parallelogram != null : AssertMessages.notNullParameter(); return Parallelogram2afp.intersectsParallelogramParallelogram( parallelogram.getCenterX(), parallelogram.getCenterY(), parallelogram.getFirstAxisX(), parallelogram.getFirstAxisY(), parallelogram.getFirstAxisExtent(), parallelogram.getSecondAxisX(), parallelogram.getSecondAxisY(), parallelogram.getSecondAxisExtent(), getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisX(), getSecondAxisY(), getSecondAxisExtent()); } @Pure @Override default boolean intersects(Rectangle2afp<?, ?, ?, ?, ?, ?> rectangle) { assert rectangle != null : AssertMessages.notNullParameter(); return intersectsOrientedRectangleRectangle( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), rectangle.getMinX(), rectangle.getMinY(), rectangle.getWidth(), rectangle.getHeight()); } @Pure @Override default boolean intersects(RoundRectangle2afp<?, ?, ?, ?, ?, ?> roundRectangle) { assert roundRectangle != null : AssertMessages.notNullParameter(); return roundRectangle.intersects(this); } @Pure @Override default boolean intersects(Segment2afp<?, ?, ?, ?, ?, ?> segment) { assert segment != null : AssertMessages.notNullParameter(); return intersectsOrientedRectangleSegment( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), segment.getX1(), segment.getY1(), segment.getX2(), segment.getY2()); } @Pure @Override default boolean intersects(Triangle2afp<?, ?, ?, ?, ?, ?> triangle) { assert triangle != null : AssertMessages.notNullParameter(); return intersectsOrientedRectangleTriangle( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), triangle.getX1(), triangle.getY1(), triangle.getX2(), triangle.getY2(), triangle.getX3(), triangle.getY3()); } @Pure @Override default boolean intersects(PathIterator2afp<?> iterator) { assert iterator != null : AssertMessages.notNullParameter(); return intersectsOrientedRectanglePathIterator( getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), iterator); } @Pure @Override default boolean intersects(MultiShape2afp<?, ?, ?, ?, ?, ?, ?> multishape) { assert multishape != null : AssertMessages.notNullParameter(); return multishape.intersects(this); } @Pure @Override default PathIterator2afp<IE> getPathIterator(Transform2D transform) { if (transform == null || transform.isIdentity()) { return new OrientedRectanglePathIterator<>(this); } return new TransformedOrientedRectanglePathIterator<>(this, transform); } @Pure @Override default void toBoundingBox(B box) { final Point2D<?, ?> minCorner = new InnerComputationPoint2afp(getCenterX(), getCenterY()); final Point2D<?, ?> maxCorner = new InnerComputationPoint2afp(getCenterX(), getCenterY()); final double srx = getFirstAxisX() * getFirstAxisExtent(); final double sry = getFirstAxisY() * getFirstAxisExtent(); final double ssx = getSecondAxisX() * getSecondAxisExtent(); final double ssy = getSecondAxisY() * getSecondAxisExtent(); if (getFirstAxisX() >= 0.) { if (getFirstAxisY() >= 0.) { minCorner.add(-srx + ssx, -sry - ssy); maxCorner.sub(-srx + ssx, -sry - ssy); } else { minCorner.add(-srx - ssx, sry - ssy); maxCorner.sub(-srx - ssx, sry - ssy); } } else { if (getFirstAxisY() >= 0.) { minCorner.add(srx + ssx, -sry + ssy); maxCorner.sub(srx + ssx, -sry + ssy); } else { minCorner.add(srx - ssx, sry + ssy); maxCorner.sub(srx - ssx, sry + ssy); } } box.setFromCorners(minCorner, maxCorner); } @Pure @Override default P getClosestPointTo(Point2D<?, ?> pt) { assert pt != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); findsClosestFarthestPointsPointOrientedRectangle( pt.getX(), pt.getY(), getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), point, null); return point; } @Override default P getClosestPointTo(Circle2afp<?, ?, ?, ?, ?, ?> circle) { assert circle != null : AssertMessages.notNullParameter(); return getClosestPointTo(circle.getCenter()); } @Override @Unefficient default P getClosestPointTo(Ellipse2afp<?, ?, ?, ?, ?, ?> ellipse) { assert ellipse != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), ellipse.getPathIterator(), point); return point; } @Override @Unefficient default P getClosestPointTo(Rectangle2afp<?, ?, ?, ?, ?, ?> rectangle) { assert rectangle != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), rectangle.getPathIterator(), point); return point; } @Override @Unefficient default P getClosestPointTo(Segment2afp<?, ?, ?, ?, ?, ?> segment) { assert segment != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), segment.getPathIterator(), point); return point; } @Override @Unefficient default P getClosestPointTo(Triangle2afp<?, ?, ?, ?, ?, ?> triangle) { assert triangle != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), triangle.getPathIterator(), point); return point; } @Override @Unefficient default P getClosestPointTo(OrientedRectangle2afp<?, ?, ?, ?, ?, ?> orientedRectangle) { assert orientedRectangle != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), orientedRectangle.getPathIterator(), point); return point; } @Override @Unefficient default P getClosestPointTo(Parallelogram2afp<?, ?, ?, ?, ?, ?> parallelogram) { assert parallelogram != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), parallelogram.getPathIterator(), point); return point; } @Override @Unefficient default P getClosestPointTo(RoundRectangle2afp<?, ?, ?, ?, ?, ?> roundRectangle) { assert roundRectangle != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), roundRectangle.getPathIterator(), point); return point; } @Override @Unefficient default P getClosestPointTo(Path2afp<?, ?, ?, ?, ?, ?> path) { assert path != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); Path2afp.findsClosestPointPathIteratorPathIterator(getPathIterator(), path.getPathIterator(), point); return point; } @Pure @Override default P getFarthestPointTo(Point2D<?, ?> pt) { assert pt != null : AssertMessages.notNullParameter(); final P point = getGeomFactory().newPoint(); findsClosestFarthestPointsPointOrientedRectangle( pt.getX(), pt.getY(), getCenterX(), getCenterY(), getFirstAxisX(), getFirstAxisY(), getFirstAxisExtent(), getSecondAxisExtent(), null, point); return point; } @Override default void rotate(double angle) { final Vector2D<?, ?> axis1 = getFirstAxis(); final Vector2D<?, ?> newAxis = new InnerComputationVector2afp(); newAxis.turn(angle, axis1); setFirstAxis(newAxis.getX(), newAxis.getY()); } /** Abstract iterator on the path elements of the oriented rectangle. * * @param <T> the type of the path elements. * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ abstract class AbstractOrientedRectanglePathIterator<T extends PathElement2afp> implements PathIterator2afp<T> { /** Number of path elements. */ protected static final int ELEMENT_COUNT = 4; /** The iterated shape. */ protected final OrientedRectangle2afp<?, ?, T, ?, ?, ?> rectangle; /** * @param rectangle the iterated rectangle. */ public AbstractOrientedRectanglePathIterator(OrientedRectangle2afp<?, ?, T, ?, ?, ?> rectangle) { this.rectangle = rectangle; } @Override public GeomFactory2afp<T, ?, ?, ?> getGeomFactory() { return this.rectangle.getGeomFactory(); } @Override public void remove() { throw new UnsupportedOperationException(); } @Pure @Override public PathWindingRule getWindingRule() { return PathWindingRule.NON_ZERO; } @Pure @Override public boolean isPolyline() { return false; } @Pure @Override public boolean isCurved() { return false; } @Pure @Override public boolean isPolygon() { return true; } @Pure @Override public boolean isMultiParts() { return false; } } /** Iterator on the path elements of an oriented rectangle. * * @param <T> the type of the path elements. * @author $Author: mgrolleau$ * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ * @since 13.0 */ class OrientedRectanglePathIterator<T extends PathElement2afp> extends AbstractOrientedRectanglePathIterator<T> { private double x; private double y; private Vector2D<?, ?> raxis; private Vector2D<?, ?> saxis; private int index; private double moveX; private double moveY; private double lastX; private double lastY; /** * @param rectangle the oriented rectangle to iterate on. */ public OrientedRectanglePathIterator(OrientedRectangle2afp<?, ?, T, ?, ?, ?> rectangle) { super(rectangle); if (rectangle.isEmpty()) { this.index = ELEMENT_COUNT; } else { this.raxis = new InnerComputationVector2afp(rectangle.getFirstAxisX(), rectangle.getFirstAxisY()); this.saxis = new InnerComputationVector2afp(rectangle.getSecondAxisX(), rectangle.getSecondAxisY()); this.raxis.scale(rectangle.getFirstAxisExtent()); this.saxis.scale(rectangle.getSecondAxisExtent()); this.x = rectangle.getCenterX(); this.y = rectangle.getCenterY(); this.index = -1; } } @Override public PathIterator2afp<T> restartIterations() { return new OrientedRectanglePathIterator<>(this.rectangle); } @Pure @Override public boolean hasNext() { return this.index < ELEMENT_COUNT; } @Override public T next() { final int idx = this.index; ++this.index; if (idx < 0) { this.moveX = this.x + this.raxis.getX() + this.saxis.getX(); this.moveY = this.y + this.raxis.getY() + this.saxis.getY(); this.lastX = this.moveX; this.lastY = this.moveY; return getGeomFactory().newMovePathElement(this.moveX, this.moveY); } final double lx = this.lastX; final double ly = this.lastY; switch (idx) { case 0: this.lastX = this.x - this.raxis.getX() + this.saxis.getX(); this.lastY = this.y - this.raxis.getY() + this.saxis.getY(); return getGeomFactory().newLinePathElement(lx, ly, this.lastX, this.lastY); case 1: this.lastX = this.x - this.raxis.getX() - this.saxis.getX(); this.lastY = this.y - this.raxis.getY() - this.saxis.getY(); return getGeomFactory().newLinePathElement(lx, ly, this.lastX, this.lastY); case 2: this.lastX = this.x + this.raxis.getX() - this.saxis.getX(); this.lastY = this.y + this.raxis.getY() - this.saxis.getY(); return getGeomFactory().newLinePathElement(lx, ly, this.lastX, this.lastY); case 3: return getGeomFactory().newClosePathElement( this.lastX, this.lastY, this.moveX, this.moveY); default: throw new NoSuchElementException(); } } } /** Iterator on the path elements of a transformed oriented rectangle. * * @param <T> the type of the path elements. * @author $Author: mgrolleau$ * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ class TransformedOrientedRectanglePathIterator<T extends PathElement2afp> extends AbstractOrientedRectanglePathIterator<T> { private final Transform2D transform; private double x; private double y; private Vector2D<?, ?> raxis; private Vector2D<?, ?> saxis; private int index; private Point2D<?, ?> move; private Point2D<?, ?> last; /** * @param rectangle the oriented rectangle to iterate on. * @param transform the transformation to apply. */ public TransformedOrientedRectanglePathIterator(OrientedRectangle2afp<?, ?, T, ?, ?, ?> rectangle, Transform2D transform) { super(rectangle); assert transform != null : AssertMessages.notNullParameter(1); this.transform = transform; if (rectangle.isEmpty()) { this.index = ELEMENT_COUNT; } else { this.move = getGeomFactory().newPoint(); this.last = getGeomFactory().newPoint(); this.raxis = new InnerComputationVector2afp(rectangle.getFirstAxisX(), rectangle.getFirstAxisY()); this.saxis = new InnerComputationVector2afp(rectangle.getSecondAxisX(), rectangle.getSecondAxisY()); this.raxis.scale(rectangle.getFirstAxisExtent()); this.saxis.scale(rectangle.getSecondAxisExtent()); this.x = rectangle.getCenterX(); this.y = rectangle.getCenterY(); this.index = -1; } } @Override public PathIterator2afp<T> restartIterations() { return new TransformedOrientedRectanglePathIterator<>(this.rectangle, this.transform); } @Pure @Override public boolean hasNext() { return this.index < ELEMENT_COUNT; } @Override public T next() { final int idx = this.index; ++this.index; if (idx < 0) { this.move.set( this.x + this.raxis.getX() + this.saxis.getX(), this.y + this.raxis.getY() + this.saxis.getY()); this.transform.transform(this.move); this.last.set(this.move); return getGeomFactory().newMovePathElement(this.move.getX(), this.move.getY()); } final double lx = this.last.getX(); final double ly = this.last.getY(); switch (idx) { case 0: this.last.set( this.x - this.raxis.getX() + this.saxis.getX(), this.y - this.raxis.getY() + this.saxis.getY()); this.transform.transform(this.last); return getGeomFactory().newLinePathElement(lx, ly, this.last.getX(), this.last.getY()); case 1: this.last.set( this.x - this.raxis.getX() - this.saxis.getX(), this.y - this.raxis.getY() - this.saxis.getY()); this.transform.transform(this.last); return getGeomFactory().newLinePathElement(lx, ly, this.last.getX(), this.last.getY()); case 2: this.last.set( this.x + this.raxis.getX() - this.saxis.getX(), this.y + this.raxis.getY() - this.saxis.getY()); this.transform.transform(this.last); return getGeomFactory().newLinePathElement(lx, ly, this.last.getX(), this.last.getY()); case 3: return getGeomFactory().newClosePathElement( this.last.getX(), this.last.getY(), this.move.getX(), this.move.getY()); default: throw new NoSuchElementException(); } } } /** An iterator that automatically transform and reply the path elements from the given iterator such that * the coordinates of the path elements are projected in the local coordinate system of the given oriented * box. * * @param <T> the type of the path elements. * @author $Author: sgalland$ * @author $Author: mgrolleau$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ * @since 13.0 */ class ProjectionToOrientedRectangleLocalCoordinateSystemPathIterator<T extends PathElement2afp> implements PathIterator2afp<T> { private final PathIterator2afp<T> iterator; private final double centerX; private final double centerY; private final double axisX1; private final double axisY1; /** * @param x the specified X coordinate of the rectangle center. * @param y the specified Y coordinate of the rectangle center. * @param axis1X the X coordinate of the first axis of the rectangle. * @param axis1Y the Y coordinate of the first axis of the rectangle. * @param iterator the iterator to transform. */ public ProjectionToOrientedRectangleLocalCoordinateSystemPathIterator( double x, double y, double axis1X, double axis1Y, PathIterator2afp<T> iterator) { this.iterator = iterator; this.centerX = x; this.centerY = y; this.axisX1 = axis1X; this.axisY1 = axis1Y; } @Override public PathIterator2afp<T> restartIterations() { return new ProjectionToOrientedRectangleLocalCoordinateSystemPathIterator<>( this.centerX, this.centerY, this.axisX1, this.axisY1, this.iterator.restartIterations()); } @Pure @Override public boolean hasNext() { return this.iterator.hasNext(); } @Override public T next() { final PathElement2afp elem = this.iterator.next(); switch (elem.getType()) { case CURVE_TO: return getCurvToFromNext(elem); case ARC_TO: return getArcToFromNext(elem); case LINE_TO: return getLineToFromNext(elem); case MOVE_TO: return getMoveToFromNext(elem); case QUAD_TO: return getQuadToFromNext(elem); case CLOSE: return getCloseFromNext(elem); default: break; } return null; } private T getMoveToFromNext(PathElement2afp elem) { return getGeomFactory().newMovePathElement( findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY)); } private T getCurvToFromNext(PathElement2afp elem) { return getGeomFactory().newCurvePathElement( findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getCtrlX1() - this.centerX, elem.getCtrlY1() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getCtrlX1() - this.centerX, elem.getCtrlY1() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getCtrlX2() - this.centerX, elem.getCtrlY2() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getCtrlX2() - this.centerX, elem.getCtrlY2() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY)); } private T getArcToFromNext(PathElement2afp elem) { return getGeomFactory().newArcPathElement( findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY), elem.getRadiusX(), elem.getRadiusY(), elem.getRotationX(), elem.getLargeArcFlag(), elem.getSweepFlag()); } private T getLineToFromNext(PathElement2afp elem) { return getGeomFactory().newLinePathElement( findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY)); } private T getQuadToFromNext(PathElement2afp elem) { return getGeomFactory().newCurvePathElement( findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getCtrlX1() - this.centerX, elem.getCtrlY1() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getCtrlX1() - this.centerX, elem.getCtrlY1() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY)); } private T getCloseFromNext(PathElement2afp elem) { return getGeomFactory().newClosePathElement( findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getFromX() - this.centerX, elem.getFromY() - this.centerY), findsVectorProjectionRAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY), findsVectorProjectionSAxisVector(this.axisX1, this.axisY1, elem.getToX() - this.centerX, elem.getToY() - this.centerY)); } @Override public void remove() { this.iterator.remove(); } @Pure @Override public PathWindingRule getWindingRule() { return this.iterator.getWindingRule(); } @Pure @Override public boolean isPolyline() { return this.iterator.isPolyline(); } @Pure @Override public boolean isCurved() { return this.iterator.isCurved(); } @Pure @Override public boolean isPolygon() { return this.iterator.isPolygon(); } @Pure @Override public boolean isMultiParts() { return this.iterator.isMultiParts(); } @Override public GeomFactory2afp<T, ?, ?, ?> getGeomFactory() { return this.iterator.getGeomFactory(); } } }