From 64c7bea57d353729c93e1f60272e400a712ca47e Mon Sep 17 00:00:00 2001
From: Rami Santina If the {@link #getLastOutline()} is empty already, no new one will be added. A clean tail is ensured, no double empty Outlines are produced
- * and a pre-existing empty outline will be replaced with the given one. If the {@code position} indicates the end of this list,
- * a clean tail is ensured, no double empty Outlines are produced
- * and a pre-existing empty outline will be replaced with the given one. Closes the current last outline via {@link #closeLastOutline()} before adding the new ones.
- * Example to creating an Outline Shape:
- *
- addVertex(...)
- addVertex(...)
- addVertex(...)
- addEmptyOutline()
- addVertex(...)
- addVertex(...)
- addVertex(...)
- *
- *
- * The above will create two outlines each with three vertices. By adding these two outlines to
- * the OutlineShape, we are stating that the combination of the two outlines represent the shape.
- *
- *
- * To specify that the shape is curved at a region, the on-curve flag should be set to false
- * for the vertex that is in the middle of the curved region (if the curved region is defined by 3
- * vertices (quadratic curve).
- *
- * In case the curved region is defined by 4 or more vertices the middle vertices should both have
- * the on-curve flag set to false.
- *
- *
Example:
- *
- addVertex(0,0, true);
- addVertex(0,1, false);
- addVertex(1,1, false);
- addVertex(1,0, true);
- *
- *
- * The above snippet defines a cubic nurbs curve where (0,1 and 1,1)
- * do not belong to the final rendered shape.
- *
- * Implementation Notes:
- *
- *
- *
- * @see Outline
- * @see Region
- */
-public class OutlineShape implements Comparable
Sets the bounding box dirty, hence a next call to {@link #getBounds()} will validate it.
- * - * @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 { - dirtyBits |= DIRTY_BOUNDS; - 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){ - final Outline lo = getLastOutline(); - lo.addVertex(v); - if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { - bbox.resize(lo.getBounds()); - } - } - - /** Adds a vertex to the last open outline in the shape. - * at {@code position} - * @param position indx at which the vertex will be added - * @param v the vertex to be added to the OutlineShape - */ - public final void addVertex(int position, Vertex v){ - final Outline lo = getLastOutline(); - lo.addVertex(position, v); - if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { - bbox.resize(lo.getBounds()); - } - } - - /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute - * of the vertex. The 2D vertex will be represented as Z=0. - * - * @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 - * of the shape around this vertex. - */ - public final void addVertex(float x, float y, boolean onCurve) { - addVertex(vertexFactory.create(x, y, 0f, onCurve)); - } - - /** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute - * of the vertex. - * @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. - */ - public final void addVertex(float x, float y, float z, boolean onCurve) { - addVertex(vertexFactory.create(x, y, z, onCurve)); - } - - /** Add a vertex to the last 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 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(float[] coordsBuffer, int offset, int length, boolean onCurve) { - addVertex(vertexFactory.create(coordsBuffer, offset, length, onCurve)); - } - - /** Closes the last outline in the shape. - *If last vertex is not equal to first vertex. - * A new temp vertex is added at the end which - * is equal to the first.
- */ - public void closeLastOutline(){ - getLastOutline().setClosed(true); - } - - /** - * @return the outline's vertices state, {@link OutlineShape.VerticesState} - */ - public final VerticesState getOutlineState() { - return outlineState; - } - - /** 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){ - transformOutlines2Quadratic(); - } else { - throw new IllegalStateException("destinationType "+destinationType.name()+" not supported (currently "+outlineState.name()+")"); - } - } - } - - 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); - } - } - // 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); - } - } - outlineState = VerticesState.QUADRATIC_NURBS; - } - - private void generateVertexIds(){ - int maxVertexId = 0; - for(int i=0; i+ addVertex(...) + addVertex(...) + addVertex(...) + addEmptyOutline() + addVertex(...) + addVertex(...) + addVertex(...) + *+ * + * The above will create two outlines each with three vertices. By adding these two outlines to + * the OutlineShape, we are stating that the combination of the two outlines represent the shape. + *
+ addVertex(0,0, true); + addVertex(0,1, false); + addVertex(1,1, false); + addVertex(1,0, true); + *+ * + * The above snippet defines a cubic nurbs curve where (0,1 and 1,1) + * do not belong to the final rendered shape. + * + * Implementation Notes:
If the {@link #getLastOutline()} is empty already, no new one will be added.
+ * + * After a call to this function all new vertices added + * will belong to the new outline + */ + public void addEmptyOutline() { + if( !getLastOutline().isEmpty() ) { + outlines.add(new Outline()); + } + } + + /** Appends the {@link Outline} element to the end, + * ensuring a clean tail. + * + *A clean tail is ensured, no double empty Outlines are produced + * and a pre-existing empty outline will be replaced with the given one.
+ * + * @param outline Outline object to be added + * @throws NullPointerException if the {@link Outline} element is null + */ + public void addOutline(Outline outline) throws NullPointerException { + addOutline(outlines.size(), outline); + } + + /** Insert the {@link Outline} element at the given {@code position}. + * + *If the {@code position} indicates the end of this list, + * a clean tail is ensured, no double empty Outlines are produced + * and a pre-existing empty outline will be replaced with the given one.
+ * + * @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( outlines.size() == position ) { + final Outline lastOutline = getLastOutline(); + if( outline.isEmpty() && lastOutline.isEmpty() ) { + return; + } + if( lastOutline.isEmpty() ) { + outlines.set(position-1, outline); + if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { + bbox.resize(outline.getBounds()); + } + return; + } + } + outlines.add(position, outline); + if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { + bbox.resize(outline.getBounds()); + } + } + + /** Insert the {@link OutlineShape} elements of type {@link Outline}, .. at the end of this shape, + * using {@link #addOutline(Outline)} for each element. + *Closes the current last outline via {@link #closeLastOutline()} before adding the new ones.
+ * @param outlineShape OutlineShape elements to be added. + * @throws NullPointerException if the {@link OutlineShape} is null + * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position > getOutlineNumber()) + */ + public void addOutlineShape(OutlineShape outlineShape) throws NullPointerException { + if (null == outlineShape) { + throw new NullPointerException("OutlineShape is null"); + } + closeLastOutline(); + for(int i=0; iSets the bounding box dirty, hence a next call to {@link #getBounds()} will validate it.
+ * + * @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 { + dirtyBits |= DIRTY_BOUNDS; + 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) { + final Outline lo = getLastOutline(); + lo.addVertex(v); + if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { + bbox.resize(lo.getBounds()); + } + } + + /** Adds a vertex to the last open outline in the shape. + * at {@code position} + * @param position indx at which the vertex will be added + * @param v the vertex to be added to the OutlineShape + */ + public final void addVertex(int position, Vertex v) { + final Outline lo = getLastOutline(); + lo.addVertex(position, v); + if( 0 == ( dirtyBits & DIRTY_BOUNDS ) ) { + bbox.resize(lo.getBounds()); + } + } + + /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute + * of the vertex. The 2D vertex will be represented as Z=0. + * + * @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 + * of the shape around this vertex. + */ + public final void addVertex(float x, float y, boolean onCurve) { + addVertex(vertexFactory.create(x, y, 0f, onCurve)); + } + + /** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute + * of the vertex. + * @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. + */ + public final void addVertex(float x, float y, float z, boolean onCurve) { + addVertex(vertexFactory.create(x, y, z, onCurve)); + } + + /** Add a vertex to the last 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 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(float[] coordsBuffer, int offset, int length, boolean onCurve) { + addVertex(vertexFactory.create(coordsBuffer, offset, length, onCurve)); + } + + /** Closes the last outline in the shape. + *If last vertex is not equal to first vertex. + * A new temp vertex is added at the end which + * is equal to the first.
+ */ + public void closeLastOutline() { + getLastOutline().setClosed(true); + } + + /** + * @return the outline's vertices state, {@link OutlineShape.VerticesState} + */ + public final VerticesState getOutlineState() { + return outlineState; + } + + /** 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){ + transformOutlines2Quadratic(); + } else { + throw new IllegalStateException("destinationType "+destinationType.name()+" not supported (currently "+outlineState.name()+")"); + } + } + } + + private void transformOutlines2Quadratic() { + int count = getOutlineNumber(); + for (int cc = 0; cc < count; cc++) { + final Outline outline = getOutline(cc); + int vertexCount = outline.getVertexCount(); + + for(int i=0; i < vertexCount; i++) { + final Vertex currentVertex = outline.getVertex(i); + final Vertex nextVertex = outline.getVertex((i+1)%vertexCount); + if ( !currentVertex.isOnCurve() && !nextVertex.isOnCurve() ) { + final float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), + nextVertex.getCoord()); + final Vertex v = vertexFactory.create(newCoords, 0, 3, true); + i++; + vertexCount++; + outline.addVertex(i, v); + } + } + if(vertexCount <= 0) { + outlines.remove(outline); + cc--; + count--; + continue; + } + + if( vertexCount > 0 ) { + if(VectorUtil.checkEquality(outline.getVertex(0).getCoord(), + outline.getLastVertex().getCoord())) { + outline.removeVertex(vertexCount-1); + } + } + } + outlineState = VerticesState.QUADRATIC_NURBS; + } + + private void generateVertexIds() { + int maxVertexId = 0; + for(int i=0; i