/**
* Copyright 2010-2024 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.geom;
import java.io.PrintStream;
import java.util.ArrayList;
import com.jogamp.math.FloatUtil;
import com.jogamp.math.VectorUtil;
import com.jogamp.math.geom.AABBox;
import com.jogamp.math.geom.plane.AffineTransform;
import com.jogamp.math.geom.plane.Winding;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.curve.Region;
/** Define a single continuous stroke by control vertices.
* The vertices define the shape of the region defined by this
* outline. The Outline can contain a list of off-curve and on-curve
* vertices which define curved regions.
*
* Note: An outline should be closed to be rendered as a region.
*
* @see OutlineShape
* @see Region
*/
public class Outline implements Comparable
* The result is cached. *
* @return {@link Winding#CCW} or {@link Winding#CW} */ public final Winding getWinding() { if( 0 == ( dirtyBits & DIRTY_WINDING ) ) { return winding; } final int count = getVertexCount(); if( 3 > count ) { winding = Winding.CCW; } else { winding = VectorUtil.getWinding( getVertices() ); } dirtyBits &= ~DIRTY_WINDING; return winding; } /** * Returns the cached or computed result whether this {@link Outline}s {@code polyline} has a convex shape using {@link VectorUtil#isConvex(ArrayList, boolean)}. ** A polyline with less than 3 elements is marked convex for simplicity, * since a non-convex complex shape may need to pass intersection testing within triangulation. *
** The result is cached. *
*/ public boolean isConvex() { if( 0 == ( dirtyBits & DIRTY_CONVEX ) ) { return convexFlag; } convexFlag = VectorUtil.isConvex1( getVertices(), true ); dirtyBits &= ~DIRTY_CONVEX; return convexFlag; } public final int getVertexCount() { return vertices.size(); } /** * 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(final Vertex vertex) throws NullPointerException { addVertex(vertices.size(), 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(final int position, final Vertex vertex) throws NullPointerException, IndexOutOfBoundsException { if (null == vertex) { throw new NullPointerException("vertex is null"); } vertices.add(position, vertex); if(!dirtyBBox) { bbox.resize(vertex.getCoord()); } dirtyBits |= DIRTY_WINDING | DIRTY_CONVEX; } /** Replaces the {@link Vertex} element at the given {@code position}. *Sets the bounding box dirty, hence a next call to {@link #getBounds()} will validate it.
* * @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 setVertex(final int position, final Vertex vertex) throws NullPointerException, IndexOutOfBoundsException { if (null == vertex) { throw new NullPointerException("vertex is null"); } vertices.set(position, vertex); dirtyBBox = true; dirtyBits |= DIRTY_WINDING | DIRTY_CONVEX; } public final Vertex getVertex(final int index){ return vertices.get(index); } public int getVertexIndex(final Vertex vertex){ return vertices.indexOf(vertex); } /** Removes the {@link Vertex} element at the given {@code position}. *Sets the bounding box dirty, hence a next call to {@link #getBounds()} will validate it.
* * @param position of the to be removed Vertex * @throws IndexOutOfBoundsException if position is out of range (position < 0 || position >= getVertexNumber()) */ public final Vertex removeVertex(final int position) throws IndexOutOfBoundsException { dirtyBBox = true; dirtyBits |= DIRTY_WINDING | DIRTY_CONVEX; return vertices.remove(position); } public final boolean isEmpty(){ return (vertices.size() == 0); } public final Vertex getLastVertex(){ if(isEmpty()){ return null; } return vertices.get(vertices.size()-1); } public final ArrayListValidates the bounding box.
* * @param vertices the new outline loop/strip */ public final void setVertices(final ArrayList
* Checks whether the last vertex equals to the first.
* If not equal, it either appends a copy of the first vertex
* or prepends a copy of the last vertex, depending on closeTail
.
*