// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.library;

import static net.cellcomputing.himawari.library.CqStats.STATS_INC;
import static net.cellcomputing.himawari.library.RiGlobal.QGetRenderContext;
import static net.cellcomputing.himawari.library.EqIntIndex.GPR_subdiv;
import static net.cellcomputing.himawari.library.EqVariableClass.class_facevarying;
import static net.cellcomputing.himawari.library.EqVariableClass.class_uniform;
import static net.cellcomputing.himawari.library.EqVariableClass.class_varying;
import static net.cellcomputing.himawari.library.EqVariableClass.class_vertex;
import static net.cellcomputing.himawari.library.EqVariableType.type_color;
import static net.cellcomputing.himawari.library.EqVariableType.type_float;
import static net.cellcomputing.himawari.library.EqVariableType.type_hpoint;
import static net.cellcomputing.himawari.library.EqVariableType.type_integer;
import static net.cellcomputing.himawari.library.EqVariableType.type_matrix;
import static net.cellcomputing.himawari.library.EqVariableType.type_normal;
import static net.cellcomputing.himawari.library.EqVariableType.type_point;
import static net.cellcomputing.himawari.library.EqVariableType.type_string;
import static net.cellcomputing.himawari.library.EqVariableType.type_vector;

import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.HashMap;

import net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.accessory.Vector;
import net.cellcomputing.himawari.accessory.primitive.p_float;
import net.cellcomputing.himawari.accessory.primitive.p_int;
import net.cellcomputing.himawari.library.types.CqColor;
import net.cellcomputing.himawari.library.types.CqMatrix;
import net.cellcomputing.himawari.library.types.CqVector3D;
import net.cellcomputing.himawari.library.types.CqVector4D;
import net.cellcomputing.himawari.util.AccessSupplier;
import net.cellcomputing.himawari.util.HimawariLogger;

