/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arakhne.afc.math.geometry.d2;
import java.util.Collection;
import org.eclipse.xtext.xbase.lib.Pure;
import org.arakhne.afc.math.geometry.PathElementType;
import org.arakhne.afc.math.geometry.PathWindingRule;
/** 2D Path.
*
* @param <ST> is the type of the general implementation.
* @param <IT> is the type of the implementation of this shape.
* @param <I> is the type of the iterator used to obtain the elements of the path.
* @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 Path2D<
ST extends Shape2D<?, ?, I, P, V, B>,
IT extends Path2D<?, ?, I, P, V, B>,
I extends PathIterator2D<?>,
P extends Point2D<? super P, ? super V>,
V extends Vector2D<? super V, ? super P>,
B extends Shape2D<?, ?, I, P, V, B>>
extends Shape2D<ST, IT, I, P, V, B> {
/** Replies the winding rule for the path.
*
* @return the winding rule for the path.
*/
@Pure
PathWindingRule getWindingRule();
/** Set the winding rule for the path.
*
* @param rule is the winding rule for the path.
*/
void setWindingRule(PathWindingRule rule);
/** Replies the path is composed only by
* one <code>MOVE_TO</code>, and a sequence of <code>LINE_TO</code>
* primitives.
*
* @return <code>true</code> if the path does not
* contain curve primitives, <code>false</code>
* otherwise.
*/
@Pure
boolean isPolyline();
/** Replies the path contains a curve..
*
* @return <code>true</code> if the path does not
* contain curve primitives, <code>false</code>
* otherwise.
*/
@Pure
boolean isCurved();
/** Replies the path has multiple parts, i.e. multiple <code>MOVE_TO</code> are inside.
* primitives.
*
* @return <code>true</code> if the path has multiple move-to primitive, <code>false</code>
* otherwise.
*/
@Pure
boolean isMultiParts();
/** Replies the path is composed only by
* one <code>MOVE_TO</code>, a sequence of <code>LINE_TO</code>
* or <code>QUAD_TO</code> or <code>CURVE_TO</code>,
* or <code>ARC_TO</code>, and a
* single <code>CLOSE</code> primitives.
*
* @return <code>true</code> if the path does not
* contain curve primitives, <code>false</code>
* otherwise.
*/
@Pure
boolean isPolygon();
/** Replies an iterator on the path elements.
*
* <p>Only {@link PathElementType#MOVE_TO},
* {@link PathElementType#LINE_TO}, and
* {@link PathElementType#CLOSE} types are returned by the iterator.
*
* <p>The amount of subdivision of the curved segments is controlled by the
* flatness parameter, which specifies the maximum distance that any point
* on the unflattened transformed curve can deviate from the returned
* flattened path segments. Note that a limit on the accuracy of the
* flattened path might be silently imposed, causing very small flattening
* parameters to be treated as larger values. This limit, if there is one,
* is defined by the particular implementation that is used.
*
* <p>The iterator for this class is not multi-threaded safe.
*
* @param flatness is the maximum distance that the line segments used to approximate
* the curved segments are allowed to deviate from any point on the original curve.
* @return an iterator on the path elements.
*/
@Pure
I getPathIterator(double flatness);
/**
* Adds a point to the path by moving to the specified
* coordinates specified in double precision.
*
* @param position the new position.
*/
void moveTo(Point2D<?, ?> position);
/**
* Adds a point to the path by drawing a straight line from the
* current coordinates to the new specified coordinates
* specified in double precision.
*
* @param to the end point
*/
void lineTo(Point2D<?, ?> to);
/**
* Adds a curved segment, defined by two new points, to the path by
* drawing a Quadratic curve that intersects both the current
* coordinates and the specified coordinates {@code (x2, y2)},
* using the specified point {@code (x1, y1)} as a quadratic
* parametric control point.
* All coordinates are specified in double precision.
*
* @param ctrl the quadratic control point
* @param to the final end point
*/
void quadTo(Point2D<?, ?> ctrl, Point2D<?, ?> to);
/**
* Adds a curved segment, defined by three new points, to the path by
* drawing a Bézier curve that intersects both the current
* coordinates and the specified coordinates {@code (x3, y3)},
* using the specified points {@code (x1, y1)} and {@code (x2, y2)} as
* Bézier control points.
* All coordinates are specified in double precision.
*
* @param ctrl1 the first Bézier control point
* @param ctrl2 the second Bézier control point
* @param to the final end point
*/
void curveTo(Point2D<?, ?> ctrl1, Point2D<?, ?> ctrl2, Point2D<?, ?> to);
/**
* Adds a section of an shallow ellipse to the current path.
* The ellipse from which a quadrant is taken is the ellipse that would be
* inscribed in a parallelogram defined by 3 points,
* The current point which is considered to be the midpoint of the edge
* leading into the corner of the ellipse where the ellipse grazes it,
* {@code (ctrlx, ctrly)} which is considered to be the location of the
* corner of the parallelogram in which the ellipse is inscribed,
* and {@code (tox, toy)} which is considered to be the midpoint of the
* edge leading away from the corner of the oval where the oval grazes it.
*
* <p><img alt="" src="./doc-files/arcto0.png">
*
* <p>Only the portion of the ellipse from {@code tfrom} to {@code tto}
* will be included where {@code 0f} represents the point where the
* ellipse grazes the leading edge, {@code 1f} represents the point where
* the oval grazes the trailing edge, and {@code 0.5f} represents the
* point on the oval closest to the control point.
* The two values must satisfy the relation
* {@code (0 <= tfrom <= tto <= 1)}.
*
* <p>If {@code tfrom} is not {@code 0f} then the caller would most likely
* want to use one of the arc {@code type} values that inserts a segment
* leading to the initial point.
* An initial {@link #moveTo(Point2D)} or {@link #lineTo(Point2D)} can be added to direct
* the path to the starting point of the ellipse section if
* {@link ArcType#MOVE_THEN_ARC} or
* {@link ArcType#LINE_THEN_ARC} are
* specified by the type argument.
* The {@code lineTo} path segment will only be added if the current point
* is not already at the indicated location to avoid spurious empty line
* segments.
* The type can be specified as
* {@link ArcType#ARC_ONLY} if the current point
* on the path is known to be at the starting point of the ellipse section.
*
* @param ctrl the control point, i.e. the corner of the parallelogram in which the ellipse is inscribed.
* @param to the target point.
* @param tfrom the fraction of the ellipse section where the curve should start.
* @param tto the fraction of the ellipse section where the curve should end
* @param type the specification of what additional path segments should
* be appended to lead the current path to the starting point.
*/
void arcTo(Point2D<?, ?> ctrl, Point2D<?, ?> to, double tfrom, double tto, ArcType type);
/**
* Adds a section of an shallow ellipse to the current path.
*
* <p>This function is equivalent to:<pre><code>
* this.arcTo(ctrl, to, 0.0, 1.0, ArcType.ARCONLY);
* </code></pre>
*
* @param ctrl the control point, i.e. the corner of the parallelogram in which the ellipse is inscribed.
* @param to the target point.
*/
default void arcTo(Point2D<?, ?> ctrl, Point2D<?, ?> to) {
arcTo(ctrl, to, 0., 1., ArcType.ARC_ONLY);
}
/**
* Adds a section of an shallow ellipse to the current path.
* The ellipse from which the portions are extracted follows the rules:
* <ul>
* <li>The ellipse will have its X axis tilted from horizontal by the
* angle {@code xAxisRotation} specified in radians.</li>
* <li>The ellipse will have the X and Y radii (viewed from its tilted
* coordinate system) specified by {@code radiusx} and {@code radiusy}
* unless that ellipse is too small to bridge the gap from the current
* point to the specified destination point in which case a larger
* ellipse with the same ratio of dimensions will be substituted instead.</li>
* <li>The ellipse may slide perpendicular to the direction from the
* current point to the specified destination point so that it just
* touches the two points.
* The direction it slides (to the "left" or to the "right") will be
* chosen to meet the criteria specified by the two boolean flags as
* described below.
* Only one direction will allow the method to meet both criteria.</li>
* <li>If the {@code largeArcFlag} is true, then the ellipse will sweep
* the longer way around the ellipse that meets these criteria.</li>
* <li>If the {@code sweepFlag} is true, then the ellipse will sweep
* clockwise around the ellipse that meets these criteria.</li>
* </ul>
*
* <p><img alt="" src="./doc-files/arcto1.png">
*
* <p>The method will do nothing if the destination point is the same as
* the current point.
* The method will draw a simple line segment to the destination point
* if either of the two radii are zero.
*
* @param to the target point.
* @param radii the X and Y radii of the tilted ellipse.
* @param xAxisRotation the angle of tilt of the ellipse.
* @param largeArcFlag <code>true</code> iff the path will sweep the long way around the ellipse.
* @param sweepFlag <code>true</code> iff the path will sweep clockwise around the ellipse.
* @see "http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands"
*/
void arcTo(Point2D<?, ?> to, Vector2D<?, ?> radii, double xAxisRotation, boolean largeArcFlag, boolean sweepFlag);
/**
* Closes the current subpath by drawing a straight line back to
* the coordinates of the last {@code moveTo}. If the path is already
* closed or if the previous coordinates are for a {@code moveTo}
* then this method has no effect.
*/
void closePath();
/** Replies the bounding box of all the points added in this path.
*
* <p>The replied bounding box includes the (invisible) control points.
*
* @return the bounding box with the control points.
* @see #toBoundingBox()
*/
B toBoundingBoxWithCtrlPoints();
/** Compute the bounding box of all the points added in this path.
*
* <p>The replied bounding box includes the (invisible) control points.
*
* @param box is the rectangle to set with the bounds.
* @see #toBoundingBox()
*/
void toBoundingBoxWithCtrlPoints(B box);
/** Replies the coordinates of this path in an array of
* integer numbers.
*
* @return the coordinates.
*/
@Pure
default int[] toIntArray() {
return toIntArray(null);
}
/** Replies the coordinates of this path in an array of
* integer numbers.
*
* @param transform is the transformation to apply to all the coordinates.
* @return the coordinates.
*/
@Pure
int[] toIntArray(Transform2D transform);
/** Replies the coordinates of this path in an array of
* single precision floating-point numbers.
*
* @return the coordinates.
*/
@Pure
default float[] toFloatArray() {
return toFloatArray(null);
}
/** Replies the coordinates of this path in an array of
* single precision floating-point numbers.
*
* @param transform is the transformation to apply to all the coordinates.
* @return the coordinates.
*/
@Pure
float[] toFloatArray(Transform2D transform);
/** Replies the coordinates of this path in an array of
* double precision floating-point numbers.
*
* @return the coordinates.
*/
@Pure
default double[] toDoubleArray() {
return toDoubleArray(null);
}
/** Replies the coordinates of this path in an array of
* double precision floating-point numbers.
*
* @param transform is the transformation to apply to all the coordinates.
* @return the coordinates.
*/
@Pure
double[] toDoubleArray(Transform2D transform);
/** Replies the points of this path in an array.
*
* @return the points.
*/
@Pure
default P[] toPointArray() {
return toPointArray(null);
}
/** Replies the points of this path in an array.
*
* @param transform is the transformation to apply to all the points.
* @return the points.
*/
@Pure
P[] toPointArray(Transform2D transform);
/** Replies the collection that is contains all the points of the path.
*
* @return the point collection.
*/
@Pure
Collection<P> toCollection();
/** Replies the point at the given index.
* The index is in [0;{@link #size()}).
*
* @param index the index.
* @return the point at the given index.
*/
@Pure
P getPointAt(int index);
/** Replies the last point in the path.
*
* @return the last point.
*/
@Pure
P getCurrentPoint();
/** Replies the number of points in the path.
*
* @return the number of points in the path.
*/
@Pure
int size();
/** Replies the number of path elements in this path.
*
* @return the number of path elements.
* @see #getPathElementTypeAt(int)
*/
@Pure
int getPathElementCount();
/** Replies the type of the path element at the given position in this path.
*
* @param index the index of the path element.
* @return the type of the path element.
* @see #getPathElementCount()
*/
@Pure
PathElementType getPathElementTypeAt(int index);
/** Replies the total length of the path.
*
* @return the length of the path.
*/
@Pure
default double getLength() {
return Math.sqrt(getLengthSquared());
}
/** Replies the total squared length of the path.
*
* @return the length of the path.
*/
@Pure
double getLengthSquared();
/** Remove the last action.
*/
void removeLast();
/** Change the coordinates of the last inserted point.
*
* @param point the point.
*/
void setLastPoint(Point2D<?, ?> point);
/** Replies if the given points exists in the coordinates of this path.
*
* @param point the point.
* @return <code>true</code> if the point is a control point of the path.
*/
@Pure
boolean containsControlPoint(Point2D<?, ?> point);
/** Type of drawing to used when drawing an arc.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 13.0
*/
enum ArcType {
/** Draw only the ellipse arc.
*/
ARC_ONLY,
/** Move to and draw the ellipse arc.
*/
MOVE_THEN_ARC,
/** Draw a line to and the ellipse arc.
*/
LINE_THEN_ARC
}
}