aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java')
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java257
1 files changed, 256 insertions, 1 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
index 4bc1d0820..be5a1d1bf 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
@@ -37,6 +37,8 @@ import com.jogamp.graph.geom.Outline;
import com.jogamp.graph.geom.Triangle;
import com.jogamp.graph.geom.Vertex;
import com.jogamp.graph.geom.plane.AffineTransform;
+import com.jogamp.graph.geom.plane.Path2F;
+import com.jogamp.graph.geom.plane.Winding;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.VectorUtil;
import com.jogamp.opengl.math.geom.AABBox;
@@ -91,6 +93,7 @@ import com.jogamp.opengl.math.geom.AABBox;
* <ul>
* <li> The first vertex of any outline belonging to the shape should be on-curve</li>
* <li> Intersections between off-curved parts of the outline is not handled</li>
+ * <li> Outline shape winding shall be constructed counter clock wise ({@link Winding#CCW}).</li>
* </ul>
*
* @see Outline
@@ -342,6 +345,9 @@ public final class OutlineShape implements Comparable<OutlineShape> {
/**
* Adds a vertex to the last open outline to the shape's tail.
+ *
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* @param v the vertex to be added to the OutlineShape
*/
public final void addVertex(final Vertex v) {
@@ -356,6 +362,9 @@ public final class OutlineShape implements Comparable<OutlineShape> {
/**
* Adds a vertex to the last open outline to the shape at {@code position}
+ *
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* @param position index within the last open outline, at which the vertex will be added
* @param v the vertex to be added to the OutlineShape
*/
@@ -372,6 +381,8 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* Add a 2D {@link Vertex} to the last open outline to the shape's tail.
* The 2D vertex will be represented as Z=0.
*
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* @param x the x coordinate
* @param y the y coordniate
* @param onCurve flag if this vertex is on the final curve or defines a curved region
@@ -385,6 +396,8 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* Add a 2D {@link Vertex} to the last open outline to the shape at {@code position}.
* The 2D vertex will be represented as Z=0.
*
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* @param position index within the last open outline, at which the vertex will be added
* @param x the x coordinate
* @param y the y coordniate
@@ -397,6 +410,9 @@ public final class OutlineShape implements Comparable<OutlineShape> {
/**
* Add a 3D {@link Vertex} to the last open outline to the shape's tail.
+ *
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
@@ -410,6 +426,8 @@ public final class OutlineShape implements Comparable<OutlineShape> {
/**
* Add a 3D {@link Vertex} to the last open outline to the shape at {@code position}.
*
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* @param position index within the last open outline, at which the vertex will be added
* @param x the x coordinate
* @param y the y coordniate
@@ -424,6 +442,8 @@ public final class OutlineShape implements Comparable<OutlineShape> {
/**
* Add a vertex to the last open outline to the shape's tail.
*
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* The vertex is passed as a float array and its offset where its attributes are located.
* The attributes should be continuous (stride = 0).
* Attributes which value are not set (when length less than 3)
@@ -441,6 +461,8 @@ public final class OutlineShape implements Comparable<OutlineShape> {
/**
* Add a vertex to the last open outline to the shape at {@code position}.
*
+ * The constructed shape should be {@link Winding#CCW}.
+ *
* The vertex is passed as a float array and its offset where its attributes are located.
* The attributes should be continuous (stride = 0).
* Attributes which value are not set (when length less than 3)
@@ -467,12 +489,245 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* otherwise a clone of the last vertex will be prepended.
*/
public final void closeLastOutline(final boolean closeTail) {
- if( getLastOutline().setClosed(true) ) {
+ if( getLastOutline().setClosed( closeTail ) ) {
dirtyBits |= DIRTY_TRIANGLES | DIRTY_VERTICES;
}
}
/**
+ * Append the given path geometry to this outline shape.
+ *
+ * The given path geometry should be {@link Winding#CCW}.
+ *
+ * If the given path geometry is {@link Winding#CW}, use {@link #addPathRev(Path2F, boolean)}.
+ *
+ * @param path the {@link Path2F} to append to this outline shape, should be {@link Winding#CCW}.
+ * @param connect pass true to turn an initial moveTo segment into a lineTo segment to connect the new geometry to the existing path, otherwise pass false.
+ * @see Path2F#getWinding()
+ */
+ public void addPath(final Path2F path, final boolean connect) {
+ addPath(path.iterator(null), connect);
+ }
+
+ /**
+ * Add the given {@link Path2F.Iterator} to this outline shape.
+ *
+ * The given path geometry should be {@link Winding#CCW}.
+ *
+ * If the given path geometry is {@link Winding#CW}, use {@link #addPathRev(Path2F.Iterator, boolean).
+ *
+ * @param pathI the {@link Path2F.Iterator} to append to this outline shape, should be {@link Winding#CCW}.
+ * @param connect pass true to turn an initial moveTo segment into a lineTo segment to connect the new geometry to the existing path, otherwise pass false.
+ * @see Path2F.Iterator#getWinding()
+ */
+ public final void addPath(final Path2F.Iterator pathI, boolean connect) {
+ final float[] points = pathI.points();
+ while ( pathI.hasNext() ) {
+ final int idx = pathI.index();
+ final Path2F.SegmentType type = pathI.next();
+ switch(type) {
+ case MOVETO:
+ final Outline lo = this.getLastOutline();
+ final int lo_sz = lo.getVertexCount();
+ if ( 0 == lo_sz ) {
+ addVertex(points, idx, 2, true);
+ break;
+ } else if ( !connect ) {
+ closeLastOutline(false);
+ addEmptyOutline();
+ addVertex(points, idx, 2, true);
+ break;
+ }
+ {
+ // Skip if last vertex in last outline matching this point -> already connected.
+ final float[] llc = lo.getVertex(lo_sz-1).getCoord();
+ if( llc[0] == points[idx+0] &&
+ llc[1] == points[idx+1] ) {
+ break;
+ }
+ }
+ // fallthrough: MOVETO -> LINETO
+ case LINETO:
+ addVertex(points, idx, 2, true);
+ break;
+ case QUADTO:
+ addVertex(points, idx, 2, false);
+ addVertex(points, idx+2, 2, true);
+ break;
+ case CUBICTO:
+ addVertex(points, idx, 2, false);
+ addVertex(points, idx+2, 2, false);
+ addVertex(points, idx+4, 2, true);
+ break;
+ case CLOSE:
+ closeLastOutline(true);
+ addEmptyOutline();
+ break;
+ default:
+ throw new IllegalArgumentException("Unhandled Segment Type: "+type);
+ }
+ connect = false;
+ }
+ }
+
+ /**
+ * Append the given path geometry to this outline shape in reverse order.
+ *
+ * The given path geometry should be {@link Winding#CW}.
+ *
+ * If the given path geometry is {@link Winding#CCW}, use {@link #addPath(Path2F, boolean)}.
+ *
+ * @param path the {@link Path2F} to append to this outline shape, should be {@link Winding#CW}.
+ * @param connect pass true to turn an initial moveTo segment into a lineTo segment to connect the new geometry to the existing path, otherwise pass false.
+ */
+ public void addPathRev(final Path2F path, final boolean connect) {
+ addPathRev(path.iterator(null), connect);
+ }
+
+ /**
+ * Add the given {@link Path2F.Iterator} to this outline shape in reverse order.
+ *
+ * The given path geometry should be {@link Winding#CW}.
+ *
+ * If the given path geometry is {@link Winding#CCW}, use {@link #addPath(Path2F.Iterator, boolean).
+ *
+ * @param pathI the {@link Path2F.Iterator} to append to this outline shape, should be {@link Winding#CW}.
+ * @param connect pass true to turn an initial moveTo segment into a lineTo segment to connect the new geometry to the existing path, otherwise pass false.
+ */
+ public final void addPathRev(final Path2F.Iterator pathI, boolean connect) {
+ final float[] points = pathI.points();
+ while ( pathI.hasNext() ) {
+ final int idx = pathI.index();
+ final Path2F.SegmentType type = pathI.next();
+ switch(type) {
+ case MOVETO:
+ final Outline lo = this.getLastOutline();
+ final int lo_sz = lo.getVertexCount();
+ if ( 0 == lo_sz ) {
+ addVertex(0, points, idx, 2, true);
+ break;
+ } else if ( !connect ) {
+ closeLastOutline(false);
+ addEmptyOutline();
+ addVertex(0, points, idx, 2, true);
+ break;
+ }
+ {
+ // Skip if last vertex in last outline matching this point -> already connected.
+ final float[] llc = lo.getVertex(0).getCoord();
+ if( llc[0] == points[idx+0] &&
+ llc[1] == points[idx+1] ) {
+ break;
+ }
+ }
+ // fallthrough: MOVETO -> LINETO
+ case LINETO:
+ addVertex(0, points, idx, 2, true);
+ break;
+ case QUADTO:
+ addVertex(0, points, idx, 2, false);
+ addVertex(0, points, idx+2, 2, true);
+ break;
+ case CUBICTO:
+ addVertex(0, points, idx, 2, false);
+ addVertex(0, points, idx+2, 2, false);
+ addVertex(0, points, idx+4, 2, true);
+ break;
+ case CLOSE:
+ closeLastOutline(true);
+ addEmptyOutline();
+ break;
+ default:
+ throw new IllegalArgumentException("Unhandled Segment Type: "+type);
+ }
+ connect = false;
+ }
+ }
+
+ /**
+ * Start a new position for the next line segment at given point x/y (P1).
+ *
+ * The constructed shape should be {@link Winding#CCW}.
+ *
+ * @param x point (P1)
+ * @param y point (P1)
+ * @see Path2F#moveTo(float, float)
+ * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean)
+ */
+ public final void moveTo(final float x, final float y) {
+ if ( 0 == getLastOutline().getVertexCount() ) {
+ addVertex(x, y, true);
+ } else {
+ closeLastOutline(false);
+ addEmptyOutline();
+ addVertex(x, y, true);
+ }
+ }
+
+ /**
+ * Add a line segment, intersecting the last point and the given point x/y (P1).
+ *
+ * The constructed shape should be {@link Winding#CCW}.
+ *
+ * @param x final point (P1)
+ * @param y final point (P1)
+ * @see Path2F#lineTo(float, float)
+ * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean)
+ */
+ public final void lineTo(final float x, final float y) {
+ addVertex(x, y, true);
+ }
+
+ /**
+ * Add a quadratic curve segment, intersecting the last point and the second given point x2/y2 (P2).
+ *
+ * The constructed shape should be {@link Winding#CCW}.
+ *
+ * @param x1 quadratic parametric control point (P1)
+ * @param y1 quadratic parametric control point (P1)
+ * @param x2 final interpolated control point (P2)
+ * @param y2 final interpolated control point (P2)
+ * @see Path2F#quadTo(float, float, float, float)
+ * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean)
+ */
+ public final void quadTo(final float x1, final float y1, final float x2, final float y2) {
+ addVertex(x1, y1, false);
+ addVertex(x2, y2, true);
+ }
+
+ /**
+ * Add a cubic Bézier curve segment, intersecting the last point and the second given point x3/y3 (P3).
+ *
+ * The constructed shape should be {@link Winding#CCW}.
+ *
+ * @param x1 Bézier control point (P1)
+ * @param y1 Bézier control point (P1)
+ * @param x2 Bézier control point (P2)
+ * @param y2 Bézier control point (P2)
+ * @param x3 final interpolated control point (P3)
+ * @param y3 final interpolated control point (P3)
+ * @see Path2F#cubicTo(float, float, float, float, float, float)
+ * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean)
+ */
+ public final void cubicTo(final float x1, final float y1, final float x2, final float y2, final float x3, final float y3) {
+ addVertex(x1, y1, false);
+ addVertex(x2, y2, false);
+ addVertex(x3, y3, true);
+ }
+
+ /**
+ * Closes the current sub-path segment by drawing a straight line back to the coordinates of the last moveTo. If the path is already closed then this method has no effect.
+ * @see Path2F#closePath()
+ * @see #addPath(com.jogamp.graph.geom.plane.Path2F.Iterator, boolean)
+ */
+ public final void closePath() {
+ if ( 0 < getLastOutline().getVertexCount() ) {
+ closeLastOutline(true);
+ addEmptyOutline();
+ }
+ }
+
+ /**
* Return the outline's vertices state, {@link OutlineShape.VerticesState}
*/
public final VerticesState getOutlineState() {