diff options
Diffstat (limited to 'src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java')
-rwxr-xr-x | src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java | 283 |
1 files changed, 218 insertions, 65 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java index d0413b1e4..fa8494d4e 100755 --- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java +++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java @@ -30,6 +30,7 @@ package com.jogamp.graph.curve; import java.util.ArrayList;
import java.util.Collections;
+import com.jogamp.graph.geom.AABBox;
import com.jogamp.graph.geom.Outline;
import com.jogamp.graph.geom.Triangle;
import com.jogamp.graph.geom.Vertex;
@@ -91,12 +92,12 @@ import com.jogamp.graph.curve.tess.CDTriangulator2D; * @see Outline
* @see Region
*/
-public class OutlineShape {
+public class OutlineShape implements Comparable<OutlineShape> {
/**
- * Outline has original user state (vertices) until transformed.
+ * Outline's vertices have undefined state until transformed.
*/
public enum VerticesState {
- ORIGINAL(0), QUADRATIC_NURBS(1);
+ UNDEFINED(0), QUADRATIC_NURBS(1);
public final int state;
@@ -111,14 +112,19 @@ public class OutlineShape { /** The list of {@link Outline}s that are part of this
* outline shape.
*/
- private ArrayList<Outline> outlines = new ArrayList<Outline>(3);
+ private ArrayList<Outline> outlines;
+ private AABBox bbox;
+ private boolean dirtyBBox;
/** Create a new Outline based Shape
*/
public OutlineShape(Vertex.Factory<? extends Vertex> factory) {
- vertexFactory = factory;
- outlines.add(new Outline());
- outlineState = VerticesState.ORIGINAL;
+ this.vertexFactory = factory;
+ this.outlines = new ArrayList<Outline>(3);
+ this.outlines.add(new Outline());
+ this.outlineState = VerticesState.UNDEFINED;
+ this.bbox = new AABBox();
+ this.dirtyBBox = false;
}
/** Returns the associated vertex factory of this outline shape
@@ -126,6 +132,10 @@ public class OutlineShape { */
public final Vertex.Factory<? extends Vertex> vertexFactory() { return vertexFactory; }
+ public int getOutlineNumber() {
+ return outlines.size();
+ }
+
/** Add a new empty {@link Outline}
* to the shape, this new outline will
* be placed at the end of the outline list.
@@ -137,28 +147,98 @@ public class OutlineShape { outlines.add(new Outline());
}
- /** Adds an {@link Outline} to the OutlineShape object
- * if last outline of the shape is empty, it will replace
- * that last Outline with the new one. If outline is empty,
- * it will do nothing.
- * @param outline an Outline object
+ /** Appends the {@link Outline} element to the end,
+ * ensuring a clean tail.
+ * <p>A clean tail is ensured, ie no double empty Outlines. </p>
+ * @param outline Outline object to be added
+ * @throws NullPointerException if the {@link Outline} element is null
*/
- public void addOutline(Outline outline){
- if(outline.isEmpty()){
- return;
+ public void addOutline(Outline outline) throws NullPointerException {
+ addOutline(outlines.size(), outline);
+ }
+
+ /** Insert the {@link Outline} element at the given {@code position}.
+ * <p>If the {@code position} indicates the end of this list,
+ * a clean tail is ensured, ie no double empty Outlines. </p>
+ * @param position of the added Outline
+ * @param outline Outline object to be added
+ * @throws NullPointerException if the {@link Outline} element is null
+ * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position > getOutlineNumber())
+ */
+ public void addOutline(int position, Outline outline) throws NullPointerException, IndexOutOfBoundsException {
+ if (null == outline) {
+ throw new NullPointerException("outline is null");
}
- if(getLastOutline().isEmpty()){
- outlines.remove(getLastOutline());
+ if(outlines.size() == position) {
+ if(outline.isEmpty()) {
+ return;
+ }
+ if(getLastOutline().isEmpty()) {
+ outlines.set(position-1, outline);
+ if(!dirtyBBox) {
+ bbox.resize(outline.getBounds());
+ }
+ }
+ } else {
+ outlines.add(position, outline);
+ if(!dirtyBBox) {
+ bbox.resize(outline.getBounds());
+ }
}
- outlines.add(outline);
}
-
+
+ /** Replaces the {@link Outline} element at the given {@code position}.
+ * <p>Sets the bounding box dirty, hence a next call to {@link #getBounds()} will validate it.</p>
+ *
+ * @param position of the replaced Outline
+ * @param outline replacement Outline object
+ * @throws NullPointerException if the {@link Outline} element is null
+ * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position >= getOutlineNumber())
+ */
+ public void setOutline(int position, Outline outline) throws NullPointerException, IndexOutOfBoundsException {
+ if (null == outline) {
+ throw new NullPointerException("outline is null");
+ }
+ outlines.set(position, outline);
+ dirtyBBox = true;
+ }
+
+ /** Removes the {@link Outline} element at the given {@code position}.
+ * <p>Sets the bounding box dirty, hence a next call to {@link #getBounds()} will validate it.</p>
+ *
+ * @param position of the to be removed Outline
+ * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position >= getOutlineNumber())
+ */
+ public final Outline removeOutline(int position) throws IndexOutOfBoundsException {
+ dirtyBBox = true;
+ return outlines.remove(position);
+ }
+
+ /** Get the last added outline to the list
+ * of outlines that define the shape
+ * @return the last outline
+ */
+ public final Outline getLastOutline(){
+ return outlines.get(outlines.size()-1);
+ }
+
+ /** @return the {@code Outline} at {@code position}
+ * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position >= getOutlineNumber())
+ */
+ public Outline getOutline(int position) throws IndexOutOfBoundsException {
+ return outlines.get(position);
+ }
+
/** Adds a vertex to the last open outline in the
* shape.
* @param v the vertex to be added to the OutlineShape
*/
public final void addVertex(Vertex v){
- getLastOutline().addVertex(v);
+ final Outline lo = getLastOutline();
+ lo.addVertex(v);
+ if(!dirtyBBox) {
+ bbox.resize(lo.getBounds());
+ }
}
/** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute
@@ -170,7 +250,7 @@ public class OutlineShape { * of the shape around this vertex.
*/
public final void addVertex(float x, float y, boolean onCurve) {
- getLastOutline().addVertex(vertexFactory, x, y, onCurve);
+ addVertex(vertexFactory.create(x, y, 0f, onCurve));
}
/** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute
@@ -182,7 +262,7 @@ public class OutlineShape { * of the shape around this vertex.
*/
public final void addVertex(float x, float y, float z, boolean onCurve) {
- getLastOutline().addVertex(vertexFactory, x, y, z, onCurve);
+ addVertex(vertexFactory.create(x, y, z, onCurve));
}
/** Add a vertex to the last outline by passing a float array and specifying the
@@ -197,7 +277,7 @@ public class OutlineShape { * of the shape around this vertex.
*/
public final void addVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) {
- getLastOutline().addVertex(vertexFactory, coordsBuffer, offset, length, onCurve);
+ addVertex(vertexFactory.create(coordsBuffer, offset, length, onCurve));
}
/** Closes the last outline in the shape
@@ -209,62 +289,59 @@ public class OutlineShape { getLastOutline().setClosed(true);
}
- /** Get the last added outline to the list
- * of outlines that define the shape
- * @return the last outline
+ /**
+ * @return the outline's vertices state, {@link OutlineShape.VerticesState}
*/
- public final Outline getLastOutline(){
- return outlines.get(outlines.size()-1);
+ public final VerticesState getOutlineState() {
+ return outlineState;
}
- /** Make sure that the outlines represent
- * the specified destinationType, if not
- * transform outlines to destination type.
- * @param destinationType TODO
+
+ /** Ensure the outlines represent
+ * the specified destinationType.
+ *
+ * @param destinationType the target outline's vertices state. Currently only {@link OutlineShape.VerticesState#QUADRATIC_NURBS} are supported.
*/
public void transformOutlines(VerticesState destinationType){
if(outlineState != destinationType){
if(destinationType == VerticesState.QUADRATIC_NURBS){
- transformOutlinesQuadratic();
+ transformOutlines2Quadratic();
} else {
throw new IllegalStateException("destinationType "+destinationType.name()+" not supported (currently "+outlineState.name()+")");
}
}
}
- private void transformOutlinesQuadratic(){
- ArrayList<Outline> newOutlines = new ArrayList<Outline>(3);
-
- /**loop over the outlines and make sure no
- * adj off-curve vertices
- */
- for(Outline outline:outlines){
- Outline newOutline = new Outline();
-
- ArrayList<Vertex> vertices = outline.getVertices();
- int size =vertices.size()-1;
- for(int i=0;i<size;i++){
- Vertex currentVertex = vertices.get(i);
- Vertex nextVertex = vertices.get((i+1)%size);
- if(!(currentVertex.isOnCurve()) && !(nextVertex.isOnCurve())) {
- newOutline.addVertex(currentVertex);
-
- float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
- newOutline.addVertex(vertexFactory, newCoords, 0, 3, true);
- }
- else {
- newOutline.addVertex(currentVertex);
- }
+ private void transformOutlines2Quadratic(){
+ final int count = getOutlineNumber();
+ for (int cc = 0; cc < count; cc++){
+ final Outline outline = getOutline(cc);
+ int vertexNumberLessOne = outline.getVertexNumber() - 1;
+ for(int i=0; i < vertexNumberLessOne; i++) {
+ final Vertex currentVertex = outline.getVertex(i);
+ final Vertex nextVertex = outline.getVertex(i+1);
+ if ( !currentVertex.isOnCurve() && !nextVertex.isOnCurve() ) {
+ final float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
+ final Vertex v = vertexFactory.create(newCoords, 0, 3, true);
+ v.setOnCurve(true);
+ i++;
+ vertexNumberLessOne++;
+ outline.addVertex(i, v);
+ }
}
- newOutlines.add(newOutline);
+ // Cut off last vertex (which is on-curve)
+ // FIXME: original code skipped the last element (it _is_ unrelated to the xform above)
+ // FIXME: understand why the last element produces artifacts in rendering
+ if( vertexNumberLessOne >= 0 ) {
+ outline.removeVertex(vertexNumberLessOne);
+ }
}
- outlines = newOutlines;
outlineState = VerticesState.QUADRATIC_NURBS;
}
private void generateVertexIds(){
int maxVertexId = 0;
- for(Outline outline:outlines){
- ArrayList<Vertex> vertices = outline.getVertices();
+ for(int i=0; i<outlines.size(); i++) {
+ final ArrayList<Vertex> vertices = outlines.get(i).getVertices();
for(Vertex vert:vertices){
vert.setId(maxVertexId);
maxVertexId++;
@@ -272,18 +349,17 @@ public class OutlineShape { }
}
- /** @return the list of vertices associated with the
- * {@code Outline} list of this object
+ /** @return the list of concatenated vertices associated with all
+ * {@code Outline}s of this object
*/
public ArrayList<Vertex> getVertices(){
ArrayList<Vertex> vertices = new ArrayList<Vertex>();
- for(Outline polyline:outlines){
- vertices.addAll(polyline.getVertices());
+ for(int i=0; i<outlines.size(); i++) {
+ vertices.addAll(outlines.get(i).getVertices());
}
return vertices;
}
-
/**Triangulate the {@link OutlineShape} generating a list of triangles
* @return an arraylist of triangles representing the filled region
* which is produced by the combination of the outlines
@@ -314,4 +390,81 @@ public class OutlineShape { Collections.sort(outlines);
Collections.reverse(outlines);
}
+
+ /** Compare two outline shapes with Bounding Box area
+ * as criteria.
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public final int compareTo(OutlineShape outline) {
+ float size = getBounds().getSize();
+ float newSize = outline.getBounds().getSize();
+ if(size < newSize){
+ return -1;
+ }
+ else if(size > newSize){
+ return 1;
+ }
+ return 0;
+ }
+
+ private final void validateBoundingBox() {
+ dirtyBBox = false;
+ bbox.reset();
+ for (int i=0; i<outlines.size(); i++) {
+ bbox.resize(outlines.get(i).getBounds());
+ }
+ }
+
+ public final AABBox getBounds() {
+ if (dirtyBBox) {
+ validateBoundingBox();
+ }
+ return bbox;
+ }
+
+ /**
+ * @param obj the Object to compare this OutlineShape with
+ * @return true if {@code obj} is an OutlineShape, not null,
+ * same outlineState, equal bounds and equal outlines in the same order
+ */
+ public boolean equals(Object obj) {
+ if( obj == this) {
+ return true;
+ }
+ if( null == obj || !(obj instanceof OutlineShape) ) {
+ return false;
+ }
+ final OutlineShape o = (OutlineShape) obj;
+ if(getOutlineState() != o.getOutlineState()) {
+ return false;
+ }
+ if(getOutlineNumber() != o.getOutlineNumber()) {
+ return false;
+ }
+ if( !getBounds().equals( o.getBounds() ) ) {
+ return false;
+ }
+ for (int i=getOutlineNumber()-1; i>=0; i--) {
+ if( ! getOutline(i).equals( o.getOutline(i) ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return deep clone of this OutlineShape
+ */
+ public OutlineShape clone() {
+ OutlineShape o;
+ try {
+ o = (OutlineShape) super.clone();
+ } catch (CloneNotSupportedException e) { return null; /* never, ever */ }
+ o.bbox = bbox.clone();
+ o.outlines = new ArrayList<Outline>(outlines.size());
+ for(int i=0; i<outlines.size(); i++) {
+ o.outlines.add(outlines.get(i).clone());
+ }
+ return o;
+ }
}
|