// 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 java.lang.Math.sqrt;
import static net.cellcomputing.himawari.library.CqStats.STATS_INC;
import static net.cellcomputing.himawari.library.EqIntIndex.GPR_poly;
import static net.cellcomputing.himawari.library.Float_h.FLT_MAX;
import net.cellcomputing.himawari.accessory.STLArray;
import net.cellcomputing.himawari.accessory.STLArrayList;
import net.cellcomputing.himawari.accessory.STLVector;
import net.cellcomputing.himawari.accessory.primitive.p_int;
import net.cellcomputing.himawari.library.types.CqVector2D;
import net.cellcomputing.himawari.library.types.CqVector4D;

/**
 * 
 * glyph変換に使用される、通常の２次元のポリゴン。
 * このポリゴンの表現は、要求されたように三角形にするために、
 * 非凸状で穴が開いてあるポリゴンをサポートを許すように設計されます。
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqPolygonGeneral2D {

//	private STLVector<p_int> m_aiVertices	= new STLVector<p_int>(p_int.class);
	private STLArray<p_int> m_aiVertices	= new STLArray<p_int>(p_int.class);
	private int m_Orientation;
	private int m_Axis;
	private CqSurface	m_pVertices;
	private boolean	m_Reverse;
	
	// enum EssAxis
	public static final int Axis_Unknown	= 0;
	public static final int Axis_XY		= 1;
	public static final int Axis_XZ		= 2;
	public static final int Axis_YZ		= 3;
	
	//enum	EssOrientation
	public static final int Orientation_Unknown			= 0;
	public static final int Orientation_Clockwise			= 1;
	public static final int Orientation_AntiClockwise		= 2;
	
	
	
	public CqPolygonGeneral2D()
	{
		m_Orientation	= Orientation_Unknown;
		m_Reverse		= false;
		STATS_INC( GPR_poly );
	}
	
	public CqPolygonGeneral2D( final CqPolygonGeneral2D From )
	{
		this.assignment( From );
	}

//	public STLVector<p_int> aiVertices()
	public STLArray<p_int> aiVertices()
	{
		return ( m_aiVertices );
	}
	public int cVertices()
	{
		return ( m_aiVertices.size() );
	}
	
	public int Orientation()
	{
		return ( m_Orientation );
	}
	
	public int Axis()
	{
		return ( m_Axis );
	}
	
	public void SetAxis( int axis )
	{
		m_Axis = axis;
	}
	
	public void SetpVertices( final CqSurface pVertices )
	{
		m_pVertices = pVertices;
	}

	public void SwapDirection()
	{
	    int vertices2 = cVertices() / 2;
	    int vertices1 = cVertices() - 1;
	    for ( int iVertex = 0; iVertex < vertices2; iVertex++ )
	    {
	        /* Mathematically equivalent */
	        int which = vertices1 - iVertex;
	        int tmp = m_aiVertices.get( iVertex ).value;

	        m_aiVertices.get( iVertex ).value = m_aiVertices.get( which ).value;
	        m_aiVertices.get( which ).value = tmp;
	    }
	    CalcOrientation();
		m_Reverse = !m_Reverse;
	}
	
	public int CalcOrientation()
	{
	    // Calculate the area of this polygon, and
	    // if it is negative the polygon is clockwise.
	    int vertices1 = cVertices() - 1;
//	  高速化オリジナルソース
//	    float	Area = ( this ).valueAt( vertices1 ).x * ( this ).valueAt(  0 ).y -
//	                   ( this ).valueAt( 0 ).x * ( this ).valueAt( vertices1 ).y;
//
//
//	    for ( int iVertex = 0; iVertex < vertices1; iVertex++ )
//	        Area += ( this ).valueAt( iVertex ).x * ( this ).valueAt( iVertex + 1 ).y -
//	                ( this ).valueAt( iVertex + 1 ).x * ( this ).valueAt( iVertex ).y;

//nttdata 案1 高速化 start
	    CqVector2D tmp1,tmp2;
	    tmp1 = ( this ).valueAt( vertices1 );
	    tmp2 = ( this ).valueAt(  0 ) ;
	    float	Area = tmp1.x * tmp2.y - tmp2.x * tmp1.y;
	    for ( int iVertex = 0; iVertex < vertices1; iVertex++ )
	    {
	    	tmp1 = ( this ).valueAt( iVertex );
	    	tmp2 = ( this ).valueAt( iVertex + 1 );
	        Area += tmp1.x * tmp2.y - tmp2.x * tmp1.y;
	    }
	    
//	  nttdata 高速化 end
//	  nttdata 案2 高速化 start
//	    CqVector4D tmp1,tmp2;
//	    tmp1 = ( this ).valueAt4( vertices1 );
//	    tmp2 = ( this ).valueAt4(  0 ) ;
//	    float	Area = tmp1.x * tmp2.y - tmp2.x * tmp1.y;
//	    for ( int iVertex = 0; iVertex < vertices1; iVertex++ )
//	    {
//	    	tmp1 = ( this ).valueAt4( iVertex );
//	    	tmp2 = ( this ).valueAt4( iVertex + 1 );
//	        Area += tmp1.x * tmp2.y - tmp2.x * tmp1.y;
//	    }
//	  nttdata 高速化 end	    
	    if ( Area >= 0.0 )
	        m_Orientation = Orientation_AntiClockwise;
	    else
	        m_Orientation = Orientation_Clockwise;

	    return ( m_Orientation );
	}
	
	public int CalcDeterminant( int i1, int i2, int i3 )
	{
	    assert( i1 >= 0 && i1 <= cVertices() );
	    assert( i2 >= 0 && i2 <= cVertices() );
	    assert( i3 >= 0 && i3 <= cVertices() );

	    // TODO: Look up what a determinant is and therefore, why this works.
//高速化オリジナルソース
//	    float	Determ =   ( ( this ).valueAt( i2 ).x - ( this ).valueAt( i1 ).x )
//	                     * ( ( this ).valueAt( i3 ).y - ( this ).valueAt( i1 ).y )
//	                     - ( ( this ).valueAt( i3 ).x - ( this ).valueAt( i1 ).x )
//	                     * ( ( this ).valueAt( i2 ).y - ( this ).valueAt( i1 ).y );
//nttdata 案1 高速化 change
	    
	    CqVector2D tmp1,tmp2,tmp3;
	    tmp1 = ( this ).valueAt( i1 );
	    tmp2 = ( this ).valueAt( i2 );
	    tmp3 = ( this ).valueAt( i3 );
	    float	Determ =   ( tmp2.x - tmp1.x )
        * (  tmp3.y - tmp1.y )
        - ( tmp3.x - tmp1.x )
        * ( tmp2.y - tmp1.y );
	   
//	  nttdata 高速化 end
//nttdata 案2 高速化 change
	    
//	    CqVector4D tmp1,tmp2,tmp3;
//	    tmp1 = ( this ).valueAt4( i1 );
//	    tmp2 = ( this ).valueAt4( i2 );
//	    tmp3 = ( this ).valueAt4( i3 );
//	    float	Determ =   ( tmp2.x - tmp1.x )
//        * (  tmp3.y - tmp1.y )
//        - ( tmp3.x - tmp1.x )
//        * ( tmp2.y - tmp1.y );
	   
//	  nttdata 高速化 end

	    
	    if ( Determ > 0.0 )
	        return ( Orientation_AntiClockwise );
	    else
	    {
	        if ( Determ == 0.0 )
	        {
				return( Orientation_Unknown );
	            //if ( ( this ) [ i1 ] == ( this ) [ i2 ] ||
	            //     ( this ) [ i1 ] == ( this ) [ i3 ] ||
	            //     ( this ) [ i2 ] == ( this ) [ i3 ] )
	            //    return ( Orientation_AntiClockwise );
	            //else
	            //    return ( Orientation_Clockwise );
	        }
	        else
	            return ( Orientation_Clockwise );
	    }
//	    return ( Orientation_Unknown );
	}
	
