/** * Copyright 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ package com.jogamp.graph.curve; import java.util.ArrayList; import java.util.Collections; 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.tess.CDTriangulator2D; /** A Generic shape objects which is defined by a list of Outlines. * This Shape can be transformed to Triangulations. * The list of triangles generated are render-able by a Region object. * The triangulation produced by this Shape will define the * closed region defined by the outlines. * * One or more OutlineShape Object can be associated to a region * this is left as a high-level representation of the Objects. For * optimizations, flexibility requirements for future features. * *

* Example to creating an Outline Shape: *
  	addVertex(...)
  	addVertex(...)
  	addVertex(...)
  	addEnptyOutline()
  	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 { public static final int QUADRATIC_NURBS = 10; private final Vertex.Factory vertexFactory; /** The list of outlines that are part of this * outline shape. */ private ArrayList> outlines = new ArrayList>(3); /** Create a new Outline based Shape */ public OutlineShape(Vertex.Factory factory) { vertexFactory = factory; outlines.add(new Outline()); } /** Returns the associated vertex factory of this outline shape * @return Vertex.Factory object */ public final Vertex.Factory vertexFactory() { return vertexFactory; } /** Add a new empty outline * to the shape, this new outline will * be placed at the end of the outline list. * * After a call to this function all new vertices added * will belong to the new outline */ public void addEmptyOutline(){ outlines.add(new Outline()); } /** Adds an 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 */ public void addOutline(Outline outline){ if(outline.isEmpty()){ return; } if(getLastOutline().isEmpty()){ outlines.remove(getLastOutline()); } outlines.add(outline); } /** 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); } /** Add a 2D 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) { getLastOutline().addVertex(vertexFactory, x, y, onCurve); } /** Add a 3D vertex to the last outline by defining the coordniate attribute * of the vertex. * @param x the x coordinate * @param y the y coordniate * @param z the z 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, float z, boolean onCurve) { getLastOutline().addVertex(vertexFactory, 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) { getLastOutline().addVertex(vertexFactory, 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); } /** 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); } /** Make sure that the outlines represent * the specified destinationType, if not * transform outlines to destination type. * @param destinationType The curve type needed */ public void transformOutlines(int destinationType){ if(destinationType == QUADRATIC_NURBS){ transformOutlinesQuadratic(); } } private void transformOutlinesQuadratic(){ ArrayList> newOutlines = new ArrayList>(3); /**loop over the outlines and make sure no * adj off-curve vertices */ for(Outline outline:outlines){ Outline newOutline = new Outline(); ArrayList vertices = outline.getVertices(); int size =vertices.size()-1; for(int i=0;i outline:outlines){ ArrayList vertices = outline.getVertices(); for(Vertex vert:vertices){ vert.setId(maxVertexId); maxVertexId++; } } } /** @return the list of vertices associated with the * {@code Outline} list of this object */ public ArrayList getVertices(){ ArrayList vertices = new ArrayList(); for(Outline polyline:outlines){ vertices.addAll(polyline.getVertices()); } return vertices; } /** Triangulate the outline shape generating a list of triangles * @return an arraylist of triangles representing the filled region * which is produced by the combination of the outlines */ public ArrayList> triangulate(){ return triangulate(0.5f); } /**Triangulate the outline shape generating a list of triangles * @param sharpness defines the curvature strength around the off-curve vertices. * defaults to 0.5f * @return an arraylist of triangles representing the filled region * which is produced by the combination of the outlines */ public ArrayList> triangulate(float sharpness){ if(outlines.size() == 0){ return null; } sortOutlines(); generateVertexIds(); CDTriangulator2D triangulator2d = new CDTriangulator2D(sharpness); for(int index = 0; index< outlines.size();index++){ Outline outline = outlines.get(index); triangulator2d.addCurve(outline); } ArrayList> triangles = triangulator2d.generateTriangulation(); triangulator2d.reset(); return triangles; } /** Sort the outlines from large * to small depending on the AABox */ private void sortOutlines() { Collections.sort(outlines); Collections.reverse(outlines); } }