/*
* $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 org.eclipse.xtext.xbase.lib.Pure;
import org.arakhne.afc.math.MathConstants;
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.Shape2D;
import org.arakhne.afc.math.geometry.d2.Transform2D;
import org.arakhne.afc.math.geometry.d2.Vector2D;
import org.arakhne.afc.math.geometry.d2.ai.Rectangle2ai;
import org.arakhne.afc.vmutil.asserts.AssertMessages;
/** 2D shape with 2D floating coordinates.
*
* @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$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 13.0
*/
public interface Shape2afp<
ST extends Shape2afp<?, ?, IE, P, V, B>,
IT extends Shape2afp<?, ?, 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 Shape2D<ST, IT, PathIterator2afp<IE>, P, V, B> {
@Pure
@Override
default boolean contains(Point2D<?, ?> pt) {
assert pt != null : AssertMessages.notNullParameter();
return contains(pt.getX(), pt.getY());
}
@Pure
@Unefficient
@Override
default boolean contains(Shape2D<?, ?, ?, ?, ?, ?> shape) {
assert shape != null : AssertMessages.notNullParameter();
if (isEmpty()) {
return false;
}
if (shape instanceof Rectangle2afp) {
return contains((Rectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
final PathIterator2afp<?> iterator = getPathIterator();
final int crossings;
if (shape instanceof Circle2afp) {
final Circle2afp<?, ?, ?, ?, ?, ?> circle = (Circle2afp<?, ?, ?, ?, ?, ?>) shape;
crossings = Path2afp.calculatesCrossingsPathIteratorCircleShadow(
0, iterator,
circle.getCenterX(), circle.getCenterY(), circle.getRadius(),
CrossingComputationType.STANDARD);
} else if (shape instanceof Ellipse2afp) {
final Ellipse2afp<?, ?, ?, ?, ?, ?> ellipse = (Ellipse2afp<?, ?, ?, ?, ?, ?>) shape;
crossings = Path2afp.calculatesCrossingsPathIteratorEllipseShadow(
0, iterator,
ellipse.getMinX(), ellipse.getMinY(), ellipse.getWidth(), ellipse.getHeight(),
CrossingComputationType.STANDARD);
} else if (shape instanceof RoundRectangle2afp) {
final RoundRectangle2afp<?, ?, ?, ?, ?, ?> roundRectangle = (RoundRectangle2afp<?, ?, ?, ?, ?, ?>) shape;
crossings = Path2afp.calculatesCrossingsPathIteratorRoundRectangleShadow(
0, iterator,
roundRectangle.getMinX(), roundRectangle.getMinY(),
roundRectangle.getMaxX(), roundRectangle.getMaxY(),
roundRectangle.getArcWidth(), roundRectangle.getArcHeight(),
CrossingComputationType.STANDARD);
} else if (shape instanceof Segment2afp) {
final Segment2afp<?, ?, ?, ?, ?, ?> segment = (Segment2afp<?, ?, ?, ?, ?, ?>) shape;
crossings = Path2afp.calculatesCrossingsPathIteratorSegmentShadow(
0, iterator,
segment.getX1(), segment.getY1(),
segment.getX2(), segment.getY2(),
CrossingComputationType.STANDARD);
} else if (shape instanceof Triangle2afp) {
final Triangle2afp<?, ?, ?, ?, ?, ?> triangle = (Triangle2afp<?, ?, ?, ?, ?, ?>) shape;
crossings = Path2afp.calculatesCrossingsPathIteratorTriangleShadow(
0, iterator,
triangle.getX1(), triangle.getY1(),
triangle.getX2(), triangle.getY2(),
triangle.getX3(), triangle.getY3(),
CrossingComputationType.STANDARD);
} else if (!iterator.isPolygon()) {
// Only a polygon can contain another shape.
return false;
} else {
final double minX;
final double minY;
final double maxX;
final double maxY;
final Shape2D<?, ?, ?, ?, ?, ?> originalBounds = shape.toBoundingBox();
if (originalBounds instanceof Rectangle2afp) {
final Rectangle2afp<?, ?, ?, ?, ?, ?> rect = (Rectangle2afp<?, ?, ?, ?, ?, ?>) originalBounds;
minX = rect.getMinX();
minY = rect.getMinY();
maxX = rect.getMaxX();
maxY = rect.getMaxY();
} else {
assert originalBounds instanceof Rectangle2ai;
final Rectangle2ai<?, ?, ?, ?, ?, ?> rect = (Rectangle2ai<?, ?, ?, ?, ?, ?>) originalBounds;
minX = rect.getMinX();
minY = rect.getMinY();
maxX = rect.getMaxX();
maxY = rect.getMaxY();
}
final PathIterator2afp<?> shapePathIterator = iterator.getGeomFactory().convert(shape.getPathIterator());
crossings = Path2afp.calculatesCrossingsPathIteratorPathShadow(
0, iterator,
new BasicPathShadow2afp(shapePathIterator, minX, minY, maxX, maxY),
CrossingComputationType.STANDARD);
}
final int mask = iterator.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 2;
return crossings != MathConstants.SHAPE_INTERSECTS
&& (crossings & mask) != 0;
}
/** Replies if the given rectangle is inside this shape.
*
* @param rectangle the rectangle.
* @return <code>true</code> if the given rectangle is inside this
* shape, otherwise <code>false</code>.
*/
@Pure
boolean contains(Rectangle2afp<?, ?, ?, ?, ?, ?> rectangle);
/** Replies if the given point is inside this shape.
*
* @param x x coordinate of the point to test.
* @param y y coordinate of the point to test.
* @return <code>true</code> if the given point is inside this
* shape, otherwise <code>false</code>.
*/
@Pure
boolean contains(double x, double y);
/** Translate the shape.
*
* @param dx x translation.
* @param dy y translation.
*/
void translate(double dx, double dy);
@Pure
@Override
default void translate(Vector2D<?, ?> vector) {
assert vector != null : AssertMessages.notNullParameter();
translate(vector.getX(), vector.getY());
}
@Pure
@Unefficient
@Override
@SuppressWarnings({"checkstyle:returncount", "checkstyle:npathcomplexity"})
default boolean intersects(Shape2D<?, ?, ?, ?, ?, ?> shape) {
if (shape instanceof Circle2afp) {
return intersects((Circle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Ellipse2afp) {
return intersects((Ellipse2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof MultiShape2afp) {
return intersects((MultiShape2afp<?, ?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof OrientedRectangle2afp) {
return intersects((OrientedRectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Parallelogram2afp) {
return intersects((Parallelogram2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Path2afp) {
return intersects((Path2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof PathIterator2afp) {
return intersects((PathIterator2afp<?>) shape);
}
if (shape instanceof Rectangle2afp) {
return intersects((Rectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof RoundRectangle2afp) {
return intersects((RoundRectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Segment2afp) {
return intersects((Segment2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Triangle2afp) {
return intersects((Triangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
return intersects(getPathIterator());
}
/** Replies if this shape is intersecting the given ellipse.
*
* @param ellipse the ellipse.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(Ellipse2afp<?, ?, ?, ?, ?, ?> ellipse);
/** Replies if this shape is intersecting the given circle.
*
* @param circle the circle.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(Circle2afp<?, ?, ?, ?, ?, ?> circle);
/** Replies if this shape is intersecting the given rectangle.
*
* @param rectangle the rectangle.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(Rectangle2afp<?, ?, ?, ?, ?, ?> rectangle);
/** Replies if this shape is intersecting the given line.
*
* @param segment the segment.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(Segment2afp<?, ?, ?, ?, ?, ?> segment);
/** Replies if this shape is intersecting the given triangle.
*
* @param triangle the triangle.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(Triangle2afp<?, ?, ?, ?, ?, ?> triangle);
/** Replies if this shape is intersecting the given path.
*
* @param path the other path.
* @return <code>true</code> if this shape is intersecting the given path;
* <code>false</code> if there is no intersection.
*/
@Pure
default boolean intersects(Path2afp<?, ?, ?, ?, ?, ?> path) {
assert path != null : AssertMessages.notNullParameter();
return intersects(path.getPathIterator());
}
/** Replies if this shape is intersecting the shape representing the given path iterator.
*
* @param iterator the path iterator.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(PathIterator2afp<?> iterator);
/** Replies if this shape is intersecting the given rectangle.
*
* @param orientedRectangle the oriented rectangle.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(OrientedRectangle2afp<?, ?, ?, ?, ?, ?> orientedRectangle);
/** Replies if this shape is intersecting the given parallelogram.
*
* @param parallelogram the parallelogram.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(Parallelogram2afp<?, ?, ?, ?, ?, ?> parallelogram);
/** Replies if this shape is intersecting the given rectangle.
*
* @param roundRectangle the round rectangle.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(RoundRectangle2afp<?, ?, ?, ?, ?, ?> roundRectangle);
/** Replies if this shape is intersecting the given multishape.
*
* @param multishape the multishape.
* @return <code>true</code> if this shape is intersecting the given shape;
* <code>false</code> if there is no intersection.
*/
@Pure
boolean intersects(MultiShape2afp<?, ?, ?, ?, ?, ?, ?> multishape);
@Pure
@Unefficient
@Override
@SuppressWarnings({"checkstyle:returncount", "checkstyle:npathcomplexity"})
default double getDistanceSquared(Shape2D<?, ?, ?, ?, ?, ?> shape) {
if (shape instanceof Circle2afp) {
return getDistanceSquared((Circle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Ellipse2afp) {
return getDistanceSquared((Ellipse2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof MultiShape2afp) {
return getDistanceSquared((MultiShape2afp<?, ?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof OrientedRectangle2afp) {
return getDistanceSquared((OrientedRectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Parallelogram2afp) {
return getDistanceSquared((Parallelogram2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Path2afp) {
return getDistanceSquared((Path2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Rectangle2afp) {
return getDistanceSquared((Rectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof RoundRectangle2afp) {
return getDistanceSquared((RoundRectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Segment2afp) {
return getDistanceSquared((Segment2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Triangle2afp) {
return getDistanceSquared((Triangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
throw new IllegalArgumentException();
}
/** Replies the minimum distance between this shape and the given ellipse.
*
* @param ellipse the ellipse.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(Ellipse2afp<?, ?, ?, ?, ?, ?> ellipse) {
assert ellipse != null : AssertMessages.notNullParameter();
return ellipse.getDistanceSquared(getClosestPointTo(ellipse));
}
/** Replies the minimum distance between this shape and the given circle.
*
* @param circle the circle.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(Circle2afp<?, ?, ?, ?, ?, ?> circle) {
assert circle != null : AssertMessages.notNullParameter();
return circle.getDistanceSquared(getClosestPointTo(circle));
}
/** Replies the minimum distance between this shape and the given rectangle.
*
* @param rectangle the rectangle.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(Rectangle2afp<?, ?, ?, ?, ?, ?> rectangle) {
assert rectangle != null : AssertMessages.notNullParameter();
return rectangle.getDistanceSquared(getClosestPointTo(rectangle));
}
/** Replies the minimum distance between this shape and the given segment.
*
* @param segment the segment.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(Segment2afp<?, ?, ?, ?, ?, ?> segment) {
assert segment != null : AssertMessages.notNullParameter();
return segment.getDistanceSquared(getClosestPointTo(segment));
}
/** Replies the minimum distance between this shape and the given triangle.
*
* @param triangle the triangle.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(Triangle2afp<?, ?, ?, ?, ?, ?> triangle) {
assert triangle != null : AssertMessages.notNullParameter();
return triangle.getDistanceSquared(getClosestPointTo(triangle));
}
/** Replies the minimum distance between this shape and the given path.
*
* @param path the path.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(Path2afp<?, ?, ?, ?, ?, ?> path) {
assert path != null : AssertMessages.notNullParameter();
return path.getDistanceSquared(getClosestPointTo(path));
}
/** Replies the minimum distance between this shape and the given oriented rectangle.
*
* @param orientedRectangle the oriented rectangle.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(OrientedRectangle2afp<?, ?, ?, ?, ?, ?> orientedRectangle) {
assert orientedRectangle != null : AssertMessages.notNullParameter();
return orientedRectangle.getDistanceSquared(getClosestPointTo(orientedRectangle));
}
/** Replies the minimum distance between this shape and the given parallelogram.
*
* @param parallelogram the parallelogram.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(Parallelogram2afp<?, ?, ?, ?, ?, ?> parallelogram) {
assert parallelogram != null : AssertMessages.notNullParameter();
return parallelogram.getDistanceSquared(getClosestPointTo(parallelogram));
}
/** Replies the minimum distance between this shape and the given round rectangle.
*
* @param roundRectangle the round rectangle.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(RoundRectangle2afp<?, ?, ?, ?, ?, ?> roundRectangle) {
assert roundRectangle != null : AssertMessages.notNullParameter();
return roundRectangle.getDistanceSquared(getClosestPointTo(roundRectangle));
}
/** Replies the minimum distance between this shape and the given multishape.
*
* @param multishape the multishape.
* @return the minimum distance between the two shapes.
*/
@Pure
default double getDistanceSquared(MultiShape2afp<?, ?, ?, ?, ?, ?, ?> multishape) {
assert multishape != null : AssertMessages.notNullParameter();
double minDist = Double.POSITIVE_INFINITY;
double dist;
for (final Shape2afp<?, ?, ?, ?, ?, ?> shape : multishape) {
dist = getDistanceSquared(shape);
if (dist < minDist) {
minDist = dist;
}
}
return minDist;
}
@Pure
@Unefficient
@Override
@SuppressWarnings({"checkstyle:returncount", "checkstyle:npathcomplexity"})
default P getClosestPointTo(Shape2D<?, ?, ?, ?, ?, ?> shape) {
if (shape instanceof Circle2afp) {
return getClosestPointTo((Circle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Ellipse2afp) {
return getClosestPointTo((Ellipse2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof MultiShape2afp) {
return getClosestPointTo((MultiShape2afp<?, ?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof OrientedRectangle2afp) {
return getClosestPointTo((OrientedRectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Parallelogram2afp) {
return getClosestPointTo((Parallelogram2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Path2afp) {
return getClosestPointTo((Path2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Rectangle2afp) {
return getClosestPointTo((Rectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof RoundRectangle2afp) {
return getClosestPointTo((RoundRectangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Segment2afp) {
return getClosestPointTo((Segment2afp<?, ?, ?, ?, ?, ?>) shape);
}
if (shape instanceof Triangle2afp) {
return getClosestPointTo((Triangle2afp<?, ?, ?, ?, ?, ?>) shape);
}
throw new IllegalArgumentException();
}
/** Replies the closest point on this shape to the given ellipse.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param ellipse the ellipse.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(Ellipse2afp<?, ?, ?, ?, ?, ?> ellipse);
/** Replies the closest point on this shape to the given circle.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param circle the circle.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
@Unefficient
P getClosestPointTo(Circle2afp<?, ?, ?, ?, ?, ?> circle);
/** Replies the closest point on this shape to the given rectangle.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param rectangle the rectangle.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(Rectangle2afp<?, ?, ?, ?, ?, ?> rectangle);
/** Replies the closest point on this shape to the given segment.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param segment the segment.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(Segment2afp<?, ?, ?, ?, ?, ?> segment);
/** Replies the closest point on this shape to the given triangle.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param triangle the triangle.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(Triangle2afp<?, ?, ?, ?, ?, ?> triangle);
/** Replies the closest point on this shape to the given oriented rectangle.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param orientedRectangle the oriented rectangle.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(OrientedRectangle2afp<?, ?, ?, ?, ?, ?> orientedRectangle);
/** Replies the closest point on this shape to the given parallelogram.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param parallelogram the parallelogram.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(Parallelogram2afp<?, ?, ?, ?, ?, ?> parallelogram);
/** Replies the closest point on this shape to the given round rectangle.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param roundRectangle the round rectangle.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(RoundRectangle2afp<?, ?, ?, ?, ?, ?> roundRectangle);
/** Replies the closest point on this shape to the given path.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param path the path.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
P getClosestPointTo(Path2afp<?, ?, ?, ?, ?, ?> path);
/** Replies the closest point on this shape to the given multishape.
*
* <p>If the two shapes are intersecting, the replied point is always at the intersection
* of the two shapes. This function does not enforce the meaning of the replied point
* in the case of shape intersection. In other words, this function is warranting that
* the reply point is the either the penetration point, nor a perimeter point, nor any point
* with a specific meaning.
*
* @param multishape the multishape.
* @return the closest point on the shape; or the point itself
* if it is inside the shape.
*/
@Pure
default P getClosestPointTo(MultiShape2afp<?, ?, ?, ?, ?, ?, ?> multishape) {
assert multishape != null : AssertMessages.notNullParameter();
Shape2afp<?, ?, ?, ?, ?, ?> closest = null;
double minDist = Double.POSITIVE_INFINITY;
double dist;
for (final Shape2afp<?, ?, ?, ?, ?, ?> shape : multishape) {
dist = getDistanceSquared(shape);
if (dist < minDist) {
minDist = dist;
closest = shape;
}
}
if (closest == null) {
return getGeomFactory().newPoint();
}
return getClosestPointTo(closest);
}
@Override
GeomFactory2afp<IE, P, V, B> getGeomFactory();
@Pure
@SuppressWarnings("unchecked")
@Override
default ST createTransformedShape(Transform2D transform) {
if (transform == null || transform.isIdentity()) {
return (ST) clone();
}
final PathIterator2afp<?> pi = getPathIterator(transform);
final GeomFactory2afp<IE, P, V, B> factory = getGeomFactory();
final Path2afp<?, ?, ?, P, V, ?> newPath = factory.newPath(pi.getWindingRule());
while (pi.hasNext()) {
final PathElement2afp e = pi.next();
switch (e.getType()) {
case MOVE_TO:
newPath.moveTo(e.getToX(), e.getToY());
break;
case LINE_TO:
newPath.lineTo(e.getToX(), e.getToY());
break;
case QUAD_TO:
newPath.quadTo(e.getCtrlX1(), e.getCtrlY1(), e.getToX(), e.getToY());
break;
case CURVE_TO:
newPath.curveTo(e.getCtrlX1(), e.getCtrlY1(), e.getCtrlX2(), e.getCtrlY2(), e.getToX(), e.getToY());
break;
case ARC_TO:
newPath.arcTo(e.getToX(), e.getToY(), e.getRadiusX(), e.getRadiusY(), e.getRotationX(),
e.getLargeArcFlag(), e.getSweepFlag());
break;
case CLOSE:
newPath.closePath();
break;
default:
}
}
return (ST) newPath;
}
@Override
default B toBoundingBox() {
final B box = getGeomFactory().newBox();
toBoundingBox(box);
return box;
}
}