//	public boolean NoneInside( int i1, int i2, int i3, STLVector<p_int> iList )
	public boolean NoneInside( int i1, int i2, int i3, STLArray<p_int> iList )
	{
		int iVertex;
		int size = iList.size();
		for ( iVertex = 0; iVertex < size; iVertex++ )
		{
			int iN = iList.get( iVertex ).value;
			
			// Ignore the vertices which make up the specified triangle
			if ( ( iN == i1 ) || ( iN == i2 ) || ( iN == i3 ) )
				continue;
			
			// Use the reverse direction of the triangle lines, and if the
			// triangle fromed with the vertex is the same orientation, the
			// vertex lies outside that edge.
			int __t1, __t2, __t3;
			__t1 = CalcDeterminant( i2, i1, iN );
			__t2 = CalcDeterminant( i1, i3, iN );
			__t3 = CalcDeterminant( i3, i2, iN );
			if ( ( __t1 == m_Orientation ) || 
					( __t2 == m_Orientation ) || 
					( __t3 == m_Orientation ) )
				continue;
			else
			{
				//nttdata 案1高速化
//				// If it is coincident with one of the vertices, then presume it is inside.
//				if (    ( ( this ).valueAt( iN ) .equals( ( this ).valueAt( i1 ) ) ) ||
//						( ( this ).valueAt( iN ) .equals( ( this ).valueAt( i2 ) ) ) ||
//						( ( this ).valueAt( iN ) .equals( ( this ).valueAt( i3 ) ) )  )
//					continue;
//				else
//					return ( false );
				//nttdata 案1高速化
				CqVector2D tmp = ( this ).valueAt( iN );
				if (    ( tmp.equals( ( this ).valueAt( i1 ) ) ) ||
						( tmp.equals( ( this ).valueAt( i2 ) ) ) ||
						( tmp.equals( ( this ).valueAt( i3 ) ) )  )
					continue;
				else
					return ( false );
				//nttdata 案2 高速化
//				CqVector4D tmp = ( this ).valueAt4( iN );
//				if (    ( tmp.equals( ( this ).valueAt4( i1 ) ) ) ||
//						( tmp.equals( ( this ).valueAt4( i2 ) ) ) ||
//						( tmp.equals( ( this ).valueAt4( i3 ) ) )  )
//					continue;
//				else
//					return ( false );
//				nttdata end
			}
		}
		return ( true );
	}
	
	public void EliminateDuplicatePoints()
	{}

	public boolean Contains( CqPolygonGeneral2D polyCheck )
	{
		assert( polyCheck.cVertices() > 0 && cVertices() > 0 );
		
		int vertices = polyCheck.cVertices();
		for ( int iVertex = 0; iVertex < vertices; iVertex++ )
		{
			boolean	c = false;
			float	x = polyCheck.valueAt( iVertex ).x;
			float	y = polyCheck.valueAt( iVertex ).y;
			
			// Check if this vertex is inside this polygon.
			int	i, j;
			for ( i = 0, j = vertices - 1; i < vertices; j = i++ )
			{
				// Check if this edge spans the vertex in y
				if ( ( ( ( ( this ).valueAt( i ).y <= y ) && ( y < ( this ).valueAt( j ).y ) ) ||
						( ( ( this ).valueAt( j ).y <= y ) && ( y < ( this ).valueAt( i ).y ) ) ) &&
						// and if so, check the position of the vertex in relation to the edge.
						( x < ( ( this ).valueAt( j ).x - ( this ).valueAt( i ).x ) * ( y - ( this ).valueAt( i ).y ) /
						( ( this ).valueAt( j ).y - ( this ).valueAt( i ).y ) + ( this ).valueAt( i ).x ) )
					c = !c;
			}
			// If this point is outside, then the polygon cannot be entirely inside.
			if ( !c ) return ( false );
		}
		return ( true );
	}
	
	public void Combine( CqPolygonGeneral2D polyFrom )
	{
		// Go through and find the two points on the polygons
		// which are closest together.
		
		CqVector2D	currToPrev, currToNext, minToPrev, minToNext;
//		CqVector2D currToPrev = new CqVector2D();
//		CqVector2D currToNext = new CqVector2D();
//		CqVector2D minToPrev  = new CqVector2D();
//		CqVector2D minToNext  = new CqVector2D();
		int	iMinThis = 0;
		int	iMinThat = 0;
		float	CurrDist;
		float	MinDist = FLT_MAX;
		
		int i;
		int vertices = cVertices();
		int polyvertices = polyFrom.cVertices();
		for ( i = 0; i < vertices; i++ )
		{
			int j;
			
			for ( j = 0; j < polyvertices; j++ )
			{
				CqVector2D vecTemp = new CqVector2D( ( this ).valueAt( i ) .sub( polyFrom.valueAt( j ) ) );
				CurrDist = (float)sqrt( vecTemp .mul( vecTemp ) );
				
				if ( CurrDist == MinDist )
				{
					currToPrev = ( i > 0 ) ? ( this ).valueAt( i - 1 ) .sub( ( this ).valueAt( i ) ) :
						( this ).valueAt( cVertices() - 1 ) .sub( ( this ).valueAt( i ) );
					currToNext = ( i < cVertices() - 1 ) ? ( this ).valueAt( i + 1 ) .sub( ( this ).valueAt( i ) ) :
						( this ).valueAt( 0 ) .sub( ( this ).valueAt( i ) );
					
					minToPrev = ( iMinThis > 0 ) ? ( this ).valueAt( iMinThis - 1 ) .sub( ( this ).valueAt( iMinThis ) ) :
						( this ).valueAt( cVertices() - 1 ) .sub( ( this ).valueAt( iMinThis ) );
					minToNext = ( iMinThis < cVertices() - 1 ) ? ( this ).valueAt( iMinThis + 1 ) .sub( ( this ).valueAt( iMinThis ) ) :
						( this ).valueAt( 0 ) .sub( ( this ).valueAt( iMinThis ) );
					
					CqVector2D	vecTest = polyFrom.valueAt( j ) .sub( ( this ).valueAt( i ) );
					
					currToPrev.Unit();
					currToNext.Unit();
					minToPrev.Unit();
					minToNext.Unit();
					
					vecTemp = currToPrev .sub( vecTest );
					float	distCP = (float)( sqrt( vecTemp .mul( vecTemp ) ) );
					vecTemp = currToNext .sub( vecTest );
					float	distCN = (float)( sqrt( vecTemp .mul( vecTemp ) ) );
					vecTemp = minToPrev .sub( vecTest );
					float	distMP = (float)( sqrt( vecTemp .mul( vecTemp ) ) );
					vecTemp = minToNext .sub( vecTest );
					float	distMN = (float)( sqrt( vecTemp .mul( vecTemp ) ) );
					
					if ( ( distCP + distCN ) < ( distMP + distMN ) )
					{
						MinDist = CurrDist;
						iMinThis = i;
						iMinThat = j;
					}
				}
				else
				{
					if ( CurrDist < MinDist )
					{
						MinDist = CurrDist;
						iMinThis = i;
						iMinThat = j;
					}
				}
			}
		}
		// Now combine the two polygons at the closest points.
		
		STLVector<p_int> avecNew = new STLVector<p_int>(p_int.class);
		
		// First copy the vertices from this one, from the min point up to the end...
		for ( i = iMinThis; i < vertices; i++ )
			avecNew.add( new p_int( m_aiVertices.get( i ) ) );
		
		// ...then copy the vertices from this one, from 0 up to (and including) the min point...
		for ( i = 0; i <= iMinThis; i++ )
			avecNew.add( new p_int( m_aiVertices.get( i ) ) );
		
		// ...then copy the vertices from that one, from the min point up to the end...
		for ( i = iMinThat; i < polyvertices; i++ )
			avecNew.add( new p_int( polyFrom.m_aiVertices.get( i ) ) );
		
		// ...then copy the vertices from that one, from 0 up to (and including) the min point...
		for ( i = 0; i <= iMinThat; i++ )
			avecNew.add( new p_int( polyFrom.m_aiVertices.get( i ) ) );
		
		// Now copy the new list of vertices to this new polygon.
		int size = (int)avecNew.size();
		m_aiVertices.resize( size );
		int ivert;
		for ( ivert = 0; ivert < size; ivert++ )
			m_aiVertices.get( ivert ).value = avecNew.get( ivert ).value;
	}
	
	public void Triangulate( STLVector<p_int> aiList )
	{
		   // This is done by checking each vertex in turn to see if it can successfully be chopped off.
	    // If at the end there are more than 3 vertices left which cannot be chopped off, the
	    // polygon is self intersecting.

//	    STLVector<p_int> iList = new STLVector<p_int>(p_int.class);
	    STLArray<p_int> iList = new STLArray<p_int>(p_int.class);
	    int size = m_aiVertices.size() ;
	    iList.resize( size );
	    int iVertex = size;
	    while ( iVertex-- > 0 )
	        iList.get( iVertex ).value = iVertex;

	    int cVertex = size;
	    while ( cVertex > 3 )
	    {
	        boolean fDone = false;
	        int	iPrev = cVertex - 1;
	        int	iCurr = 0;
	        int	iNext = 1;

	        while ( ( iCurr < cVertex ) && ( fDone == false ) )
	        {
	            iPrev = iCurr - 1;
	            iNext = iCurr + 1;

	            if ( iCurr == 0 )
	                iPrev = cVertex - 1;
	            else
	                if ( iCurr == cVertex - 1 )
	                    iNext = 0;

	            int	CurrDeterm = CalcDeterminant( iList.get( iPrev ).value,
	                                                iList.get( iCurr ).value,
	                                                iList.get( iNext ).value );
	            boolean CurrPos = NoneInside( iList.get( iPrev ).value,
	                                        iList.get( iCurr ).value,
	                                        iList.get( iNext ).value,
	                                        iList );
	            if ( ( CurrDeterm == Orientation() ) &&
	                    ( CurrPos != false ) )
	                fDone = true;
	            else
	                iCurr++;
	        }

	        if ( fDone == false )
	            return ;
	        else
	        {
				if( m_Reverse )
				{
					aiList.add( new p_int( m_aiVertices.get( iList.get( iNext ).value ) ) );
					aiList.add( new p_int( m_aiVertices.get( iList.get( iCurr ).value ) ) );
					aiList.add( new p_int( m_aiVertices.get( iList.get( iPrev ).value ) ) );
				}
				else
				{				
					aiList.add( new p_int( m_aiVertices.get( iList.get( iPrev ).value ) ) );
					aiList.add( new p_int( m_aiVertices.get( iList.get( iCurr ).value ) ) );
					aiList.add( new p_int( m_aiVertices.get( iList.get( iNext ).value ) ) );
				}

	            cVertex -= 1;
	            for ( iVertex = iCurr; iVertex < cVertex; iVertex++ )
	                iList.get( iVertex ).value = iList.get( iVertex + 1 ).value;
	            iList.resize( cVertex );
	        }
	    }
		if( cVertex == 3 )
		{
			if( m_Reverse )
			{
				aiList.add( new p_int( m_aiVertices.get( iList.get( 2 ).value ) ) );
				aiList.add( new p_int( m_aiVertices.get( iList.get( 1 ).value ) ) );
				aiList.add( new p_int( m_aiVertices.get( iList.get( 0 ).value ) ) );
			}
			else
			{
				aiList.add( new p_int( m_aiVertices.get( iList.get( 0 ).value ) ) );
				aiList.add( new p_int( m_aiVertices.get( iList.get( 1 ).value ) ) );
				aiList.add( new p_int( m_aiVertices.get( iList.get( 2 ).value ) ) );
			}
		}
	}

	/**
	 * 
	 * 配列参照演算子。
	 * 引数の定義域は１〜３．フラグ Axis_XY,Axis_XZ,Axis_YZ の使用を推奨。
	 * 
	 * 
	 * @param index	フラグ Axis_XY,Axis_XZ,Axis_YZ のどれか。
	 * @return	フラグに該当する座標値を示すCqVector2D
	 */
	//nttdata 高速化