/**
 * 
 *	Container for the topology description of a mesh.
 *	Holds information about which Laths represent which facets and vertices, and 
 *  provides functions to build topology data structures from unstructured meshes.
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqSubdivision2 extends CqMotionSpec<CqPolygonPoints> {

	
	/// Array of pointers to laths, one each representing each facet.
	private Vector<CqLath>				m_apFacets		= new Vector<CqLath>();
	/// Array of arrays of pointers to laths each array representing the total laths referencing a single vertex.
	private STLVector< Vector<CqLath> >	m_aapVertices	= new STLVector<Vector<CqLath>>( (Class<? extends Vector<CqLath>>) Vector.class );
	/// Array of lath pointers, one for each lath generated.
	private Vector<CqLath>				m_apLaths		= new Vector<CqLath>();
	/// Map of face indices which are to be treated as holes in the surface, i.e. not rendered.
	private HashMap<Integer, Boolean>		m_mapHoles		= new HashMap<Integer, Boolean>();
	/// Flag indicating whether this surface interpolates it's boundaries or not.
	private boolean						m_bInterpolateBoundary;
	/// Map of sharp edges.
	private HashMap<CqLath, Float>			m_mapSharpEdges	= new HashMap<CqLath, Float>();
	/// Map of sharp corners.
	private HashMap<CqLath, Float>			m_mapSharpCorners	= new HashMap<CqLath, Float>();
	

    /// Flag indicating whether the topology structures have been finalised.
	private boolean						m_fFinalised;

	
    ///	Constructor.
    public CqSubdivision2( )
    {
    	super( (CqPolygonPoints)null, CqPolygonPoints.class );
        m_bInterpolateBoundary = false;
        m_fFinalised = false;
    }
    
    ///	Constructor.
    public CqSubdivision2( final CqPolygonPoints pPoints )
    {
    	super(pPoints);
    	m_bInterpolateBoundary = false;
    	m_fFinalised = false;
    	
    	// Store the reference to our points.
    	AddTimeSlot( 0, pPoints );
    	
    	STATS_INC( GPR_subdiv );
    }

    ///	Destructor.
//    virtual ~CqSubdivision2();
    
    /**
     *	Get a pointer to a lath referencing the specified facet index.
     *	The returned lath pointer can be any lath on the edge of the facet.
     *	Asserts if the facet index is invalid.
     *
     *	@param	iIndex	Index of the facet to query.
     *
     *	@return			Pointer to a lath on the facet.
     */
    public CqLath pFacet(int iIndex)
    {
        assert(iIndex < m_apFacets.size());
        return(m_apFacets.get(iIndex));
    }
    
    /**
     *	Get a pointer to a lath which references the specified vertex index.
     *	The returned lath pointer can be any lath which references the vertex.
     *	Asserts if the vertex index is invalid.
     *
     *	@param	iIndex	Index of the vertex to query.
     *
     *	@return			Pointer to a lath on the vertex.
     */
    public CqLath pVertex(int iIndex)
    {
        assert(iIndex < m_aapVertices.size() && m_aapVertices.get(iIndex).size() >= 1);
        return(m_aapVertices.get(iIndex).get(0));
    }
    
    /// Get the number of faces representing this topology.
    public int	cFacets() 	{return(m_apFacets.size());}
    /// Get the number of laths representing this topology.
    public int	cLaths() 	{return(m_apLaths.size());}
    /// Get the number of faces representing this topology.
    public int	cVertices() {return(m_aapVertices.size());}
    
    /// Get a refrence to the array of autoatically generated laths.
    public Vector<CqLath> apLaths()
    {return(m_apLaths);}
    
    /// Get pointer to the vertex storage class
    public CqPolygonPoints pPoints( int TimeIndex )
    {
    	return ( GetMotionObject( Time( TimeIndex ) ) );
    }
    final public CqPolygonPoints pPoints(){
    	return pPoints( 0 );
    }

    /**
     *	Initialise the topology class to store the specified number of vertices.
     *	Use this function to prepare the topology structure to receive a number of
     *	vertices then use SetVertex to initialise them.
     *
     *	@param	cVerts	Then number of vertices that will be needed.
     */
    public void Prepare(int cVerts)
    {
    	// Initialise the array of vertex indexes to the appropriate size.
    	m_aapVertices.resize(cVerts);
    	
    	m_fFinalised=false;
    }

    /**
     *	Add a new facet to the topology structure.
     *	Adds the facet by adding new laths for the specified vertex indices, and
     *	linking them to each other clockwise about the facet. By convention, as
     *	outside of the topology structure facets are stored counter clockwise, the
     *	vertex indices should be passed to this function as counter clockwise and
     *	they will be internally altered to specify the facet as clockwise.
     *
     *	@param	cVerts		The number of vertices in the facet.
     *	@param	pIndices	Pointer to an array of vertex indices.
     *
     *	@return				Pointer to one of the laths which represent this new
     *						facet in the topology structure.
     */
    public CqLath AddFacet(int cVerts,int[] pIndices, int iFVIndex)
    {
        CqLath pLastLath=null;
        CqLath pFirstLath=null;
        // Add the laths for this facet, referencing the appropriate vertexes as we go.
        for(int iVert = 0; iVert < cVerts; iVert++)
        {
            CqLath pNewLath = new CqLath();
            pNewLath.SetVertexIndex(pIndices[iVert]);
            pNewLath.SetFaceVertexIndex(iFVIndex+iVert);

            if(pLastLath!=null)
                pNewLath.SetpClockwiseFacet(pLastLath);

            m_apLaths.add(pNewLath);
            pLastLath = pNewLath;
            if(iVert == 0)	pFirstLath = pLastLath;

            // We also need to keep up to date a complete list of which laths refer to which
            // vertices to aid us in finalising the topology structure later.
            m_aapVertices.get(pIndices[iVert]).add(pLastLath);
        }
        // complete the chain by linking the last one as the next clockwise one to the first.
        pFirstLath.SetpClockwiseFacet(pLastLath);

        // Add the start lath in as the one referring to this facet in the list.
        m_apFacets.add(pFirstLath);

        return(pFirstLath);
    }

    /**
     *	Finalise the linkage of the laths.
     *	After adding vertices and facets, call this to complete the linkage of the
     *	laths. To overcome any non-manifold areas in the mesh, this function may
     *	change the topology in order to produce a manifold mesh, or series of
     *	manifold meshes. This also means that all facets in the mesh may no longer
     *	be joined in a complete loop, so care must be taken when traversing the
     *	topology to ensure that all facets are processed.
     */
    public boolean Finalise()
    {
        for( Vector<CqLath> ivert : m_aapVertices )
        {
            int cLaths = (ivert).size();

            // If there is only one lath, it can't be connected to anything.
            if(cLaths<=1)	continue;

            // Create an array for the laths on this vertex that have been visited.
//            STLVector<Boolean>  aVisited;
//            aVisited.setSize(cLaths);
            boolean[] aVisited = new boolean[cLaths];
            int cVisited = 0;

            // Initialise it to all false.
//            aVisited.assign(cLaths, false);		//Javaならデフォルトでfalse。

            CqLath pCurrent = (ivert).get(0);
            CqLath pStart = pCurrent;
//            int iCurrent = 0;
            int iStart = 0;

            boolean fDone = false;
            while(!fDone)
            {
                // Find a clockwise vertex match for the counterclockwise vertex index of this lath.
                int ccwVertex = pCurrent.ccf().VertexIndex();
                int iLath = 0;
                for(iLath = 0; iLath < cLaths; iLath++)
                {
                    // Only check non-visited laths.
                    if(!aVisited[iLath] && (ivert).get(iLath).cf().VertexIndex() == ccwVertex)
                    {
                        pCurrent.SetpClockwiseVertex((ivert).get(iLath));
                        pCurrent = (ivert).get(iLath);
//                        iCurrent = iLath;
                        // Mark the linked to lath as visited.
                        aVisited[iLath] = true;
                        cVisited++;

                        break;
                    }
                }
                // If we didn't find a match then we are done.
                fDone = iLath==cLaths;
            }

            // If the last lath wasn't linked, then we have a boundary condition, so
            // start again from the initial lath and process backwards.
            if(null == pCurrent.cv())
            {
                fDone = false;
                while(!fDone)
                {
                    // Find a counterclockwise vertex match for the clockwise vertex index of this lath.
                    int cwVertex = pStart.cf().VertexIndex();
                    int iLath = 0;
                    for(iLath = 0; iLath < cLaths; iLath++)
                    {
                        // Only check non-visited laths.
                        if(!aVisited[iLath] && (ivert).get(iLath).ccf().VertexIndex() == cwVertex)
                        {
                            // Link the current to the match.
                        	(ivert).get(iLath).SetpClockwiseVertex(pStart);
                            // Mark the linked to lath as visited.
                            aVisited[iStart] = true;
                            cVisited++;
                            pStart = (ivert).get(iLath);
                            iStart = iLath;

                            break;
                        }
                    }
                    // If we didn't find a match then we are done.
                    fDone = iLath==cLaths;
                }
            }
            aVisited[iStart] = true;
            cVisited++;
            // If we have not visited all the laths referencing this vertex, then we have a non-manifold situation.
            if(cVisited < cLaths)
            {
                return( false );
            }
        }

        m_fFinalised = true;
        return( true );
    }
    
    private static int modulo( int a, int b){
    	return (a * b >= 0 ? a % b : (a % b) + b);
    }

    public void SubdivideFace(CqLath pFace, Vector<CqLath> apSubFaces)
    {
        assert(pFace!=null);

        // If this has already beed subdivided then skip it.
        if( pFace.pFaceVertex()!=null )
        {
            apSubFaces.clear();
            Vector<CqLath> aQvf = new Vector<CqLath>();
            pFace.pFaceVertex().Qvf(aQvf);
            // Fill in the lath pointers to the same laths that reference the faces in the topology list. This ensures that
            // the dicing routine will still get the lath it expects in the corner for reading data out.
            for( CqLath iVF : aQvf )
                apSubFaces.add( (iVF).ccf().ccf() );
            return;
        }

        // First make sure that the appropriate neighbour facets have been subdivided if this is >0 level face.
        if( pFace.pParentFacet()!=null )
        {
    		// loop through all our neighbour faces.
    		// we don't use Qff here because we can handle multiple copies
    		// of each face faster than it can.
    		Vector<CqLath> parentVertices = new Vector<CqLath>();
    		pFace.pParentFacet().Qfv( parentVertices );

//    		Vector<CqLath>::iterator vertexIt;
//    		Vector<CqLath>::iterator vertexEnd = parentVertices.end();
    		for( CqLath vertexIt : parentVertices )
    		{
    			CqLath vertex = vertexIt;
    			Vector<CqLath> vertexFaces = new Vector<CqLath>();
    			vertex.Qvf( vertexFaces );

//    			Vector<CqLath>::iterator faceIt;
//    			Vector<CqLath>::iterator faceEnd = vertexFaces.end();
    			for( CqLath faceIt : vertexFaces )
    			{
    				CqLath face = (faceIt);
    				if( null == face.pFaceVertex() )
    				{
    					Vector<CqLath> dummySubFaces = new Vector<CqLath>();
    					SubdivideFace(face, dummySubFaces);
    				}
    			}
    		}
    	}

        Vector<CqLath> aQfv = new Vector<CqLath>();
        int[] aVertices;
        int[] aFVertices;

        pFace.Qfv(aQfv);
        int n = aQfv.size();

//        aVertices.setSize((2*n)+1);
//        aFVertices.setSize((2*n)+1);
        aVertices = new int[(2*n)+1];
        aFVertices = new int[(2*n)+1];
        
        // Clear the return array for subdface indices.
        apSubFaces.clear();

        // First of all setup the points.
        int i;

        // Create new point for the face midpoint.
        p_int iVert=new p_int(-1), iFVert=new p_int(-1);
        AddFaceVertex(pFace, iVert, iFVert);

        // Store the index, for later lath creation
        aVertices[2*n] = iVert.value;
        aFVertices[2*n] = iFVert.value;

        // Create new points for the edge midpoints.
        for(i = 0; i < n; i++)
        {
//            int iVert=-1, iFVert=-2;
        	iVert.value = -1; iFVert.value = -2;
            // Create new vertices for the edge mid points.
            if( null != aQfv.get(i).ec() && null != aQfv.get(i).ec().pMidVertex() )
                // There is already a next level vertex for this, so reuse the 'vertex' class index.
                iVert.value = aQfv.get(i).ec().pMidVertex().VertexIndex();
            // Create new vertex for the edge midpoint.
            AddEdgeVertex(aQfv.get(i), iVert, iFVert);

            // Store the index, for later lath creation
            aVertices[i+n] = iVert.value;
            aFVertices[i+n] = iFVert.value;
        }

        // Create new points for the existing vertices
        for(i = 0; i < n; i++)
        {
//            int iVert=-1, iFVert=-3;
        	iVert.value = -1; iFVert.value = -3;
            // Create new vertices for the original points.
            if( aQfv.get(i).pChildVertex() != null )
                // There is already a next level vertex for this, so reuse the 'vertex' class index.
                iVert.value = aQfv.get(i).pChildVertex().VertexIndex();

            // Create a new vertex for the next level
            AddVertex(aQfv.get(i), iVert, iFVert);

            // Store the index, for later lath creation
            aVertices[i] = iVert.value;
            aFVertices[i] = iFVert.value;
        }

        // Now create new laths for the new facets
//        std::vector<SqFaceLathList>	apFaceLaths;
//        apFaceLaths.setSize(n);
        SqFaceLathList[] apFaceLaths = new SqFaceLathList[n];
        for( int idx=0; idx<n; idx++ )	apFaceLaths[idx] = new SqFaceLathList();

        for( i = 0; i < n; i++ )
        {
            // For each facet, create 4 laths and join them in the order of the facet
            CqLath pLathA = apFaceLaths[i].pA = new CqLath( aVertices[i], aFVertices[i] );
            m_apLaths.add(pLathA);
            CqLath pLathB = apFaceLaths[i].pB = new CqLath( aVertices[(modulo((i+1),n))+n], aFVertices[(modulo((i+1),n))+n] );
            m_apLaths.add(pLathB);
            CqLath pLathC = apFaceLaths[i].pC = new CqLath( aVertices[2*n], aFVertices[2*n] );
            m_apLaths.add(pLathC);
            CqLath pLathD = apFaceLaths[i].pD = new CqLath( aVertices[i+n], aFVertices[i+n] );
            m_apLaths.add(pLathD);
            pLathA.SetpClockwiseFacet(pLathB);
            pLathB.SetpClockwiseFacet(pLathC);
            pLathC.SetpClockwiseFacet(pLathD);
            pLathD.SetpClockwiseFacet(pLathA);
            pLathA.SetpParentFacet(pFace);
            pLathB.SetpParentFacet(pFace);
            pLathC.SetpParentFacet(pFace);
            pLathD.SetpParentFacet(pFace);

            // Fill in the vertex references table for these vertices.
            m_aapVertices.get(pLathA.VertexIndex()).add(pLathA);
            m_aapVertices.get(pLathB.VertexIndex()).add(pLathB);
            m_aapVertices.get(pLathC.VertexIndex()).add(pLathC);
            m_aapVertices.get(pLathD.VertexIndex()).add(pLathD);

            // Set the child vertex pointer for all laths which reference the A vertex of this facet
            // so that we can use them when subdividing other faces.
            CqLath pNextV = aQfv.get(i);
            do
            {
                pNextV.SetpChildVertex(pLathA);
                pNextV = pNextV.cv();
            }while( pNextV != null && pNextV != aQfv.get(i));
            // Make sure that if we have hit a boundary, we go backwards from the start point until we hit the boundary that
            // way as well.
            if(null == pNextV)
            {
                pNextV = aQfv.get(i).ccv();
                // We know we are going to hit a boundary in this direction as well so we can just look for that
                // case as a terminator.
                while( pNextV != null )
                {
                    assert( pNextV != aQfv.get(i) );
                    pNextV.SetpChildVertex(pLathA);
                    pNextV = pNextV.ccv();
                }
            }

            // For this edge of the original face, set a ponter to the new midpoint lath, so that we can
            // use it when subdividing neighbour facets.
            aQfv.get(i).SetpMidVertex(pLathD);

            // Transfer sharpness information
            float sharpness = EdgeSharpness( aQfv.get(i) );
            if( sharpness > 0.0f )
                AddSharpEdge( pLathA, sharpness * sharpness );

            sharpness = EdgeSharpness( aQfv.get( modulo( (i+1),n ) ) );
            if( sharpness > 0.0f )
                AddSharpEdge( pLathB, sharpness * sharpness );

            if( CornerSharpness( aQfv.get(i) ) > 0.0f )
                AddSharpCorner( pLathA, CornerSharpness( aQfv.get(i) ) );

            //【改】aqsis1.01変更・追加***********************************************************
            // Store a lath reference for the facet.
            CqLath pLathF = pLathA;
    		int reorder = i;
    		while( reorder-- > 0)	
    			pLathF = pLathF.ccf();
    		//*****追加部終わり***********************************************
            apSubFaces.add( pLathF );
            m_apFacets.add( pLathF );
           
        }

        // Now connect up the laths we have created.
        // The clcckwise face connections will have already been made, we need to fixup and clockwise
        // vertex connections we can.
        for( i = 0; i < n; i++ )
        {
            // Set the facet point reference for all laths representing this facet.
            aQfv.get(i).SetpFaceVertex(apFaceLaths[i].pC);
            // Connect midpoints clockwise vertex pointers.
            apFaceLaths[((i+1)%n)].pD.SetpClockwiseVertex( apFaceLaths[i].pB );
            // Connect all laths around the new face point.
            apFaceLaths[i].pC.SetpClockwiseVertex( apFaceLaths[ ((i+1)%n) ].pC );

            // Connect the new corner vertices, this is only possible if neighbouring facets have previously been
            // subdivided.
//            Vector<CqLath>::iterator iVertLath;
            for( CqLath iVertLath : m_aapVertices.get(apFaceLaths[i].pA.VertexIndex()) )
            {
                if( (iVertLath).cf().VertexIndex() == apFaceLaths[i].pD.VertexIndex() )
                    apFaceLaths[i].pA.SetpClockwiseVertex( (iVertLath ) );
                if( (iVertLath).ccf().VertexIndex() == apFaceLaths[i].pB.VertexIndex() )
                    (iVertLath).SetpClockwiseVertex( apFaceLaths[i].pA );
            }
        }

        for( i = 0; i < n; i++ )
        {
            // Connect the new edge midpoint vertices to any neighbours, this is only possible if neighbouring facets have previously been
            // subdivided.
//            Vector<CqLath>::iterator iVertLath;
            for( CqLath iVertLath : m_aapVertices.get(apFaceLaths[i].pB.VertexIndex()) )
            {
                if( (iVertLath).cf().VertexIndex() == apFaceLaths[i].pA.VertexIndex() )
                    apFaceLaths[i].pB.SetpClockwiseVertex( (iVertLath ) );
            }
            for( CqLath iVertLath : m_aapVertices.get(apFaceLaths[i].pD.VertexIndex()) )
            {
                if( (iVertLath).ccf().VertexIndex() == apFaceLaths[i].pA.VertexIndex() )
                    (iVertLath ).SetpClockwiseVertex( apFaceLaths[i].pD );
            }
        }
        //OutputInfo("out.dat");

    }

    /**
     * Determine if the topology surrounding the specified face is suitable for
     * conversion to a bicubic patch.
     */

    public boolean CanUsePatch( CqLath pFace )
    {
        // If the patch is a quad with each corner having valence 4, and no special features,
        // we can just create a B-Spline patch.
        if( pFace.cQfv() != 4 )
            return( false );

        Vector<CqLath> aQff = new Vector<CqLath>();
        Vector<CqLath> aQfv = new Vector<CqLath>();;
        pFace.Qfv(aQfv);
//        std::vector<CqLath*>::iterator iFV;
        for( CqLath iFV : aQfv )
        {
            // Check if all vertices are valence 4.
            if( (iFV).cQvv() != 4 )
                return( false );

            // Check if all edges incident on the face vertices are smooth.
            Vector<CqLath> aQve = new Vector<CqLath>();
            (iFV).Qve(aQve);
//            std::vector<CqLath*>::iterator iVE;
            for( CqLath iVE : aQve )
            {
                if( EdgeSharpness((iVE)) != 0.0f ||
                        CornerSharpness((iVE)) != 0.0f )
                    return( false );
            }

            // Check if no internal boundaries.
            CqLath pEnd = (iFV).cv();
            while( (iFV) != pEnd )
            {
                if( null == pEnd )
                    return( false );
                pEnd = pEnd.cv();
            }
        }

        // Check local neighbourhood of patch is 9 quads.
        pFace.Qff(aQff);
        if( aQff.size() != 9 )
            return( false );

//        std::vector<CqLath*>::iterator iFF;
        for( CqLath iFF : aQff )
        {
            if( (iFF).cQfv() != 4 )
                return( false );
        }

        // Finally check if the "facevarying" indexes match, as patches can't have
        // different facevarying indexes across the parameter lines.
        for( CqLath iFV : aQfv )
        {
        	Vector<CqLath> aQvv = new Vector<CqLath>();;
            (iFV).Qvv(aQvv);
            // We already know this must have 4 entries to have passed the previous tests.
            if( !( aQvv.get(0).FaceVertexIndex() == aQvv.get(1).FaceVertexIndex() == (aQvv.get(2).FaceVertexIndex()==0?false:true) == (aQvv.get(3).FaceVertexIndex()==0?false:true) ) )
                return( false );

            // Check the edge parameter lines from this face vertex.
            if( (iFV).ccv().ccf().FaceVertexIndex() != (iFV).ccv().ccf().ccv().FaceVertexIndex() )
                return( false );
            if( (iFV).ccv().ccv().ccf().FaceVertexIndex() != (iFV).ccv().ccv().ccf().ccv().FaceVertexIndex() )
                return( false );
        }

        return( true );
    }

    public void SetInterpolateBoundary( boolean state )
    {
        m_bInterpolateBoundary = state;
    }
    public final void SetInterpolateBoundary(){
    	SetInterpolateBoundary( true );
    }
    public boolean	 isInterpolateBoundary( )
    {
        return( m_bInterpolateBoundary );
    }
    public void SetHoleFace( int iFaceIndex )
    {
        m_mapHoles.put( iFaceIndex, true );
    }
    public boolean isHoleFace( int iFaceIndex )
    {
//        return( m_mapHoles.find( iFaceIndex ) != m_mapHoles.end() );
    	return m_mapHoles.containsKey( iFaceIndex );
    }
    public void AddSharpEdge( CqLath pLath, float Sharpness )
    {
        m_mapSharpEdges.put( pLath, Sharpness );
    }
    public float EdgeSharpness( CqLath pLath )
    {
//        if( m_mapSharpEdges.find( pLath ) != m_mapSharpEdges.end() )
    	if( m_mapSharpEdges.containsKey( pLath ) )
            return( m_mapSharpEdges.get( pLath ) );
        return( 0.0f );
    }
    public void AddSharpCorner( CqLath pLath, float Sharpness )
    {
        Vector<CqLath> aQve = new Vector<CqLath>();
        pLath.Qve( aQve );
//        std::vector<CqLath*>::iterator iVE;
        for( CqLath iVE : aQve )
            m_mapSharpCorners.put( iVE, Sharpness );
    }
    public float CornerSharpness( CqLath pLath )
    {
//        if( m_mapSharpCorners.find( pLath ) != m_mapSharpCorners.end() )
    	if( m_mapSharpCorners.containsKey( pLath ) )
            return( m_mapSharpCorners.get( pLath ) );
        return( 0.0f );
    }

    /**
     *	Add a completely new vertex to the list.
     *	Appends a new vertex to the end of the list, updating the referencing
     *	table as well.
     *
     *	@return			The index of the new point.
     */
    public void AddVertex(CqLath pVertex, p_int iVIndex, p_int iFVIndex)
    {
        iFVIndex.value=0;

        // If -1 is passed in as the 'vertex' class index, we must create a new value.
        boolean fNewVertex = iVIndex.value < 0;

//        std::vector<CqParameter*>::iterator iUP;
        int iTime;

        for( iTime = 0; iTime < iTimes(); iTime++ )
        {
//            for( iUP = pPoints( iTime ).aUserParams().begin(); iUP != pPoints( iTime ).aUserParams().end(); iUP++ )
        	for( CqParameter iUP : pPoints( iTime ).aUserParams() )
            {
                int iIndex = ( iUP ).Size();
                // Store the index in the return variable based on its type.
                if( ( iUP ).Class().getValue() == class_vertex || ( iUP ).Class().getValue() == class_varying )
                {
                    if( fNewVertex )
                    {
                        assert( iVIndex.value<0 || iVIndex.value==iIndex );
                        iVIndex.value = iIndex;
                        ( iUP ).SetSize( iIndex+1 );
                        // Resize the vertex lath
                        m_aapVertices.resize(iVIndex.value+1);
                    }
                    else
                        continue;
                }
                else if( ( iUP ).Class().getValue() == class_facevarying )
                {
                    assert( iFVIndex.value==0 || iFVIndex.value==iIndex );
                    iFVIndex.value = iIndex;
                    ( iUP ).SetSize( iIndex+1 );
                }
    			else
    				continue;

                switch ( ( iUP ).Type().getValue() )
                {
                case type_float:
                    {
                        CqParameterTyped<p_float, p_float> pParam = (CqParameterTyped<p_float, p_float>)( ( iUP ) );
                        CreateVertexFloat( pParam, pVertex, iIndex );
                    }
                    break;

                case type_integer:
                    {
                        CqParameterTyped<p_int, p_float> pParam = (CqParameterTyped<p_int, p_float>)( ( iUP ) );
                        CreateVertexInt( pParam, pVertex, iIndex );
                    }
                    break;

                case type_point:
                case type_normal:
                case type_vector:
                    {
                        CqParameterTyped<CqVector3D, CqVector3D> pParam = (CqParameterTyped<CqVector3D, CqVector3D>)( ( iUP ) );
                        CreateVertexVec3D( pParam, pVertex, iIndex );
                    }
                    break;

                case type_color:
                    {
                        CqParameterTyped<CqColor, CqColor> pParam = (CqParameterTyped<CqColor, CqColor>)( ( iUP ) );
                        CreateVertexColor( pParam, pVertex, iIndex );
                    }
                    break;

                case type_hpoint:
                    {
                        CqParameterTyped<CqVector4D, CqVector3D> pParam = (CqParameterTyped<CqVector4D, CqVector3D>)( ( iUP ) );
                        CreateVertexVec4D( pParam, pVertex, iIndex );
                    }
                    break;

                case type_string:
                    {
                        //CqParameterTyped<CqString, CqString>* pParam = (CqParameterTyped<CqString, CqString>*>( ( iUP ) );
                        //CreateVertex( pParam, pVertex, iIndex );
                    }
                    break;

                case type_matrix:
                    {
                        //CqParameterTyped<CqMatrix, CqMatrix>* pParam = (CqParameterTyped<CqMatrix, CqMatrix>*>( ( iUP ) );
                        //CreateVertex( pParam, pVertex, iIndex );
                    }
                    break;

                default:
                    {
                        // left blank to avoid compiler warnings about unhandled types
                    }
                    break;
                }

            }
        }
    }
    
    public void CreateVertexFloat(CqParameterTyped<p_float, p_float> pParam, CqLath pVertex, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			p_float S = new p_float(0.0f);
			p_float Q = new p_float(0.0f);
			p_float R = new p_float(0.0f);
			int n;

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				// Determine if we have a boundary vertex.
				if( pVertex.isBoundaryVertex() )
				{
					// The vertex is on a boundary.
					/// \note If "interpolateboundary" is not specified, we will never see this as
					/// the boundary facets aren't rendered. So we don't need to check for "interpolateboundary" here.
					Vector<CqLath> apQve = new Vector<CqLath>();
					pVertex.Qve(apQve);
					// Is the valence == 2 ?
					if( apQve.size() == 2 )
					{
						// Yes, boundary with valence 2 is corner.
						((p_float)pParam.pValue_get( iIndex ,arrayindex)).value = ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
					}
					else
					{
						// No, boundary is average of two adjacent boundary edges, and original point.
						// Get the midpoints of the adjacent boundary edges
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						int cBoundaryEdges = 0;
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							// Only consider the boundary edges.
							if( null == (iE).ec() )
							{
								if( (iE).VertexIndex() == invokeMethod(pVertex,IndexFunction) )
									R.value += ((p_float)pParam.pValue_get( invokeMethod((iE).ccf(),IndexFunction) ,arrayindex)).value;
								else
									R.value += ((p_float)pParam.pValue_get( invokeMethod((iE),IndexFunction) ,arrayindex)).value;
								cBoundaryEdges++;
							}
						}
						assert( cBoundaryEdges == 2 );

						// Get the current vertex;
						S.value = ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
						((p_float)pParam.pValue_get( iIndex ,arrayindex)).value = ( R.value + ( S.value * 6.0f ) ) / 8.0f;
					}
				}
				else
				{
					// Check if a sharp corner vertex.
					if( CornerSharpness( pVertex ) > 0.0f )
					{
						((p_float)pParam.pValue_get( iIndex ,arrayindex)).value = ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
					}
					else
					{
						// Check if crease vertex.
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						CqLath hardEdge1 = null;
						CqLath hardEdge2 = null;
						CqLath hardEdge3 = null;
						int se = 0;
//						std::vector<CqLath*>::iterator iEdge;
						for( CqLath iEdge : aQve )
						{
							float h = EdgeSharpness( (iEdge) );
							if( hardEdge1 == null || h > EdgeSharpness(hardEdge1) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = hardEdge1;
								hardEdge1 = iEdge;
							}
							else if( hardEdge2 == null || h > EdgeSharpness(hardEdge2) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = iEdge;
							}
							else if( hardEdge3 == null || h > EdgeSharpness(hardEdge3) )
							{
								hardEdge3 = iEdge;
							}

							if( h > 0.0f )
							{
								se++;
								//		printf("h = %f\n", h);
							}
						}

						p_float softPos			= new p_float();
						p_float semiSharpPos	= new p_float();
						p_float sharpPos		= new p_float();
						// Smooth
						// Vertex point is...
						//    Q     2R     S(n-3)
						//   --- + ---- + --------
						//    n      n        n
						//
						// Q = Average of face points surrounding old vertex
						// R = average of midpoints of edges surrounding old vertex
						// S = old vertex
						// n = number of edges sharing the old vertex.

						n = aQve.size();

						// Get the face points of the surrounding faces
						Vector<CqLath> aQvf = new Vector<CqLath>();
						pVertex.Qvf( aQvf );
//						std::vector<CqLath*>::iterator iF;
						for( CqLath iF : aQvf )
						{
							Vector<CqLath> aQfv = new Vector<CqLath>();
							(iF).Qfv(aQfv);
//							std::vector<CqLath*>::iterator iV;
							p_float Val = new p_float(0.0f);
							for( CqLath iV : aQfv )
								Val.value += ((p_float)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)).value;
							Val.value = Val.value / ( aQfv.size() );
							Q.value += Val.value;
						}
						Q.value /= aQvf.size();
						Q.value /= n;

						// Get the midpoints of the surrounding edges
						p_float A = new p_float( ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value );
						p_float B = new p_float(0.0f);
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							B.value = ((p_float)pParam.pValue_get( invokeMethod(iE.ccf(),IndexFunction) ,arrayindex)).value;
							R.value += (A.value+B.value)/2.0f;
						}
						R.value = R.value * 2.0f;
						R.value /= n;
						R.value /= n;

						// Get the current vertex;
						S.value = ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
						S.value = S.value * (n-3);
						S.value /= n;

						//pParam.pValue_get( iIndex ,0) = Q+R+S;
						softPos.value = Q.value+R.value+S.value;

						if( se >= 2 )
						{
							// Crease
							// Get the midpoints of the surrounding 2 hardest edges
							R.value = ((p_float)pParam.pValue_get( invokeMethod(hardEdge1.ccf(),IndexFunction) ,arrayindex)).value;
							R.value = R.value + ((p_float)pParam.pValue_get( invokeMethod(hardEdge2.ccf(),IndexFunction) ,arrayindex)).value;

							// Get the current vertex;
							S.value = ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
							semiSharpPos.value = ( R.value + ( S.value * 6.0f ) ) / 8.0f;
						}

						sharpPos.value = ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;

						// Blend the three values together weighted by the sharpness values.
						p_float Pos = new p_float();
						float h2 = hardEdge2 != null ? EdgeSharpness(hardEdge2) : 0.0f;
						float h3 = hardEdge3 != null ? EdgeSharpness(hardEdge3) : 0.0f;
						Pos.value = (1.0f - h2)*softPos.value;
						Pos.value = Pos.value + (h2 - h3)*semiSharpPos.value;
						Pos.value = Pos.value + h3*sharpPos.value;
						((p_float)pParam.pValue_get( iIndex ,arrayindex)).value = Pos.value;
					}
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				p_float A = new p_float( ((p_float)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value );
				((p_float)pParam.pValue_get( iIndex ,arrayindex)).value = A.value;
			}
		}
    }
    
    public void CreateVertexInt(CqParameterTyped<p_int, p_float> pParam, CqLath pVertex, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			p_int S = new p_int(0);
			p_int Q = new p_int(0);
			p_int R = new p_int(0);
			int n;

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				// Determine if we have a boundary vertex.
				if( pVertex.isBoundaryVertex() )
				{
					// The vertex is on a boundary.
					/// \note If "interpolateboundary" is not specified, we will never see this as
					/// the boundary facets aren't rendered. So we don't need to check for "interpolateboundary" here.
					Vector<CqLath> apQve = new Vector<CqLath>();
					pVertex.Qve(apQve);
					// Is the valence == 2 ?
					if( apQve.size() == 2 )
					{
						// Yes, boundary with valence 2 is corner.
						((p_int)pParam.pValue_get( iIndex ,arrayindex)).value = ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
					}
					else
					{
						// No, boundary is average of two adjacent boundary edges, and original point.
						// Get the midpoints of the adjacent boundary edges
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						int cBoundaryEdges = 0;
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							// Only consider the boundary edges.
							if( null == (iE).ec() )
							{
								if( (iE).VertexIndex() == invokeMethod(pVertex,IndexFunction) )
									R.value += ((p_int)pParam.pValue_get( invokeMethod((iE).ccf(),IndexFunction) ,arrayindex)).value;
								else
									R.value += ((p_int)pParam.pValue_get( invokeMethod((iE),IndexFunction) ,arrayindex)).value;
								cBoundaryEdges++;
							}
						}
						assert( cBoundaryEdges == 2 );

						// Get the current vertex;
						S.value = ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
						((p_int)pParam.pValue_get( iIndex ,arrayindex)).value = ( R.value + ( S.value * 6 ) ) / 8;
					}
				}
				else
				{
					// Check if a sharp corner vertex.
					if( CornerSharpness( pVertex ) > 0.0f )
					{
						((p_int)pParam.pValue_get( iIndex ,arrayindex)).value = ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
					}
					else
					{
						// Check if crease vertex.
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						CqLath hardEdge1 = null;
						CqLath hardEdge2 = null;
						CqLath hardEdge3 = null;
						int se = 0;
//						std::vector<CqLath*>::iterator iEdge;
						for( CqLath iEdge : aQve )
						{
							float h = EdgeSharpness( (iEdge) );
							if( hardEdge1 == null || h > EdgeSharpness(hardEdge1) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = hardEdge1;
								hardEdge1 = iEdge;
							}
							else if( hardEdge2 == null || h > EdgeSharpness(hardEdge2) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = iEdge;
							}
							else if( hardEdge3 == null || h > EdgeSharpness(hardEdge3) )
							{
								hardEdge3 = iEdge;
							}

							if( h > 0.0f )
							{
								se++;
								//		printf("h = %f\n", h);
							}
						}

						p_int softPos			= new p_int();
						p_int semiSharpPos	= new p_int();
						p_int sharpPos		= new p_int();
						// Smooth
						// Vertex point is...
						//    Q     2R     S(n-3)
						//   --- + ---- + --------
						//    n      n        n
						//
						// Q = Average of face points surrounding old vertex
						// R = average of midpoints of edges surrounding old vertex
						// S = old vertex
						// n = number of edges sharing the old vertex.

						n = aQve.size();

						// Get the face points of the surrounding faces
						Vector<CqLath> aQvf = new Vector<CqLath>();
						pVertex.Qvf( aQvf );
//						std::vector<CqLath*>::iterator iF;
						for( CqLath iF : aQvf )
						{
							Vector<CqLath> aQfv = new Vector<CqLath>();
							(iF).Qfv(aQfv);
//							std::vector<CqLath*>::iterator iV;
							p_int Val = new p_int(0);
							for( CqLath iV : aQfv )
								Val.value += ((p_int)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)).value;
							Val.value = Val.value / ( aQfv.size() );
							Q.value += Val.value;
						}
						Q.value /= aQvf.size();
						Q.value /= n;

						// Get the midpoints of the surrounding edges
						p_int A = new p_int( ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value );
						p_int B = new p_int(0);
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							B.value = ((p_int)pParam.pValue_get( invokeMethod(iE.ccf(),IndexFunction) ,arrayindex)).value;
							R.value += (A.value+B.value)/2.0f;
						}
						R.value = R.value * 2;
						R.value /= n;
						R.value /= n;

						// Get the current vertex;
						S.value = ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
						S.value = S.value * (n-3);
						S.value /= n;

						//pParam.pValue_get( iIndex ,0) = Q+R+S;
						softPos.value = Q.value+R.value+S.value;

						if( se >= 2 )
						{
							// Crease
							// Get the midpoints of the surrounding 2 hardest edges
							R.value = ((p_int)pParam.pValue_get( invokeMethod(hardEdge1.ccf(),IndexFunction) ,arrayindex)).value;
							R.value = R.value + ((p_int)pParam.pValue_get( invokeMethod(hardEdge2.ccf(),IndexFunction) ,arrayindex)).value;

							// Get the current vertex;
							S.value = ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;
							semiSharpPos.value = ( R.value + ( S.value * 6 ) ) / 8;
						}

						sharpPos.value = ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value;

						// Blend the three values together weighted by the sharpness values.
						p_int Pos = new p_int();
						int h2 = hardEdge2 != null ? (int)EdgeSharpness(hardEdge2) : 0;
						int h3 = hardEdge3 != null ? (int)EdgeSharpness(hardEdge3) : 0;
						Pos.value = (1 - h2)*softPos.value;
						Pos.value = Pos.value + (h2 - h3)*semiSharpPos.value;
						Pos.value = Pos.value + h3*sharpPos.value;
						((p_int)pParam.pValue_get( iIndex ,arrayindex)).value = Pos.value;
					}
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				p_int A = new p_int( ((p_int)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)).value );
				((p_int)pParam.pValue_get( iIndex ,arrayindex)).value = A.value;
			}
		}
    }
    
    public void CreateVertexVec3D(CqParameterTyped<CqVector3D, CqVector3D> pParam, CqLath pVertex, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			CqVector3D S = new CqVector3D(0.0f);
			CqVector3D Q = new CqVector3D(0.0f);
			CqVector3D R = new CqVector3D(0.0f);
			int n;

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				// Determine if we have a boundary vertex.
				if( pVertex.isBoundaryVertex() )
				{
					// The vertex is on a boundary.
					/// \note If "interpolateboundary" is not specified, we will never see this as
					/// the boundary facets aren't rendered. So we don't need to check for "interpolateboundary" here.
					Vector<CqLath> apQve = new Vector<CqLath>();
					pVertex.Qve(apQve);
					// Is the valence == 2 ?
					if( apQve.size() == 2 )
					{
						// Yes, boundary with valence 2 is corner.
						((CqVector3D)pParam.pValue_get( iIndex ,arrayindex)).assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
					}
					else
					{
						// No, boundary is average of two adjacent boundary edges, and original point.
						// Get the midpoints of the adjacent boundary edges
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						int cBoundaryEdges = 0;
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							// Only consider the boundary edges.
							if( null == (iE).ec() )
							{
								if( (iE).VertexIndex() == invokeMethod(pVertex,IndexFunction) )
									R.assignAdd( ((CqVector3D)pParam.pValue_get( invokeMethod((iE).ccf(),IndexFunction) ,arrayindex)) );
								else
									R.assignAdd( ((CqVector3D)pParam.pValue_get( invokeMethod((iE),IndexFunction) ,arrayindex)) );
								cBoundaryEdges++;
							}
						}
						assert( cBoundaryEdges == 2 );

						// Get the current vertex;
						S.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						((CqVector3D)pParam.pValue_get( iIndex ,arrayindex)).assignment( R.add( ( S.mul( 6.0f ) ) ) .div( 8.0f ) );
					}
				}
				else
				{
					// Check if a sharp corner vertex.
					if( CornerSharpness( pVertex ) > 0.0f )
					{
						((CqVector3D)pParam.pValue_get( iIndex ,arrayindex)).assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
					}
					else
					{
						// Check if crease vertex.
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						CqLath hardEdge1 = null;
						CqLath hardEdge2 = null;
						CqLath hardEdge3 = null;
						int se = 0;
//						std::vector<CqLath*>::iterator iEdge;
						for( CqLath iEdge : aQve )
						{
							float h = EdgeSharpness( (iEdge) );
							if( hardEdge1 == null || h > EdgeSharpness(hardEdge1) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = hardEdge1;
								hardEdge1 = iEdge;
							}
							else if( hardEdge2 == null || h > EdgeSharpness(hardEdge2) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = iEdge;
							}
							else if( hardEdge3 == null || h > EdgeSharpness(hardEdge3) )
							{
								hardEdge3 = iEdge;
							}

							if( h > 0.0f )
							{
								se++;
								//		printf("h = %f\n", h);
							}
						}

						CqVector3D softPos		= new CqVector3D();
						CqVector3D semiSharpPos	= new CqVector3D();
						CqVector3D sharpPos		= new CqVector3D();
						// Smooth
						// Vertex point is...
						//    Q     2R     S(n-3)
						//   --- + ---- + --------
						//    n      n        n
						//
						// Q = Average of face points surrounding old vertex
						// R = average of midpoints of edges surrounding old vertex
						// S = old vertex
						// n = number of edges sharing the old vertex.

						n = aQve.size();

						// Get the face points of the surrounding faces
						Vector<CqLath> aQvf = new Vector<CqLath>();
						pVertex.Qvf( aQvf );
//						std::vector<CqLath*>::iterator iF;
						for( CqLath iF : aQvf )
						{
							Vector<CqLath> aQfv = new Vector<CqLath>();
							(iF).Qfv(aQfv);
//							std::vector<CqLath*>::iterator iV;
							CqVector3D Val = new CqVector3D(0.0f);
							for( CqLath iV : aQfv )
								Val.assignAdd( ((CqVector3D)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
							Val.assignment( Val.div( ( aQfv.size() ) ) );
							Q.assignAdd( Val );
						}
						Q.assignDiv( aQvf.size() );
						Q.assignDiv( n );

						// Get the midpoints of the surrounding edges
						CqVector3D A = new CqVector3D( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						CqVector3D B = new CqVector3D(0.0f);
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							B.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(iE.ccf(),IndexFunction) ,arrayindex)) );
							R.assignAdd( (A.add(B)).div(2.0f) );
						}
						R.assignment( R.mul( 2.0f ) );
						R.assignDiv( n );
						R.assignDiv( n );

						// Get the current vertex;
						S.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						S.assignment( S.mul( (n-3) ) );
						S.assignDiv( n );

						//pParam.pValue_get( iIndex ,0) = Q+R+S;
						softPos.assignment( Q.add(R).add(S) );

						if( se >= 2 )
						{
							// Crease
							// Get the midpoints of the surrounding 2 hardest edges
							R.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(hardEdge1.ccf(),IndexFunction) ,arrayindex)) );
							R.assignment( R.add( ((CqVector3D)pParam.pValue_get( invokeMethod(hardEdge2.ccf(),IndexFunction) ,arrayindex)) ) );

							// Get the current vertex;
							S.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
							semiSharpPos.assignment( ( R.add( ( S.mul( 6.0f ) ) ) ).div( 8.0f ) );
						}

						sharpPos.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );

						// Blend the three values together weighted by the sharpness values.
						CqVector3D Pos = new CqVector3D();
						float h2 = hardEdge2 != null ? EdgeSharpness(hardEdge2) : 0.0f;
						float h3 = hardEdge3 != null ? EdgeSharpness(hardEdge3) : 0.0f;
						Pos.assignment( softPos.mul( 1.0f - h2 ) );
						Pos.assignment( Pos.add( semiSharpPos.mul( h2 - h3 ) ) );
						Pos.assignment( Pos.add( sharpPos.mul(h3) ) );
						((CqVector3D)pParam.pValue_get( iIndex ,arrayindex)).assignment( Pos );
					}
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				CqVector3D A = new CqVector3D( ((CqVector3D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
				((CqVector3D)pParam.pValue_get( iIndex ,arrayindex)).assignment( A );
			}
		}
    }
  
    public void CreateVertexVec4D(CqParameterTyped<CqVector4D, CqVector3D> pParam, CqLath pVertex, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			CqVector4D S = new CqVector4D(0,0,0,1);
			CqVector4D Q = new CqVector4D(0,0,0,1);
			CqVector4D R = new CqVector4D(0,0,0,1);
			int n;

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				// Determine if we have a boundary vertex.
				if( pVertex.isBoundaryVertex() )
				{
					// The vertex is on a boundary.
					/// \note If "interpolateboundary" is not specified, we will never see this as
					/// the boundary facets aren't rendered. So we don't need to check for "interpolateboundary" here.
					Vector<CqLath> apQve = new Vector<CqLath>();
					pVertex.Qve(apQve);
					// Is the valence == 2 ?
					if( apQve.size() == 2 )
					{
						// Yes, boundary with valence 2 is corner.
						((CqVector4D)pParam.pValue_get( iIndex ,arrayindex)).assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
					}
					else
					{
						// No, boundary is average of two adjacent boundary edges, and original point.
						// Get the midpoints of the adjacent boundary edges
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						int cBoundaryEdges = 0;
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							// Only consider the boundary edges.
							if( null == (iE).ec() )
							{
								if( (iE).VertexIndex() == invokeMethod(pVertex,IndexFunction) )
									R.assignAdd( ((CqVector4D)pParam.pValue_get( invokeMethod((iE).ccf(),IndexFunction) ,arrayindex)) );
								else
									R.assignAdd( ((CqVector4D)pParam.pValue_get( invokeMethod((iE),IndexFunction) ,arrayindex)) );
								cBoundaryEdges++;
							}
						}
						assert( cBoundaryEdges == 2 );

						// Get the current vertex;
						S.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						((CqVector4D)pParam.pValue_get( iIndex ,arrayindex)).assignment( R.add( ( S.mul( 6.0f ) ) ) .div( 8.0f ) );
					}
				}
				else
				{
					// Check if a sharp corner vertex.
					if( CornerSharpness( pVertex ) > 0.0f )
					{
						((CqVector4D)pParam.pValue_get( iIndex ,arrayindex)).assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
					}
					else
					{
						// Check if crease vertex.
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						CqLath hardEdge1 = null;
						CqLath hardEdge2 = null;
						CqLath hardEdge3 = null;
						int se = 0;
//						std::vector<CqLath*>::iterator iEdge;
						for( CqLath iEdge : aQve )
						{
							float h = EdgeSharpness( (iEdge) );
							if( hardEdge1 == null || h > EdgeSharpness(hardEdge1) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = hardEdge1;
								hardEdge1 = iEdge;
							}
							else if( hardEdge2 == null || h > EdgeSharpness(hardEdge2) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = iEdge;
							}
							else if( hardEdge3 == null || h > EdgeSharpness(hardEdge3) )
							{
								hardEdge3 = iEdge;
							}

							if( h > 0.0f )
							{
								se++;
								//		printf("h = %f\n", h);
							}
						}

						CqVector4D softPos		= new CqVector4D();
						CqVector4D semiSharpPos	= new CqVector4D();
						CqVector4D sharpPos		= new CqVector4D();
						// Smooth
						// Vertex point is...
						//    Q     2R     S(n-3)
						//   --- + ---- + --------
						//    n      n        n
						//
						// Q = Average of face points surrounding old vertex
						// R = average of midpoints of edges surrounding old vertex
						// S = old vertex
						// n = number of edges sharing the old vertex.

						n = aQve.size();

						// Get the face points of the surrounding faces
						Vector<CqLath> aQvf = new Vector<CqLath>();
						pVertex.Qvf( aQvf );
//						std::vector<CqLath*>::iterator iF;
						for( CqLath iF : aQvf )
						{
							Vector<CqLath> aQfv = new Vector<CqLath>();
							(iF).Qfv(aQfv);
//							std::vector<CqLath*>::iterator iV;
							CqVector4D Val = new CqVector4D(0,0,0,1);
							for( CqLath iV : aQfv )
								Val.assignAdd( ((CqVector4D)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
							Val.assignment( Val.div( ( aQfv.size() ) ) );
							Q.assignAdd( Val );
						}
						Q.assignDiv( aQvf.size() );
						Q.assignDiv( n );

						// Get the midpoints of the surrounding edges
						CqVector4D A = new CqVector4D( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						CqVector4D B = new CqVector4D(0,0,0,1);
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							B.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(iE.ccf(),IndexFunction) ,arrayindex)) );
							R.assignAdd( (A.add(B)).div(2.0f) );
						}
						R.assignment( R.mul( 2.0f ) );
						R.assignDiv( n );
						R.assignDiv( n );

						// Get the current vertex;
						S.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						S.assignment( S.mul( (n-3) ) );
						S.assignDiv( n );

						//pParam.pValue_get( iIndex ,0) = Q+R+S;
						softPos.assignment( Q.add(R).add(S) );

						if( se >= 2 )
						{
							// Crease
							// Get the midpoints of the surrounding 2 hardest edges
							R.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(hardEdge1.ccf(),IndexFunction) ,arrayindex)) );
							R.assignment( R.add( ((CqVector4D)pParam.pValue_get( invokeMethod(hardEdge2.ccf(),IndexFunction) ,arrayindex)) ) );

							// Get the current vertex;
							S.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
							semiSharpPos.assignment( ( R.add( ( S.mul( 6.0f ) ) ) ).div( 8.0f ) );
						}

						sharpPos.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );

						// Blend the three values together weighted by the sharpness values.
						CqVector4D Pos = new CqVector4D();
						float h2 = hardEdge2 != null ? EdgeSharpness(hardEdge2) : 0.0f;
						float h3 = hardEdge3 != null ? EdgeSharpness(hardEdge3) : 0.0f;
						Pos.assignment( softPos.mul( 1.0f - h2 ) );
						Pos.assignment( Pos.add( semiSharpPos.mul( h2 - h3 ) ) );
						Pos.assignment( Pos.add( sharpPos.mul(h3) ) );
						((CqVector4D)pParam.pValue_get( iIndex ,arrayindex)).assignment( Pos );
					}
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				CqVector4D A = new CqVector4D( ((CqVector4D)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
				((CqVector4D)pParam.pValue_get( iIndex ,arrayindex)).assignment( A );
			}
		}
    }
   
    public void CreateVertexColor(CqParameterTyped<CqColor, CqColor> pParam, CqLath pVertex, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			CqColor S = new CqColor(0.0f);
			CqColor Q = new CqColor(0.0f);
			CqColor R = new CqColor(0.0f);
			int n;

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				// Determine if we have a boundary vertex.
				if( pVertex.isBoundaryVertex() )
				{
					// The vertex is on a boundary.
					/// \note If "interpolateboundary" is not specified, we will never see this as
					/// the boundary facets aren't rendered. So we don't need to check for "interpolateboundary" here.
					Vector<CqLath> apQve = new Vector<CqLath>();
					pVertex.Qve(apQve);
					// Is the valence == 2 ?
					if( apQve.size() == 2 )
					{
						// Yes, boundary with valence 2 is corner.
						((CqColor)pParam.pValue_get( iIndex ,arrayindex)).assignment( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
					}
					else
					{
						// No, boundary is average of two adjacent boundary edges, and original point.
						// Get the midpoints of the adjacent boundary edges
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						int cBoundaryEdges = 0;
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							// Only consider the boundary edges.
							if( null == (iE).ec() )
							{
								if( (iE).VertexIndex() == invokeMethod(pVertex,IndexFunction) )
									R.assignAdd( ((CqColor)pParam.pValue_get( invokeMethod((iE).ccf(),IndexFunction) ,arrayindex)) );
								else
									R.assignAdd( ((CqColor)pParam.pValue_get( invokeMethod((iE),IndexFunction) ,arrayindex)) );
								cBoundaryEdges++;
							}
						}
						assert( cBoundaryEdges == 2 );

						// Get the current vertex;
						S.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						((CqColor)pParam.pValue_get( iIndex ,arrayindex)).assignment( R.add( ( S.mul( 6.0f ) ) ) .div( 8.0f ) );
					}
				}
				else
				{
					// Check if a sharp corner vertex.
					if( CornerSharpness( pVertex ) > 0.0f )
					{
						((CqColor)pParam.pValue_get( iIndex ,arrayindex)).assignment( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
					}
					else
					{
						// Check if crease vertex.
						Vector<CqLath> aQve = new Vector<CqLath>();
						pVertex.Qve( aQve );

						CqLath hardEdge1 = null;
						CqLath hardEdge2 = null;
						CqLath hardEdge3 = null;
						int se = 0;
//						std::vector<CqLath*>::iterator iEdge;
						for( CqLath iEdge : aQve )
						{
							float h = EdgeSharpness( (iEdge) );
							if( hardEdge1 == null || h > EdgeSharpness(hardEdge1) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = hardEdge1;
								hardEdge1 = iEdge;
							}
							else if( hardEdge2 == null || h > EdgeSharpness(hardEdge2) )
							{
								hardEdge3 = hardEdge2;
								hardEdge2 = iEdge;
							}
							else if( hardEdge3 == null || h > EdgeSharpness(hardEdge3) )
							{
								hardEdge3 = iEdge;
							}

							if( h > 0.0f )
							{
								se++;
								//		printf("h = %f\n", h);
							}
						}

						CqColor softPos		= new CqColor();
						CqColor semiSharpPos	= new CqColor();
						CqColor sharpPos		= new CqColor();
						// Smooth
						// Vertex point is...
						//    Q     2R     S(n-3)
						//   --- + ---- + --------
						//    n      n        n
						//
						// Q = Average of face points surrounding old vertex
						// R = average of midpoints of edges surrounding old vertex
						// S = old vertex
						// n = number of edges sharing the old vertex.

						n = aQve.size();

						// Get the face points of the surrounding faces
						Vector<CqLath> aQvf = new Vector<CqLath>();
						pVertex.Qvf( aQvf );
//						std::vector<CqLath*>::iterator iF;
						for( CqLath iF : aQvf )
						{
							Vector<CqLath> aQfv = new Vector<CqLath>();
							(iF).Qfv(aQfv);
//							std::vector<CqLath*>::iterator iV;
							CqColor Val = new CqColor(0.0f);
							for( CqLath iV : aQfv )
								Val.assignAdd( ((CqColor)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
							Val.assignment( Val.div( ( aQfv.size() ) ) );
							Q.assignAdd( Val );
						}
						Q.assignDiv( aQvf.size() );
						Q.assignDiv( n );

						// Get the midpoints of the surrounding edges
						CqColor A = new CqColor( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						CqColor B = new CqColor(0.0f);
//						std::vector<CqLath*>::iterator iE;
						for( CqLath iE : aQve )
						{
							B.assignment( ((CqColor)pParam.pValue_get( invokeMethod(iE.ccf(),IndexFunction) ,arrayindex)) );
							R.assignAdd( (A.add(B)).div(2.0f) );
						}
						R.assignment( R.mul( 2.0f ) );
						R.assignDiv( n );
						R.assignDiv( n );

						// Get the current vertex;
						S.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
						S.assignment( S.mul( (n-3) ) );
						S.assignDiv( n );

						//pParam.pValue_get( iIndex ,0) = Q+R+S;
						softPos.assignment( Q.add(R).add(S) );

						if( se >= 2 )
						{
							// Crease
							// Get the midpoints of the surrounding 2 hardest edges
							R.assignment( ((CqColor)pParam.pValue_get( invokeMethod(hardEdge1.ccf(),IndexFunction) ,arrayindex)) );
							R.assignment( R.add( ((CqColor)pParam.pValue_get( invokeMethod(hardEdge2.ccf(),IndexFunction) ,arrayindex)) ) );

							// Get the current vertex;
							S.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
							semiSharpPos.assignment( ( R.add( ( S.mul( 6.0f ) ) ) ).div( 8.0f ) );
						}

						sharpPos.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );

						// Blend the three values together weighted by the sharpness values.
						CqColor Pos = new CqColor();
						float h2 = hardEdge2 != null ? EdgeSharpness(hardEdge2) : 0.0f;
						float h3 = hardEdge3 != null ? EdgeSharpness(hardEdge3) : 0.0f;
						Pos.assignment( softPos.mul( 1.0f - h2 ) );
						Pos.assignment( Pos.add( semiSharpPos.mul( h2 - h3 ) ) );
						Pos.assignment( Pos.add( sharpPos.mul(h3) ) );
						((CqColor)pParam.pValue_get( iIndex ,arrayindex)).assignment( Pos );
					}
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				int (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				CqColor A = new CqColor( ((CqColor)pParam.pValue_get( invokeMethod(pVertex,IndexFunction) ,arrayindex)) );
				((CqColor)pParam.pValue_get( iIndex ,arrayindex)).assignment( A );
			}
		}
    }
  
  
    /**
     *	Add a completely new vertex to the list.
     *	Appends a new vertex to the end of the list, updating the referencing
     *	table as well.
     *
     *	@return			The index of the new point.
     */
    public void AddEdgeVertex(CqLath pVertex, p_int iVIndex, p_int iFVIndex )
    {
        iFVIndex.value=0;

        // If -1 is passed in as the 'vertex' class index, we must create a new value.
        boolean fNewVertex = iVIndex.value < 0;

//        std::vector<CqParameter*>::iterator iUP;
        int iTime;

        for( iTime = 0; iTime < iTimes(); iTime ++ )
        {
//            for ( iUP = pPoints( iTime ).aUserParams().begin(); iUP != pPoints( iTime ).aUserParams().end(); iUP++ )
        	for( CqParameter iUP : pPoints( iTime ).aUserParams() )
            {
                int iIndex = ( iUP ).Size();
                // Store the index in the return variable based on its type.
                if( ( iUP ).Class().getValue() == class_vertex || ( iUP ).Class().getValue() == class_varying )
                {
                    if( fNewVertex )
                    {
                        assert( iVIndex.value<0 || iVIndex.value==iIndex );
                        iVIndex.value=iIndex;
                        ( iUP ).SetSize( iIndex+1 );
                        // Resize the vertex lath
                        m_aapVertices.resize(iVIndex.value+1);
                    }
                    else
                        continue;
                }
                else if( ( iUP ).Class().getValue() == class_facevarying )
                {
                    assert( iFVIndex.value==0 || iFVIndex.value==iIndex );
                    iFVIndex.value = iIndex;
                    ( iUP ).SetSize( iIndex+1 );
                }
    			else
    				continue;

                switch ( ( iUP ).Type().getValue() )
                {
                case type_float:
                    {
                        CqParameterTyped<p_float, p_float> pParam = (CqParameterTyped<p_float, p_float>)( ( iUP ) );
                        CreateEdgeVertexFloat( pParam, pVertex, iIndex );
                    }
                    break;

                case type_integer:
                    {
                        CqParameterTyped<p_int, p_float> pParam = (CqParameterTyped<p_int, p_float>)( ( iUP ) );
                        CreateEdgeVertexInt( pParam, pVertex, iIndex );
                    }
                    break;

                case type_point:
                case type_normal:
                case type_vector:
                    {
                        CqParameterTyped<CqVector3D, CqVector3D> pParam = (CqParameterTyped<CqVector3D, CqVector3D>)( ( iUP ) );
                        CreateEdgeVertexVec3D( pParam, pVertex, iIndex );
                    }
                    break;

                case type_color:
                    {
                        CqParameterTyped<CqColor, CqColor> pParam = (CqParameterTyped<CqColor, CqColor>)( ( iUP ) );
                        CreateEdgeVertexColor( pParam, pVertex, iIndex );
                    }
                    break;

                case type_hpoint:
                    {
                        CqParameterTyped<CqVector4D, CqVector3D> pParam = (CqParameterTyped<CqVector4D, CqVector3D>)( ( iUP ) );
                        CreateEdgeVertexVec4D( pParam, pVertex, iIndex );
                    }
                    break;

                case type_string:
                    {
                        //CqParameterTyped<CqString, CqString>* pParam = (CqParameterTyped<CqString, CqString>*>( ( iUP ) );
                        //CreateEdgeVertex( pParam, pVertex, iIndex );
                    }
                    break;

                case type_matrix:
                    {
                        //CqParameterTyped<CqMatrix, CqMatrix>* pParam = (CqParameterTyped<CqMatrix, CqMatrix>*>( ( iUP ) );
                        //CreateEdgeVertex( pParam, pVertex, iIndex );
                    }
                    break;

                default:
                    {
                        // left blank to avoid compiler warnings about unhandled types
                    }
                    break;
                }
            }
        }
    }

    public void CreateEdgeVertexFloat(CqParameterTyped<p_float, p_float> pParam, CqLath pEdge, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			p_float A = new p_float(0.0f);
			p_float B = new p_float(0.0f);
			p_float C = new p_float(0.0f);

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*Index/Function)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				if( null != pEdge.ec() )
				{
					// Edge point is the average of the centrepoint of the original edge and the
					// average of the two new face points of the adjacent faces.
					Vector<CqLath> aQef = new Vector<CqLath>();
					pEdge.Qef( aQef );
//					std::vector<CqLath*>::iterator iF;
					for( CqLath iF : aQef )
					{
						Vector<CqLath> aQfv = new Vector<CqLath>();
						(iF).Qfv(aQfv);
//						std::vector<CqLath*>::iterator iV;
						p_float Val = new p_float(0.0f);
						for( CqLath iV : aQfv )
							Val.value += ((p_float)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)).value;
						Val.value = Val.value / ( aQfv.size() );
						C.value += Val.value;
					}
					C.value = C.value / (aQef.size());

					A.value = ((p_float)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)).value;
					B.value = ((p_float)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)).value;

					float h = EdgeSharpness( pEdge );
					A.value = ((1.0f+h)*(A.value+B.value)) / 2.0f;
					A.value = (A.value + (1.0f-h)*C.value) / 2.0f;
				}
				else
				{
					A.value = ((p_float)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)).value;
					B.value = ((p_float)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)).value;
					A.value = (A.value+B.value)/2.0f;
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				A.value = ((p_float)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)).value;
				B.value = ((p_float)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)).value;
				A.value = (A.value+B.value)/2.0f;
			}
			((p_float)pParam.pValue_get( iIndex ,arrayindex)).value = A.value;
		}
    }
    
    public void CreateEdgeVertexInt(CqParameterTyped<p_int, p_float> pParam, CqLath pEdge, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			p_int A = new p_int(0);
			p_int B = new p_int(0);
			p_int C = new p_int(0);

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*Index/Function)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				if( null != pEdge.ec() )
				{
					// Edge point is the average of the centrepoint of the original edge and the
					// average of the two new face points of the adjacent faces.
					Vector<CqLath> aQef = new Vector<CqLath>();
					pEdge.Qef( aQef );
//					std::vector<CqLath*>::iterator iF;
					for( CqLath iF : aQef )
					{
						Vector<CqLath> aQfv = new Vector<CqLath>();
						(iF).Qfv(aQfv);
//						std::vector<CqLath*>::iterator iV;
						p_int Val = new p_int(0);
						for( CqLath iV : aQfv )
							Val.value += ((p_int)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)).value;
						Val.value = Val.value / ( aQfv.size() );
						C.value += Val.value;
					}
					C.value = C.value / (aQef.size());

					A.value = ((p_int)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)).value;
					B.value = ((p_int)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)).value;

					int h = (int)EdgeSharpness( pEdge );
					A.value = ((1+h)*(A.value+B.value)) / 2;
					A.value = (A.value + (1-h)*C.value) / 2;
				}
				else
				{
					A.value = ((p_int)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)).value;
					B.value = ((p_int)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)).value;
					A.value = (A.value+B.value)/2;
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				A.value = ((p_int)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)).value;
				B.value = ((p_int)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)).value;
				A.value = (A.value+B.value)/2;
			}
			((p_int)pParam.pValue_get( iIndex ,arrayindex)).value = A.value;
		}
    }
 
    public void CreateEdgeVertexVec3D(CqParameterTyped<CqVector3D, CqVector3D> pParam, CqLath pEdge, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			CqVector3D A = new CqVector3D(0.0f);
			CqVector3D B = new CqVector3D(0.0f);
			CqVector3D C = new CqVector3D(0.0f);

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*Index/Function)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				if( null != pEdge.ec() )
				{
					// Edge point is the average of the centrepoint of the original edge and the
					// average of the two new face points of the adjacent faces.
					Vector<CqLath> aQef = new Vector<CqLath>();
					pEdge.Qef( aQef );
//					std::vector<CqLath*>::iterator iF;
					for( CqLath iF : aQef )
					{
						Vector<CqLath> aQfv = new Vector<CqLath>();
						(iF).Qfv(aQfv);
//						std::vector<CqLath*>::iterator iV;
						CqVector3D Val = new CqVector3D(0.0f);
						for( CqLath iV : aQfv )
							Val.assignAdd( ((CqVector3D)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
						Val.assignment( Val.div( ( aQfv.size() ) ) );
						C.assignAdd( Val );
					}
					C.assignment( C.div( aQef.size() ) );

					A.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
					B.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );

					float h = EdgeSharpness( pEdge );
					A.assignment( ( (A.add(B)).mul(1.0f+h) ).div( 2.0f ) );
					A.assignment( (A.add( C.mul(1.0f-h) )).div( 2.0f ) );
				}
				else
				{
					A.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
					B.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );
					A.assignment( (A.add(B)).div(2.0f) );
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				A.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
				B.assignment( ((CqVector3D)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );
				A.assignment( (A.add(B)).div(2.0f) );
			}
			((CqVector3D)pParam.pValue_get( iIndex ,arrayindex)).assignment( A );
		}
    }
   
    public void CreateEdgeVertexVec4D(CqParameterTyped<CqVector4D, CqVector3D> pParam, CqLath pEdge, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			CqVector4D A = new CqVector4D(0,0,0,1);
			CqVector4D B = new CqVector4D(0,0,0,1);
			CqVector4D C = new CqVector4D(0,0,0,1);

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*Index/Function)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				if( null != pEdge.ec() )
				{
					// Edge point is the average of the centrepoint of the original edge and the
					// average of the two new face points of the adjacent faces.
					Vector<CqLath> aQef = new Vector<CqLath>();
					pEdge.Qef( aQef );
//					std::vector<CqLath*>::iterator iF;
					for( CqLath iF : aQef )
					{
						Vector<CqLath> aQfv = new Vector<CqLath>();
						(iF).Qfv(aQfv);
//						std::vector<CqLath*>::iterator iV;
						CqVector4D Val = new CqVector4D(0,0,0,1);
						for( CqLath iV : aQfv )
							Val.assignAdd( ((CqVector4D)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
						Val.assignment( Val.div( ( aQfv.size() ) ) );
						C.assignAdd( Val );
					}
					C.assignment( C.div( aQef.size() ) );

					A.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
					B.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );

					float h = EdgeSharpness( pEdge );
					A.assignment( ( (A.add(B)).mul(1.0f+h) ).div( 2.0f ) );
					A.assignment( (A.add( C.mul(1.0f-h) )).div( 2.0f ) );
				}
				else
				{
					A.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
					B.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );
					A.assignment( (A.add(B)).div(2.0f) );
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				A.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
				B.assignment( ((CqVector4D)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );
				A.assignment( (A.add(B)).div(2.0f) );
			}
			((CqVector4D)pParam.pValue_get( iIndex ,arrayindex)).assignment( A );
		}
    }

    public void CreateEdgeVertexColor(CqParameterTyped<CqColor, CqColor> pParam, CqLath pEdge, int iIndex)
    {
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
			CqColor A = new CqColor(0.0f);
			CqColor B = new CqColor(0.0f);
			CqColor C = new CqColor(0.0f);

			if(pParam.Class().getValue() == class_vertex /*|| pParam.Class() == class_facevarying*/)
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*Index/Function)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_vertex )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				if( null != pEdge.ec() )
				{
					// Edge point is the average of the centrepoint of the original edge and the
					// average of the two new face points of the adjacent faces.
					Vector<CqLath> aQef = new Vector<CqLath>();
					pEdge.Qef( aQef );
//					std::vector<CqLath*>::iterator iF;
					for( CqLath iF : aQef )
					{
						Vector<CqLath> aQfv = new Vector<CqLath>();
						(iF).Qfv(aQfv);
//						std::vector<CqLath*>::iterator iV;
						CqColor Val = new CqColor(0.0f);
						for( CqLath iV : aQfv )
							Val.assignAdd( ((CqColor)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
						Val.assignment( Val.div( ( aQfv.size() ) ) );
						C.assignAdd( Val );
					}
					C.assignment( C.div( aQef.size() ) );

					A.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
					B.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );

					float h = EdgeSharpness( pEdge );
					A.assignment( ( (A.add(B)).mul(1.0f+h) ).div( 2.0f ) );
					A.assignment( (A.add( C.mul(1.0f-h) )).div( 2.0f ) );
				}
				else
				{
					A.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
					B.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );
					A.assignment( (A.add(B)).div(2.0f) );
				}
			}
			else
			{
				// Get a pointer to the appropriate index accessor function on CqLath based on class.
//				TqInt (CqLath::*IndexFunction)() const;
				String IndexFunction;
				if( pParam.Class().getValue() == class_varying )
					IndexFunction = "VertexIndex";
//					IndexFunction = &CqLath::VertexIndex;
				else
					IndexFunction = "FaceVertexIndex";
//					IndexFunction = &CqLath::FaceVertexIndex;

				A.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pEdge,IndexFunction) ,arrayindex)) );
				B.assignment( ((CqColor)pParam.pValue_get( invokeMethod(pEdge.ccf(),IndexFunction) ,arrayindex)) );
				A.assignment( (A.add(B)).div(2.0f) );
			}
			((CqColor)pParam.pValue_get( iIndex ,arrayindex)).assignment( A );
		}
    }
   
    
   
    /**
     *	Add a completely new vertex to the list.
     *	Appends a new vertex to the end of the list, updating the referencing
     *	table as well.
     *
     *	@return			The index of the new point.
     */
    public void AddFaceVertex(CqLath pVertex, p_int iVIndex, p_int iFVIndex)
    {
        iVIndex.value=0;
        iFVIndex.value=0;

//        std::vector<CqParameter*>::iterator iUP;
        int iTime;

        for( iTime = 0; iTime < iTimes(); iTime++ )
        {
            for ( CqParameter iUP : pPoints( iTime ).aUserParams() )
            {
                if( ( iUP ).Class().getValue() == class_uniform )
    				continue;

                int iIndex = ( iUP ).Size();
                ( iUP ).SetSize( iIndex+1 );
                // Store the index in the return variable based on its type.
                if( ( iUP ).Class().getValue() == class_vertex || ( iUP ).Class().getValue() == class_varying )
                {
                    assert( iVIndex.value==0 || iVIndex.value==iIndex );
                    iVIndex.value = iIndex;
                }
                else if( ( iUP ).Class().getValue() == class_facevarying )
                {
                    assert( iFVIndex.value==0 || iFVIndex.value==iIndex );
                    iFVIndex.value = iIndex;
                }

                switch ( ( iUP ).Type().getValue() )
                {
                case type_float:
                    {
                        CqParameterTyped<p_float, p_float> pParam = (CqParameterTyped<p_float, p_float>)( ( iUP ) );
                        CreateFaceVertexFloat( pParam, pVertex, iIndex );
                    }
                    break;

                case type_integer:
                    {
                        CqParameterTyped<p_int, p_float> pParam = (CqParameterTyped<p_int, p_float>)( ( iUP ) );
                        CreateFaceVertexInt( pParam, pVertex, iIndex );
                    }
                    break;

                case type_point:
                case type_normal:
                case type_vector:
                    {
                        CqParameterTyped<CqVector3D, CqVector3D> pParam = (CqParameterTyped<CqVector3D, CqVector3D>)( ( iUP ) );
                        CreateFaceVertexVec3D( pParam, pVertex, iIndex );
                    }
                    break;

                case type_color:
                    {
                        CqParameterTyped<CqColor, CqColor> pParam = (CqParameterTyped<CqColor, CqColor>)( ( iUP ) );
                        CreateFaceVertexColor( pParam, pVertex, iIndex );
                    }
                    break;

                case type_hpoint:
                    {
                        CqParameterTyped<CqVector4D, CqVector3D> pParam = (CqParameterTyped<CqVector4D, CqVector3D>)( ( iUP ) );
                        CreateFaceVertexVec4D( pParam, pVertex, iIndex );
                    }
                    break;

                case type_string:
                    {
                        //CqParameterTyped<CqString, CqString>* pParam = static_cast<CqParameterTyped<CqString, CqString>*>( ( iUP ) );
                        //CreateFaceVertex( pParam, pVertex, iIndex );
                    }
                    break;

                case type_matrix:
                    {
                        //CqParameterTyped<CqMatrix, CqMatrix>* pParam = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( ( iUP ) );
                        //CreateFaceVertex( pParam, pVertex, iIndex );
                    }
                    break;

                default:
                    {
                        // left blank to avoid compiler warnings about unhandled types
                    }
                    break;
                }

            }
        }

        // Resize the vertex lath
        m_aapVertices.resize(iVIndex.value+1);
    }

    public void CreateFaceVertexFloat(CqParameterTyped<p_float, p_float> pParam, CqLath pFace, int iIndex)
    {
        // Get a pointer to the appropriate index accessor function on CqLath based on class.
//        TqInt (CqLath::*IndexFunction)() const;
    	String IndexFunction;
        if( pParam.Class().getValue() == class_vertex || pParam.Class().getValue() == class_varying)
        	IndexFunction = "VertexIndex";
//            IndexFunction = &CqLath::VertexIndex;
        else
        	IndexFunction = "FaceVertexIndex";
//            IndexFunction = &CqLath::FaceVertexIndex;
        // Face point is just the average of the original faces vertices.
        Vector<CqLath> aQfv = new Vector<CqLath>();
        pFace.Qfv(aQfv);
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
//	        std::vector<CqLath*>::iterator iV;
	        p_float Val = new p_float(0.0f);
			for( CqLath iV : aQfv )
			{
				assert( invokeMethod(iV,IndexFunction) >= 0 &&
						invokeMethod(iV,IndexFunction) < pParam.Size() );
				Val.value += ((p_float)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)).value;
			}
			Val.value = Val.value / ( aQfv.size() );
			((p_float)pParam.pValue_get( iIndex ,arrayindex)).value = Val.value;
		}
    }

    public void CreateFaceVertexInt(CqParameterTyped<p_int, p_float> pParam, CqLath pFace, int iIndex)
    {
        // Get a pointer to the appropriate index accessor function on CqLath based on class.
//        TqInt (CqLath::*IndexFunction)() const;
    	String IndexFunction;
        if( pParam.Class().getValue() == class_vertex || pParam.Class().getValue() == class_varying)
        	IndexFunction = "VertexIndex";
//            IndexFunction = &CqLath::VertexIndex;
        else
        	IndexFunction = "FaceVertexIndex";
//            IndexFunction = &CqLath::FaceVertexIndex;
        // Face point is just the average of the original faces vertices.
        Vector<CqLath> aQfv = new Vector<CqLath>();
        pFace.Qfv(aQfv);
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
//	        std::vector<CqLath*>::iterator iV;
	        p_int Val = new p_int(0);
			for( CqLath iV : aQfv )
			{
				assert( invokeMethod(iV,IndexFunction) >= 0 &&
						invokeMethod(iV,IndexFunction) < pParam.Size() );
				Val.value += ((p_int)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)).value;
			}
			Val.value = Val.value / ( aQfv.size() );
			((p_int)pParam.pValue_get( iIndex ,arrayindex)).value = Val.value;
		}
    }

    public void CreateFaceVertexVec3D(CqParameterTyped<CqVector3D, CqVector3D> pParam, CqLath pFace, int iIndex)
    {
        // Get a pointer to the appropriate index accessor function on CqLath based on class.
//        TqInt (CqLath::*IndexFunction)() const;
    	String IndexFunction;
        if( pParam.Class().getValue() == class_vertex || pParam.Class().getValue() == class_varying)
        	IndexFunction = "VertexIndex";
//            IndexFunction = &CqLath::VertexIndex;
        else
        	IndexFunction = "FaceVertexIndex";
//            IndexFunction = &CqLath::FaceVertexIndex;
        // Face point is just the average of the original faces vertices.
        Vector<CqLath> aQfv = new Vector<CqLath>();
        pFace.Qfv(aQfv);
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
//	        std::vector<CqLath*>::iterator iV;
	        CqVector3D Val = new CqVector3D(0.0f);
			for( CqLath iV : aQfv )
			{
				assert( invokeMethod(iV,IndexFunction) >= 0 &&
						invokeMethod(iV,IndexFunction) < pParam.Size() );
				Val.assignAdd( ((CqVector3D)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
			}
			Val.assignment( Val.div( ( aQfv.size() ) ) );
			((CqVector3D)pParam.pValue_get( iIndex ,arrayindex)).assignment( Val );
		}
    }

    public void CreateFaceVertexVec4D(CqParameterTyped<CqVector4D, CqVector3D> pParam, CqLath pFace, int iIndex)
    {
        // Get a pointer to the appropriate index accessor function on CqLath based on class.
//        TqInt (CqLath::*IndexFunction)() const;
    	String IndexFunction;
        if( pParam.Class().getValue() == class_vertex || pParam.Class().getValue() == class_varying)
        	IndexFunction = "VertexIndex";
//            IndexFunction = &CqLath::VertexIndex;
        else
        	IndexFunction = "FaceVertexIndex";
//            IndexFunction = &CqLath::FaceVertexIndex;
        // Face point is just the average of the original faces vertices.
        Vector<CqLath> aQfv = new Vector<CqLath>();
        pFace.Qfv(aQfv);
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
//	        std::vector<CqLath*>::iterator iV;
	        CqVector4D Val = new CqVector4D(0,0,0,1);
			for( CqLath iV : aQfv )
			{
				assert( invokeMethod(iV,IndexFunction) >= 0 &&
						invokeMethod(iV,IndexFunction) < pParam.Size() );
				Val.assignAdd( ((CqVector4D)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
			}
			Val.assignment( Val.div( ( aQfv.size() ) ) );
			((CqVector4D)pParam.pValue_get( iIndex ,arrayindex)).assignment( Val );
		}
    }

    public void CreateFaceVertexColor(CqParameterTyped<CqColor, CqColor> pParam, CqLath pFace, int iIndex)
    {
        // Get a pointer to the appropriate index accessor function on CqLath based on class.
//        TqInt (CqLath::*IndexFunction)() const;
    	String IndexFunction;
        if( pParam.Class().getValue() == class_vertex || pParam.Class().getValue() == class_varying)
        	IndexFunction = "VertexIndex";
//            IndexFunction = &CqLath::VertexIndex;
        else
        	IndexFunction = "FaceVertexIndex";
//            IndexFunction = &CqLath::FaceVertexIndex;
        // Face point is just the average of the original faces vertices.
        Vector<CqLath> aQfv = new Vector<CqLath>();
        pFace.Qfv(aQfv);
		int arraysize = 0, arrayindex;
		arraysize = pParam.Count();
		for( arrayindex = 0; arrayindex < arraysize; arrayindex++ )
		{
//	        std::vector<CqLath*>::iterator iV;
	        CqColor Val = new CqColor(0.0f);
			for( CqLath iV : aQfv )
			{
				assert( invokeMethod(iV,IndexFunction) >= 0 &&
						invokeMethod(iV,IndexFunction) < pParam.Size() );
				Val.assignAdd( ((CqColor)pParam.pValue_get( invokeMethod(iV,IndexFunction) ,arrayindex)) );
			}
			Val.assignment( Val.div( ( aQfv.size() ) ) );
			((CqColor)pParam.pValue_get( iIndex ,arrayindex)).assignment( Val );
		}
    }

    
    // Overrides from CqMotionSpec
    public void ClearMotionObject(CqPolygonPoints A) 
    {
    }
    public CqPolygonPoints ConcatMotionObjects(CqPolygonPoints A, CqPolygonPoints B) 
    {
    	return ( A );
    }    
    public CqPolygonPoints LinearInterpolateMotionObjects(float Fraction, CqPolygonPoints A, CqPolygonPoints B) 
    {
        return ( A );
    }

    
    public void OutputMesh( final String fname, Vector<CqLath> paFaces )
    {
//        std::ofstream file(fname);
    	PrintStream file;
		try {
			file = new PrintStream(fname);
		} catch (FileNotFoundException e) {
			//開けなかったら標準出力へ
			HimawariLogger.outputException(e);
			file = System.out;
		}
        Vector<CqLath> aQfv = new Vector<CqLath>();

        int i;
        for( i = 0; i < cVertices(); i++ )
        {
            CqVector3D vec = new CqVector3D( (CqVector4D)pPoints().P().pValue_get(0 , pVertex( i ).VertexIndex() ) );
//            file << "v " << vec.x() << " " << vec.y() << " " << vec.z() << std::endl;
            file.println( "v " + vec.x + " " + vec.y + " " + vec.z );
        }


        for(i = 0; i < cFacets(); i++)
        {
            if( null == pFacet(i).pFaceVertex() )
            {
                pFacet(i).Qfv(aQfv);
                int j;
//                file << "f ";
                file.print( "f " );
                for( j = 0; j < aQfv.size(); j++ )
//                    file << aQfv[j).VertexIndex()+1 << " ";
                	file.print( aQfv.get(j).VertexIndex()+1 + " " );
//                file << std::endl;
                file.println();
            }
        }

        if( paFaces!=null )
        {
//            file << "g CurrentFace" << std::endl;
        	file.println( "g CurrentFace" );
            for(i = 0; i < paFaces.size(); i++)
            {
                (paFaces).get(i).Qfv(aQfv);
                int j;
//                file << "f ";
                file.print( "f " );
                for( j = 0; j < aQfv.size(); j++ )
//                    file << aQfv[j).VertexIndex()+1 << " ";
                	file.print( aQfv.get(j).VertexIndex()+1 + " " );
//                file << std::endl;
                file.println();
            }
        }

        file.close();
    }
    public void OutputMesh( final String fname )
    {
    	OutputMesh( fname, null );
    }

    public void OutputInfo( final String fname, Vector<CqLath> paFaces)
    {
//        std::ofstream file(fname);
    	PrintStream file;
    	try {
			file = new PrintStream(fname);
		} catch (FileNotFoundException e) {
			//開けなかったら標準出力へ
			HimawariLogger.outputException(e);
			file = System.out;
		}
//        Vector<CqLath> aQfv = new Vector<CqLath>();

        Vector<CqLath> paLaths = paFaces;

        if( null == paLaths )
            paLaths = m_apFacets;
        
        //【改】aqsis1.01変更・追加********************************
        paLaths = m_apLaths;
        CqMatrix matCameraToObject0 = QGetRenderContext().matSpaceToSpace( 
							        		"camera", "object", 
							        		new CqMatrix(), 
        									pPoints().pTransform().matObjectToWorld(pPoints().pTransform().Time(0)), 
        									pPoints().pTransform().Time(0) 
        									);
        //ここまで********************************************************
        for(int i = 0; i < paLaths.size(); i++)
        {
            CqLath pL = paLaths.get(i);
//            file << i << " - 0x" << pL << " - "	<<
//            pL.VertexIndex() << " - " <<
//            pL.FaceVertexIndex() << " - (cf) ";
//            file.print( i + " - 0x" + pL + " - " +
            file.print( i + " - " + pL + " - " +
              pL.VertexIndex() + " - " +
              pL.FaceVertexIndex() + " - (cf) "
            );
            if( pL.cf()!=null )
//                file << "0x" << pL.cf();
//            	file.print( "0x" + pL.cf() );
            	file.print( "" + pL.cf() );
            else
//                file << "***";
            	file.print( "***" );
//            file << " - (cv) ";
            file.print( " - (cv) " );

            if(pL.cv()!=null)
//                file << "0x" << pL.cv();
//            	file.print( "0x" + pL.cv() );
            	file.print( "" + pL.cv() );
            else
//                file << "***";
            	file.print( "***" );

            //【改】 aqsis 1.01変更追加***********************************
    		CqVector3D vecP = new CqVector3D( (CqVector4D)pPoints().P().pValue_get(pL.VertexIndex(),0) ); 
    		vecP = matCameraToObject0.multiply( vecP );
    		file.print( "[P=" + vecP + ")" );
    		//*********************************************************
            
//            file << std::endl;
            file.println();
        }

        file.close();
    }

    
//    ///	Declared private to prevent copying.
//    private CqSubdivision2(final CqSubdivision2 from){}
//    ///	Declared private to prevent copying.
//    private CqSubdivision2 assignment(final CqSubdivision2 from )	{return null;}
    
    
    
    
    private static Method vertexIndex		= AccessSupplier.getMethod( CqLath.class, "VertexIndex" );
    private static Method faceVertexIndex	= AccessSupplier.getMethod( CqLath.class, "FaceVertexIndex" );
    private int invokeMethod( CqLath instance, String methodName )
    {
    	try{
    		if( methodName.equals("VertexIndex") )
    		{
    			return (Integer)vertexIndex.invoke( instance );
    		}
    		else if( methodName.equals("FaceVertexIndex") )
    		{
    			return (Integer)faceVertexIndex.invoke( instance );
    		}
    	}
    	catch( Exception e ){
    		HimawariLogger.outputException(e);
    	}
    	return 0;
    }

}
