/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.utility.geometry.nvtristrip;
import java.util.ArrayList;
import java.util.Vector;
/**
* @author YVG
*/
class StripInfo
{
protected StripStartInfo m_startInfo;
protected ArrayList< FaceInfo > m_faces = new ArrayList< FaceInfo >();
protected int m_stripId;
protected int m_experimentId;
protected int m_numDegenerates;
protected boolean visited;
public StripInfo( StripStartInfo startInfo, int stripId, int experimentId )
{
m_startInfo = startInfo;
m_stripId = stripId;
m_experimentId = experimentId;
m_numDegenerates = 0;
visited = false;
}
boolean isExperiment()
{
return m_experimentId >= 0;
}
boolean isInStrip( FaceInfo faceInfo )
{
if ( faceInfo == null )
return false;
return ( m_experimentId >= 0 ? faceInfo.m_testStripId == m_stripId : faceInfo.m_stripId == m_stripId );
}
/**
* If either the faceInfo has a real strip index because it is
* already assign to a committed strip OR it is assigned in an
* experiment and the experiment index is the one we are building
* for, then it is marked and unavailable.
*
* @param faceInfo
*/
boolean isMarked( FaceInfo faceInfo )
{
return ( faceInfo.m_stripId >= 0 ) || ( isExperiment() && faceInfo.m_experimentId == m_experimentId );
}
/**
* Marks the face with the current strip ID.
*
* @param faceInfo
*/
void markTriangle( FaceInfo faceInfo )
{
assert ( !isMarked( faceInfo ) );
if ( isExperiment() )
{
faceInfo.m_experimentId = m_experimentId;
faceInfo.m_testStripId = m_stripId;
}
else
{
assert ( faceInfo.m_stripId == -1 );
faceInfo.m_experimentId = -1;
faceInfo.m_stripId = m_stripId;
}
}
boolean unique( ArrayList< FaceInfo > faceVec, FaceInfo face )
{
boolean bv0, bv1, bv2; //bools to indicate whether a vertex is in the faceVec or not
bv0 = bv1 = bv2 = false;
for ( int i = 0; i < faceVec.size(); i++ )
{
if ( !bv0 )
{
if ( ( faceVec.get( i ).m_v0 == face.m_v0 ) || ( faceVec.get( i ).m_v1 == face.m_v0 ) || ( faceVec.get( i ).m_v2 == face.m_v0 ) )
bv0 = true;
}
if ( !bv1 )
{
if ( ( faceVec.get( i ).m_v0 == face.m_v1 ) || ( faceVec.get( i ).m_v1 == face.m_v1 ) || ( faceVec.get( i ).m_v2 == face.m_v1 ) )
bv1 = true;
}
if ( !bv2 )
{
if ( ( faceVec.get( i ).m_v0 == face.m_v2 ) || ( faceVec.get( i ).m_v1 == face.m_v2 ) || ( faceVec.get( i ).m_v2 == face.m_v2 ) )
bv2 = true;
}
//the face is not unique, all it's vertices exist in the face vector
if ( bv0 && bv1 && bv2 )
return false;
}
//if we get out here, it's unique
return true;
}
/**
* Builds a strip forward as far as we can go, then builds backwards, and joins the two lists.
*
* @param edgeInfos
* @param faceInfos
*/
void build( ArrayList< EdgeInfo > edgeInfos, ArrayList< FaceInfo > faceInfos )
{
// used in building the strips forward and backward
Vector< Integer > scratchIndices = new Vector< Integer >();
// build forward... start with the initial face
ArrayList< FaceInfo > forwardFaces = new ArrayList< FaceInfo >();
ArrayList< FaceInfo > backwardFaces = new ArrayList< FaceInfo >();
forwardFaces.add( m_startInfo.m_startFace );
markTriangle( m_startInfo.m_startFace );
int v0 = ( m_startInfo.m_toV1 ? m_startInfo.m_startEdge.m_v0 : m_startInfo.m_startEdge.m_v1 );
int v1 = ( m_startInfo.m_toV1 ? m_startInfo.m_startEdge.m_v1 : m_startInfo.m_startEdge.m_v0 );
// easiest way to get v2 is to use this function which requires the
// other indices to already be in the list.
scratchIndices.add( v0 );
scratchIndices.add( v1 );
int v2 = Stripifier.getNextIndex( scratchIndices, m_startInfo.m_startFace );
scratchIndices.add( v2 );
//
// build the forward list
//
int nv0 = v1;
int nv1 = v2;
FaceInfo nextFace = Stripifier.findOtherFace( edgeInfos, nv0, nv1, m_startInfo.m_startFace );
while ( nextFace != null && !isMarked( nextFace ) )
{
//check to see if this next face is going to cause us to die soon
int testnv0 = nv1;
int testnv1 = Stripifier.getNextIndex( scratchIndices, nextFace );
FaceInfo nextNextFace = Stripifier.findOtherFace( edgeInfos, testnv0, testnv1, nextFace );
if ( ( nextNextFace == null ) || ( isMarked( nextNextFace ) ) )
{
//uh, oh, we're following a dead end, try swapping
FaceInfo testNextFace = Stripifier.findOtherFace( edgeInfos, nv0, testnv1, nextFace );
if ( ( ( testNextFace != null ) && !isMarked( testNextFace ) ) )
{
//we only swap if it buys us something
//add a "fake" degenerate face
FaceInfo tempFace = new FaceInfo( nv0, nv1, nv0 );
forwardFaces.add( tempFace );
markTriangle( tempFace );
scratchIndices.add( nv0 );
testnv0 = nv0;
++m_numDegenerates;
}
}
// add this to the strip
forwardFaces.add( nextFace );
markTriangle( nextFace );
// add the index
//nv0 = nv1;
//nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace);
scratchIndices.add( testnv1 );
// and get the next face
nv0 = testnv0;
nv1 = testnv1;
nextFace = Stripifier.findOtherFace( edgeInfos, nv0, nv1, nextFace );
}
// tempAllFaces is going to be forwardFaces + backwardFaces
// it's used for Unique()
ArrayList< FaceInfo > tempAllFaces = new ArrayList< FaceInfo >();
for ( int i = 0; i < forwardFaces.size(); i++ )
tempAllFaces.add( forwardFaces.get( i ) );
//
// reset the indices for building the strip backwards and do so
//
scratchIndices.clear();
scratchIndices.add( v2 );
scratchIndices.add( v1 );
scratchIndices.add( v0 );
nv0 = v1;
nv1 = v0;
nextFace = Stripifier.findOtherFace( edgeInfos, nv0, nv1, m_startInfo.m_startFace );
while ( nextFace != null && !isMarked( nextFace ) )
{
//this tests to see if a face is "unique", meaning that its vertices aren't already in the list
// so, strips which "wrap-around" are not allowed
if ( !unique( tempAllFaces, nextFace ) )
break;
//check to see if this next face is going to cause us to die soon
int testnv0 = nv1;
int testnv1 = Stripifier.getNextIndex( scratchIndices, nextFace );
FaceInfo nextNextFace = Stripifier.findOtherFace( edgeInfos, testnv0, testnv1, nextFace );
if ( ( nextNextFace == null ) || ( isMarked( nextNextFace ) ) )
{
//uh, oh, we're following a dead end, try swapping
FaceInfo testNextFace = Stripifier.findOtherFace( edgeInfos, nv0, testnv1, nextFace );
if ( ( ( testNextFace != null ) && !isMarked( testNextFace ) ) )
{
//we only swap if it buys us something
//add a "fake" degenerate face
FaceInfo tempFace = new FaceInfo( nv0, nv1, nv0 );
backwardFaces.add( tempFace );
markTriangle( tempFace );
scratchIndices.add( nv0 );
testnv0 = nv0;
++m_numDegenerates;
}
}
// add this to the strip
backwardFaces.add( nextFace );
//this is just so Unique() will work
tempAllFaces.add( nextFace );
markTriangle( nextFace );
// add the index
//nv0 = nv1;
//nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace);
scratchIndices.add( testnv1 );
// and get the next face
nv0 = testnv0;
nv1 = testnv1;
nextFace = Stripifier.findOtherFace( edgeInfos, nv0, nv1, nextFace );
}
// Combine the forward and backwards stripification lists and put into our own face vector
combine( forwardFaces, backwardFaces );
}
/**
* Combines the two input face vectors and puts the result into m_faces.
*
* @param forward
* @param backward
*/
void combine( ArrayList< FaceInfo > forward, ArrayList< FaceInfo > backward )
{
// add backward faces
int numFaces = backward.size();
for ( int i = numFaces - 1; i >= 0; i-- )
m_faces.add( backward.get( i ) );
// add forward faces
numFaces = forward.size();
for ( int i = 0; i < numFaces; i++ )
m_faces.add( forward.get( i ) );
}
/**
* @param faceInfo
* @param edgeInfos
*
* @return true if the input face and the current strip share an edge
*/
boolean sharesEdge( FaceInfo faceInfo, ArrayList< EdgeInfo > edgeInfos )
{
//check v0.v1 edge
EdgeInfo currEdge = Stripifier.findEdgeInfo( edgeInfos, faceInfo.m_v0, faceInfo.m_v1 );
if ( isInStrip( currEdge.m_face0 ) || isInStrip( currEdge.m_face1 ) )
return true;
//check v1.v2 edge
currEdge = Stripifier.findEdgeInfo( edgeInfos, faceInfo.m_v1, faceInfo.m_v2 );
if ( isInStrip( currEdge.m_face0 ) || isInStrip( currEdge.m_face1 ) )
return true;
//check v2.v0 edge
currEdge = Stripifier.findEdgeInfo( edgeInfos, faceInfo.m_v2, faceInfo.m_v0 );
if ( isInStrip( currEdge.m_face0 ) || isInStrip( currEdge.m_face1 ) )
return true;
return false;
}
}