diff options
Diffstat (limited to 'src/jogl/classes/com/jogamp')
8 files changed, 504 insertions, 227 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java index c995b3749..9a5d86fc2 100755 --- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java +++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java @@ -30,11 +30,13 @@ 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;
import com.jogamp.graph.math.VectorUtil;
+import com.jogamp.graph.curve.OutlineShape.VerticesState;
import com.jogamp.graph.curve.tess.CDTriangulator2D;
/** A Generic shape objects which is defined by a list of Outlines.
@@ -53,7 +55,7 @@ import com.jogamp.graph.curve.tess.CDTriangulator2D; addVertex(...)
addVertex(...)
addVertex(...)
- addEnptyOutline()
+ addEmptyOutline()
addVertex(...)
addVertex(...)
addVertex(...)
@@ -90,21 +92,39 @@ import com.jogamp.graph.curve.tess.CDTriangulator2D; * @see Outline
* @see Region
*/
-public class OutlineShape {
+public class OutlineShape implements Comparable<OutlineShape> {
+ /**
+ * Outline's vertices have undefined state until transformed.
+ */
+ public enum VerticesState {
+ UNDEFINED(0), QUADRATIC_NURBS(1);
- public static final int QUADRATIC_NURBS = 10;
+ public final int state;
+
+ VerticesState(int state){
+ this.state = state;
+ }
+ }
+
private final Vertex.Factory<? extends Vertex> vertexFactory;
+ private VerticesState outlineState;
/** 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());
+ 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
@@ -112,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.
@@ -123,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
@@ -156,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
@@ -168,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
@@ -183,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
@@ -195,57 +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 The curve type needed
+
+ /** 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(int destinationType){
- if(destinationType == QUADRATIC_NURBS){
- transformOutlinesQuadratic();
+ public void transformOutlines(VerticesState destinationType){
+ if(outlineState != destinationType){
+ if(destinationType == VerticesState.QUADRATIC_NURBS){
+ 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++;
@@ -253,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
@@ -295,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) { throw new InternalError(); }
+ 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;
+ }
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java index d0bb568f9..c7a01b8b8 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java @@ -113,7 +113,7 @@ public abstract class RegionRenderer extends Renderer { protected Region createRegion(GL2ES2 gl, OutlineShape outlineShape) { Region region = RegionFactory.create(rs, renderType); - outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS); + outlineShape.transformOutlines(OutlineShape.VerticesState.QUADRATIC_NURBS); ArrayList<Triangle> triangles = (ArrayList<Triangle>) outlineShape.triangulate(); ArrayList<Vertex> vertices = (ArrayList<Vertex>) outlineShape.getVertices(); region.addVertices(vertices); @@ -133,7 +133,7 @@ public abstract class RegionRenderer extends Renderer { int numVertices = region.getNumVertices(); for(OutlineShape outlineShape:outlineShapes){ - outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS); + outlineShape.transformOutlines(OutlineShape.VerticesState.QUADRATIC_NURBS); ArrayList<Triangle> triangles = outlineShape.triangulate(); region.addTriangles(triangles); diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java index 1010d4f1a..a942c7a58 100644 --- a/src/jogl/classes/com/jogamp/graph/font/Font.java +++ b/src/jogl/classes/com/jogamp/graph/font/Font.java @@ -88,8 +88,8 @@ public interface Font { public Glyph getGlyph(char symbol); public int getNumGlyphs(); - public float getStringWidth(String string, float pixelSize); - public float getStringHeight(String string, float pixelSize); + public float getStringWidth(CharSequence string, float pixelSize); + public float getStringHeight(CharSequence string, float pixelSize); public AABBox getStringBounds(CharSequence string, float pixelSize); public boolean isPrintableChar( char c ); diff --git a/src/jogl/classes/com/jogamp/graph/geom/AABBox.java b/src/jogl/classes/com/jogamp/graph/geom/AABBox.java index 7051e9110..87f084919 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/AABBox.java +++ b/src/jogl/classes/com/jogamp/graph/geom/AABBox.java @@ -35,7 +35,7 @@ import com.jogamp.graph.math.VectorUtil; * right corner of the box. * */ -public class AABBox { +public class AABBox implements Cloneable { private float[] low = new float[3]; private float[] high = new float[3]; private float[] center = new float[3]; @@ -79,7 +79,7 @@ public class AABBox { } /** resets this box to the inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit. */ - public void reset() { + public final void reset() { setLow(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE); setHigh(-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE); center[0] = 0f; @@ -90,11 +90,11 @@ public class AABBox { /** Get the max xyz-coordinates * @return a float array containing the max xyz coordinates */ - public float[] getHigh() { + public final float[] getHigh() { return high; } - private void setHigh(float hx, float hy, float hz) { + private final void setHigh(float hx, float hy, float hz) { this.high[0] = hx; this.high[1] = hy; this.high[2] = hz; @@ -103,11 +103,11 @@ public class AABBox { /** Get the min xyz-coordinates * @return a float array containing the min xyz coordinates */ - public float[] getLow() { + public final float[] getLow() { return low; } - private void setLow(float lx, float ly, float lz) { + private final void setLow(float lx, float ly, float lz) { this.low[0] = lx; this.low[1] = ly; this.low[2] = lz; @@ -116,7 +116,7 @@ public class AABBox { /** Resize the AABBox to encapsulate another AABox * @param newBox AABBox to be encapsulated in */ - public void resize(AABBox newBox) { + public final void resize(AABBox newBox) { float[] newLow = newBox.getLow(); float[] newHigh = newBox.getHigh(); @@ -139,7 +139,7 @@ public class AABBox { computeCenter(); } - private void computeCenter() { + private final void computeCenter() { center[0] = (high[0] + low[0])/2; center[1] = (high[1] + low[1])/2; center[2] = (high[2] + low[2])/2; @@ -151,7 +151,7 @@ public class AABBox { * @param y y-axis coordinate value * @param z z-axis coordinate value */ - public void resize(float x, float y, float z) { + public final void resize(float x, float y, float z) { /** test low */ if (x < low[0]) low[0] = x; @@ -171,6 +171,15 @@ public class AABBox { computeCenter(); } + /** Resize the AABBox to encapsulate the passed + * xyz-coordinates. + * @param xyz xyz-axis coordinate values + * @param offset of the array + */ + public final void resize(float[] xyz, int offset) { + resize(xyz[0+offset], xyz[1+offset], xyz[2+offset]); + } + /** Check if the x & y coordinates are bounded/contained * by this AABBox * @param x x-axis coordinate value @@ -178,7 +187,7 @@ public class AABBox { * @return true if x belong to (low.x, high.x) and * y belong to (low.y, high.y) */ - public boolean contains(float x, float y) { + public final boolean contains(float x, float y) { if(x<low[0] || x>high[0]){ return false; } @@ -196,7 +205,7 @@ public class AABBox { * @return true if x belong to (low.x, high.x) and * y belong to (low.y, high.y) and z belong to (low.z, high.z) */ - public boolean contains(float x, float y, float z) { + public final boolean contains(float x, float y, float z) { if(x<low[0] || x>high[0]){ return false; } @@ -217,7 +226,7 @@ public class AABBox { * @param h hight * @return true if this AABBox might have a common region with this 2D region */ - public boolean intersects(float x, float y, float w, float h) { + public final boolean intersects(float x, float y, float w, float h) { if (w <= 0 || h <= 0) { return false; } @@ -241,21 +250,21 @@ public class AABBox { * length of the vector between low and high. * @return a float representing the size of the AABBox */ - public float getSize() { + public final float getSize() { return VectorUtil.computeLength(low, high); } /**Get the Center of the AABBox * @return the xyz-coordinates of the center of the AABBox */ - public float[] getCenter() { + public final float[] getCenter() { return center; } /** Scale the AABBox by a constant * @param size a constant float value */ - public void scale(float size) { + public final void scale(float size) { float[] diffH = new float[3]; diffH[0] = high[0] - center[0]; diffH[1] = high[1] - center[1]; @@ -274,30 +283,43 @@ public class AABBox { low = VectorUtil.vectorAdd(center, diffL); } - public float getMinX() { + public final float getMinX() { return low[0]; } - public float getMinY() { + public final float getMinY() { return low[1]; } - public float getWidth(){ + public final float getWidth(){ return high[0] - low[0]; } - public float getHeight() { + public final float getHeight() { return high[1] - low[1]; } - public float getDepth() { + public final float getDepth() { return high[2] - low[2]; } - public AABBox clone() { + + public final AABBox clone() { return new AABBox(this.low, this.high); } - public String toString() { + public final boolean equals(Object obj) { + if( obj == this ) { + return true; + } + if( null == obj || !(obj instanceof AABBox) ) { + return false; + } + final AABBox other = (AABBox) obj; + return VectorUtil.checkEquality(low, other.low) && + VectorUtil.checkEquality(high, other.high) ; + } + + public final String toString() { return "[ "+low[0]+"/"+low[1]+"/"+low[1]+" .. "+high[0]+"/"+high[0]+"/"+high[0]+", ctr "+ center[0]+"/"+center[1]+"/"+center[1]+" ]"; } diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java index 315be002f..b0ad86fda 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java @@ -43,110 +43,116 @@ import com.jogamp.graph.math.VectorUtil; * * @see OutlineShape, Region */ -public class Outline implements Comparable<Outline> { +public class Outline implements Cloneable, Comparable<Outline> { private ArrayList<Vertex> vertices = new ArrayList<Vertex>(3); private boolean closed = false; - private AABBox box = new AABBox(); + private AABBox bbox = new AABBox(); + private boolean dirtyBBox = false; /**Create an outline defined by control vertices. * An outline can contain off Curve vertices which define curved * regions in the outline. */ - public Outline(){ + public Outline() { + } + public final int getVertexNumber() { + return vertices.size(); } - /** Add a vertex to the outline. The {@link Vertex} is added at the - * end of the outline loop/strip. + /** Appends a vertex to the outline loop/strip. * @param vertex Vertex to be added + * @throws NullPointerException if the {@link Vertex} element is null */ - public final void addVertex(Vertex vertex) { - vertices.add(vertex); - box.resize(vertex.getX(), vertex.getY(), vertex.getZ()); + public final void addVertex(Vertex vertex) throws NullPointerException { + addVertex(vertices.size(), vertex); } - /** Add a {@link Vertex} by specifying its 2D attributes to the outline. - * The {@link Vertex} is added at the - * end of the outline loop/strip. - * @param factory a {@link Factory} to get the required Vertex impl - * @param x the x coordinate - * @param y the y coordinate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + /** Insert the {@link Vertex} element at the given {@code position} to the outline loop/strip. + * @param position of the added Vertex + * @param vertex Vertex object to be added + * @throws NullPointerException if the {@link Vertex} element is null + * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position > getVertexNumber()) */ - public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, boolean onCurve) { - addVertex(factory, x, y, 0f, onCurve); + public final void addVertex(int position, Vertex vertex) throws NullPointerException, IndexOutOfBoundsException { + if (null == vertex) { + throw new NullPointerException("vertex is null"); + } + vertices.add(position, vertex); + if(!dirtyBBox) { + bbox.resize(vertex.getX(), vertex.getY(), vertex.getZ()); + } } - - /** Add a {@link Vertex} by specifying its 3D attributes to the outline. - * The {@link Vertex} is added at the - * end of the outline loop/strip. - * @param factory a {@link Factory} to get the required Vertex impl - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. + + /** Replaces the {@link Vertex} 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 Vertex + * @param vertex replacement Vertex object + * @throws NullPointerException if the {@link Outline} element is null + * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position >= getVertexNumber()) */ - public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, float z, boolean onCurve) { - Vertex v = factory.create(x, y, z); - v.setOnCurve(onCurve); - addVertex(v); + public final void setVertex(int position, Vertex vertex) throws NullPointerException, IndexOutOfBoundsException { + if (null == vertex) { + throw new NullPointerException("vertex is null"); + } + vertices.set(position, vertex); + dirtyBBox = true; } - /** Add a vertex to the outline by passing a float array and specifying the - * offset and length in which. The attributes of the vertex are located. - * The attributes should be continuous (stride = 0). - * Attributes which value are not set (when length less than 3) - * are set implicitly to zero. - * @param factory a {@link Factory} to get the required Vertex impl - * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from - * @param offset the offset in the buffer to the x coordinate - * @param length the number of attributes to pick from the buffer (maximum 3) - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. - */ - public final void addVertex(Vertex.Factory<? extends Vertex> factory, float[] coordsBuffer, int offset, int length, boolean onCurve) { - Vertex v = factory.create(coordsBuffer, offset, length); - v.setOnCurve(onCurve); - addVertex(v); + public final Vertex getVertex(int index){ + return vertices.get(index); } - public Vertex getVertex(int index){ - return vertices.get(index); + /** Removes the {@link Vertex} 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 Vertex + * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position >= getVertexNumber()) + */ + public final Vertex removeVertex(int position) throws IndexOutOfBoundsException { + dirtyBBox = true; + return vertices.remove(position); } - public boolean isEmpty(){ + public final boolean isEmpty(){ return (vertices.size() == 0); } - public Vertex getLastVertex(){ + + public final Vertex getLastVertex(){ if(isEmpty()){ return null; } return vertices.get(vertices.size()-1); } - public ArrayList<Vertex> getVertices() { + public final ArrayList<Vertex> getVertices() { return vertices; } - public void setVertices(ArrayList<Vertex> vertices) { + + /** + * Use the given outline loop/strip. + * <p>Validates the bounding box.</p> + * + * @param vertices the new outline loop/strip + */ + public final void setVertices(ArrayList<Vertex> vertices) { this.vertices = vertices; + validateBoundingBox(); } - public AABBox getBox() { - return box; - } - public boolean isClosed() { + + public final boolean isClosed() { return closed; } - + /** define if this outline is closed or not. * if set to closed, checks if the last vertex is * equal to the first vertex. If not Equal adds a * vertex at the end to the list. * @param closed */ - public void setClosed(boolean closed) { + public final void setClosed(boolean closed) { this.closed = closed; if(closed){ Vertex first = vertices.get(0); @@ -162,9 +168,9 @@ public class Outline implements Comparable<Outline> { * as criteria. * @see java.lang.Comparable#compareTo(java.lang.Object) */ - public int compareTo(Outline outline) { - float size = box.getSize(); - float newSize = outline.getBox().getSize(); + public final int compareTo(Outline outline) { + float size = getBounds().getSize(); + float newSize = outline.getBounds().getSize(); if(size < newSize){ return -1; } @@ -173,4 +179,61 @@ public class Outline implements Comparable<Outline> { } return 0; } + + private final void validateBoundingBox() { + dirtyBBox = false; + bbox.reset(); + for (int i=0; i<vertices.size(); i++) { + bbox.resize(vertices.get(i).getCoord(), 0); + } + } + + public final AABBox getBounds() { + if (dirtyBBox) { + validateBoundingBox(); + } + return bbox; + } + + /** + * @param obj the Object to compare this Outline with + * @return true if {@code obj} is an Outline, not null, equals bounds and equal vertices in the same order + */ + public boolean equals(Object obj) { + if( obj == this) { + return true; + } + if( null == obj || !(obj instanceof Outline) ) { + return false; + } + final Outline o = (Outline) obj; + if(getVertexNumber() != o.getVertexNumber()) { + return false; + } + if( !getBounds().equals( o.getBounds() ) ) { + return false; + } + for (int i=getVertexNumber()-1; i>=0; i--) { + if( ! getVertex(i).equals( o.getVertex(i) ) ) { + return false; + } + } + return true; + } + + /** + * @return deep clone of this Outline + */ + public Outline clone() { + Outline o; + try { + o = (Outline) super.clone(); + } catch (CloneNotSupportedException e) { throw new InternalError(); } + o.bbox = bbox.clone(); + o.vertices = new ArrayList<Vertex>(vertices.size()); + for(int i=0; i<vertices.size(); i++) { + o.vertices.add(vertices.get(i).clone()); + } + return o; + } } diff --git a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java index 859add943..3080f32cc 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java @@ -30,22 +30,21 @@ package com.jogamp.graph.geom; /** * A Vertex with custom memory layout using custom factory. */ -public interface Vertex extends Comparable<Vertex>, Cloneable { +public interface Vertex extends Cloneable { public static interface Factory <T extends Vertex> { T create(); - T create(float x, float y); + T create(float x, float y, float z, boolean onCurve); - T create(float x, float y, float z); - - T create(float[] coordsBuffer, int offset, int length); + T create(float[] coordsBuffer, int offset, int length, boolean onCurve); } - void setCoord(float x, float y); - void setCoord(float x, float y, float z); + /** + * @see System#arraycopy(Object, int, Object, int, int) for thrown IndexOutOfBoundsException + */ void setCoord(float[] coordsBuffer, int offset, int length); float[] getCoord(); @@ -70,11 +69,23 @@ public interface Vertex extends Comparable<Vertex>, Cloneable { void setId(int id); - int compareTo(Vertex p); - float[] getTexCoord(); void setTexCoord(float s, float t); + /** + * @see System#arraycopy(Object, int, Object, int, int) for thrown IndexOutOfBoundsException + */ + void setTexCoord(float[] texCoordsBuffer, int offset, int length); + + /** + * @param obj the Object to compare this Vertex with + * @return true if {@code obj} is a Vertex and not null, on-curve flag is equal and has same vertex- and tex-coords. + */ + boolean equals(Object obj); + + /** + * @return deep clone of this Vertex + */ Vertex clone(); } diff --git a/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java b/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java index 6241d60df..9dade17e9 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java +++ b/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java @@ -27,7 +27,6 @@ */ package com.jogamp.graph.geom.opengl; - import com.jogamp.graph.geom.Vertex; import com.jogamp.graph.math.VectorUtil; @@ -38,7 +37,7 @@ import com.jogamp.graph.math.VectorUtil; public class SVertex implements Vertex { private int id = Integer.MAX_VALUE; protected float[] coord = new float[3]; - protected boolean onCurve = true; + protected boolean onCurve; private float[] texCoord = new float[2]; static final Factory factory = new Factory(); @@ -46,133 +45,130 @@ public class SVertex implements Vertex { public static Factory factory() { return factory; } public static class Factory implements Vertex.Factory<SVertex> { - @Override public SVertex create() { return new SVertex(); } - @Override - public SVertex create(float x, float y) { - return new SVertex(x, y); - } - - @Override - public SVertex create(float x, float y, float z) { - return new SVertex(x, y, z); + public SVertex create(float x, float y, float z, boolean onCurve) { + return new SVertex(x, y, z, onCurve); } - @Override - public SVertex create(float[] coordsBuffer, int offset, int length) { - return new SVertex(coordsBuffer, offset, length); + public SVertex create(float[] coordsBuffer, int offset, int length, boolean onCurve) { + return new SVertex(coordsBuffer, offset, length, onCurve); } } public SVertex() { } - public SVertex(float x, float y) { - setCoord(x, y); - } - public SVertex(float x, float y, float z) { + public SVertex(float x, float y, float z, boolean onCurve) { setCoord(x, y, z); - } - public SVertex(float[] coordsBuffer, int offset, int length) { + setOnCurve(onCurve); + } + + public SVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) { setCoord(coordsBuffer, offset, length); + setOnCurve(onCurve); } - public void setCoord(float x, float y) { - this.coord[0] = x; - this.coord[1] = y; - this.coord[2] = 0f; + public SVertex(float[] coordsBuffer, int offset, int length, + float[] texCoordsBuffer, int offsetTC, int lengthTC, boolean onCurve) { + setCoord(coordsBuffer, offset, length); + setTexCoord(texCoordsBuffer, offsetTC, lengthTC); + setOnCurve(onCurve); } - - public void setCoord(float x, float y, float z) { + + public final void setCoord(float x, float y, float z) { this.coord[0] = x; this.coord[1] = y; this.coord[2] = z; } - public void setCoord(float[] coordsBuffer, int offset, int length) { - if(length > coordsBuffer.length - offset) { - throw new IndexOutOfBoundsException("coordsBuffer too small: "+coordsBuffer.length+" - "+offset+" < "+length); - } - if(length > 3) { - throw new IndexOutOfBoundsException("length too big: "+length+" > "+3); - } - int i=0; - while(i<length) { - this.coord[i++] = coordsBuffer[offset++]; - } + public final void setCoord(float[] coordsBuffer, int offset, int length) { + System.arraycopy(coordsBuffer, offset, coord, 0, length); } - public float[] getCoord() { + public final float[] getCoord() { return coord; } - public void setX(float x) { + public final void setX(float x) { this.coord[0] = x; } - public void setY(float y) { + public final void setY(float y) { this.coord[1] = y; } - public void setZ(float z) { + public final void setZ(float z) { this.coord[2] = z; } - public float getX() { + public final float getX() { return this.coord[0]; } - public float getY() { + public final float getY() { return this.coord[1]; } - public float getZ() { + public final float getZ() { return this.coord[2]; } - public boolean isOnCurve() { + public final boolean isOnCurve() { return onCurve; } - public void setOnCurve(boolean onCurve) { + public final void setOnCurve(boolean onCurve) { this.onCurve = onCurve; } - public int getId(){ + public final int getId(){ return id; } - public void setId(int id){ + public final void setId(int id){ this.id = id; } - public int compareTo(Vertex p) { - if(VectorUtil.checkEquality(coord, p.getCoord())) { - return 0; + public boolean equals(Object obj) { + if( obj == this) { + return true; + } + if( null == obj || !(obj instanceof Vertex) ) { + return false; } - return -1; + final Vertex v = (Vertex) obj; + return this == v || + isOnCurve() == v.isOnCurve() && + VectorUtil.checkEqualityVec2(getTexCoord(), v.getTexCoord()) && + VectorUtil.checkEquality(getCoord(), v.getCoord()) ; } - public float[] getTexCoord() { + public final float[] getTexCoord() { return texCoord; } - public void setTexCoord(float s, float t) { + public final void setTexCoord(float s, float t) { this.texCoord[0] = s; this.texCoord[1] = t; } - + + public final void setTexCoord(float[] texCoordsBuffer, int offset, int length) { + System.arraycopy(texCoordsBuffer, offset, texCoord, 0, length); + } + + /** + * @return deep clone of this Vertex, but keeping the id blank + */ public SVertex clone(){ - SVertex v = new SVertex(this.coord, 0, 3); - v.setOnCurve(this.onCurve); - return v; + return new SVertex(this.coord, 0, 3, this.texCoord, 0, 2, this.onCurve); } public String toString() { - return "[ID: " + id + " X: " + coord[0] - + " Y: " + coord[1] + " Z: " + coord[2] + "]"; + return "[ID: " + id + ", onCurve: " + onCurve + + ": p " + coord[0] + ", " + coord[1] + ", " + coord[2] + + ", t " + texCoord[0] + ", " + texCoord[1] + "]"; } } diff --git a/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java b/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java index 7cbb742e5..afab69f79 100755 --- a/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java +++ b/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java @@ -197,9 +197,22 @@ public class VectorUtil { */
public static boolean checkEquality(float[] v1, float[] v2)
{
- if(Float.compare(v1[0], v2[0]) == 0
- && Float.compare(v1[1] , v2[1]) == 0
- && Float.compare(v1[2], v2[2]) == 0 )
+ if(Float.compare(v1[0], v2[0]) == 0 &&
+ Float.compare(v1[1], v2[1]) == 0 &&
+ Float.compare(v1[2], v2[2]) == 0 )
+ return true;
+ return false;
+ }
+
+ /**Check equality of 2 vec2 vectors
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @return
+ */
+ public static boolean checkEqualityVec2(float[] v1, float[] v2)
+ {
+ if(Float.compare(v1[0], v2[0]) == 0 &&
+ Float.compare(v1[1], v2[1]) == 0)
return true;
return false;
}
|