//	public CqVector4D valueAt4( int index )
//	{
//		//nttdata change
//		switch ( m_Axis )
//		{
//		case Axis_XY:
//			//return ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
//			return ((CqVector4D)m_pVertices.P().pValue_get( m_aiVertices.get( index ).value ,0));
//		case Axis_XZ:
//			//return ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
//			return ((CqVector4D)m_pVertices.P().pValue_get( m_aiVertices.get( index ).value ,0));
//		case Axis_YZ:
//			//return((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
//			return((CqVector4D)m_pVertices.P().pValue_get( m_aiVertices.get( index ).value ,0));
//		}
//		return new CqVector4D(0,0,0,0);
//	}
	//end
	public CqVector2D valueAt( int index )
	{
		//nttdata change
		CqVector4D tmp;
		switch ( m_Axis )
		{
		case Axis_XY:
			//tmp = ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
			tmp = ((CqVector4D)m_pVertices.P().pValue_get( m_aiVertices.get( index ).value ,0));
			return ( new CqVector2D( tmp.x,tmp.y));
			
		case Axis_XZ:
			//tmp = ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
			tmp = ((CqVector4D)m_pVertices.P().pValue_get( m_aiVertices.get( index ).value ,0));
			return ( new CqVector2D( tmp.x,tmp.z));
			
		case Axis_YZ:
			//tmp = ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
			tmp = ((CqVector4D)m_pVertices.P().pValue_get( m_aiVertices.get( index ).value ,0));
			return ( new CqVector2D( tmp.y,tmp.z));
		}
//		if(m_Axis == Axis_XY)
//		{
//			tmp = ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
//			return ( new CqVector2D( tmp.x,tmp.y));
//		}
//		if(m_Axis == Axis_XZ)
//		{
//			tmp = ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
//			return ( new CqVector2D( tmp.x,tmp.z));
//			
//		}
//		if(m_Axis == Axis_YZ)
//		{
//			tmp = ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]);
//			return ( new CqVector2D( tmp.y,tmp.z));
//		}
		
		//nttdata chenge end
//		switch ( m_Axis )
//		{
//		case Axis_XY:
//			return ( new CqVector2D( ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]).x,
//					((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]).y ) );
//			
//		case Axis_XZ:
//			return ( new CqVector2D( ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]).x,
//					((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]).z ) );
//			
//		case Axis_YZ:
//			return ( new CqVector2D( ((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]).y,
//					((CqVector4D)m_pVertices.P().pValue( m_aiVertices.get( index ).value )[0]).z ) );
//		}
		return ( new CqVector2D( 0, 0 ) );
	}
	
	/**
	 * 
	 * 代入演算子。
	 * すべての内部変数をコピーする。ただし、m_aiVerticesは値コピー。
	 * 
	 * @param From	コピー元
	 * @return	thisポインタ
	 */
	public CqPolygonGeneral2D assignment( final CqPolygonGeneral2D From )
	{
	    // Copy the vertices
	    int iVertex = From.cVertices();
	    m_aiVertices.resize( iVertex );
	    while ( iVertex-- > 0 )
	        m_aiVertices.get( iVertex ).value = From.m_aiVertices.get( iVertex ).value;

	    m_Orientation = From.m_Orientation;
	    m_Axis = From.m_Axis;
		m_Reverse = From.m_Reverse;

	    m_pVertices = From.m_pVertices;

	    return ( this );

	}
	
}
	