0b2d4d4879
Recommendation is to avoid using the year nomenclature as this information is already encoded in the git repo. Avoids needing to repeatly update. Also updates AUTHORS.txt from current repo with contributor names
846 lines
20 KiB
C++
846 lines
20 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2016-2017 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program 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 program 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 program; if not, you may find one here:
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
|
|
#define GLM_FORCE_RADIANS
|
|
|
|
#include <glm/glm.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
#include <cmath>
|
|
|
|
#include "wrlfacet.h"
|
|
|
|
#define LOWER_LIMIT (1e-12)
|
|
|
|
|
|
static bool VDegenerate( glm::vec3* pts )
|
|
{
|
|
// note: only checks the degenerate case of zero length sides; it
|
|
// does not detect the case of 3 distinct collinear points
|
|
|
|
double dx, dy, dz;
|
|
|
|
dx = double{ pts[1].x } - pts[0].x;
|
|
dy = double{ pts[1].y } - pts[0].y;
|
|
dz = double{ pts[1].z } - pts[0].z;
|
|
|
|
if( ( dx*dx + dy*dy + dz*dz ) < LOWER_LIMIT )
|
|
return true;
|
|
|
|
dx = double{ pts[2].x } - pts[0].x;
|
|
dy = double{ pts[2].y } - pts[0].y;
|
|
dz = double{ pts[2].z } - pts[0].z;
|
|
|
|
if( ( dx*dx + dy*dy + dz*dz ) < LOWER_LIMIT )
|
|
return true;
|
|
|
|
dx = double{ pts[2].x } - pts[1].x;
|
|
dy = double{ pts[2].y } - pts[1].y;
|
|
dz = double{ pts[2].z } - pts[1].z;
|
|
|
|
if( ( dx*dx + dy*dy + dz*dz ) < LOWER_LIMIT )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
static WRLVEC3F VCalcTriNorm( const WRLVEC3F& p1, const WRLVEC3F& p2, const WRLVEC3F& p3 )
|
|
{
|
|
// note: p1 = reference vertex
|
|
glm::vec3 tri = glm::vec3( 0.0, 0.0, 0.0 );
|
|
glm::vec3 pts[3];
|
|
|
|
pts[0] = p1;
|
|
pts[1] = p2;
|
|
pts[2] = p3;
|
|
|
|
// degenerate points are given a default 0, 0, 0 normal
|
|
if( VDegenerate( pts ) )
|
|
return tri;
|
|
|
|
// normal
|
|
tri = glm::cross( pts[2] - pts[0], pts[1] - pts[0] );
|
|
|
|
float dn = sqrtf( tri.x * tri.x + tri.y * tri.y + tri.z * tri.z );
|
|
|
|
if( dn > LOWER_LIMIT )
|
|
{
|
|
tri.x /= dn;
|
|
tri.y /= dn;
|
|
tri.z /= dn;
|
|
}
|
|
|
|
return tri;
|
|
}
|
|
|
|
|
|
static float VCalcCosAngle( const WRLVEC3F& p1, const WRLVEC3F& p2, const WRLVEC3F& p3 )
|
|
{
|
|
// note: p1 = reference vertex
|
|
float l12, l13;
|
|
float dx, dy, dz;
|
|
|
|
dx = p2.x - p1.x;
|
|
dy = p2.y - p1.y;
|
|
dz = p2.z - p1.z;
|
|
float p12 = dx*dx + dy*dy + dz*dz;
|
|
l12 = sqrtf( p12 );
|
|
|
|
dx = p3.x - p2.x;
|
|
dy = p3.y - p2.y;
|
|
dz = p3.z - p2.z;
|
|
float p23 = dx*dx + dy*dy + dz*dz;
|
|
|
|
dx = p3.x - p1.x;
|
|
dy = p3.y - p1.y;
|
|
dz = p3.z - p1.z;
|
|
float p13 = dx*dx + dy*dy + dz*dz;
|
|
l13 = sqrtf( p13 );
|
|
|
|
float dn = 2.0f * l12 * l13;
|
|
|
|
// place a limit to prevent calculations from blowing up
|
|
if( dn < LOWER_LIMIT )
|
|
{
|
|
if( ( p12 + p13 - p23 ) < FLT_EPSILON )
|
|
return -1.0f;
|
|
|
|
if( ( p12 + p13 - p23 ) > FLT_EPSILON )
|
|
return 1.0f;
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
float cosAngle = ( p12 + p13 - p23 ) / dn;
|
|
|
|
// check the domain; errors in the cosAngle calculation can result in domain errors
|
|
if( cosAngle > 1.0f )
|
|
cosAngle = 1.0f;
|
|
else if( cosAngle < -1.0f )
|
|
cosAngle = -1.0f;
|
|
|
|
// note: we are guaranteed that acosf() is never negative
|
|
return cosAngle;
|
|
}
|
|
|
|
|
|
FACET::FACET()
|
|
{
|
|
face_normal.x = 0.0;
|
|
face_normal.y = 0.0;
|
|
face_normal.z = 0.0;
|
|
maxIdx = 0;
|
|
}
|
|
|
|
|
|
void FACET::Init()
|
|
{
|
|
vertices.clear();
|
|
colors.clear();
|
|
indices.clear();
|
|
norms.clear();
|
|
vnweight.clear();
|
|
|
|
face_normal.x = 0.0;
|
|
face_normal.y = 0.0;
|
|
face_normal.z = 0.0;
|
|
maxIdx = 0;
|
|
}
|
|
|
|
|
|
bool FACET::HasMinPoints()
|
|
{
|
|
if( vertices.size() < 3 )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FACET::HasColors()
|
|
{
|
|
if( colors.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void FACET::AddVertex( WRLVEC3F& aVertex, int aIndex )
|
|
{
|
|
if( aIndex < 0 )
|
|
return;
|
|
|
|
vertices.push_back( aVertex );
|
|
indices.push_back( aIndex );
|
|
|
|
if( aIndex > maxIdx )
|
|
maxIdx = aIndex;
|
|
}
|
|
|
|
|
|
void FACET::AddColor( const SGCOLOR& aColor )
|
|
{
|
|
colors.push_back( aColor );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
float FACET::CalcFaceNormal()
|
|
{
|
|
// note: this calculation assumes that the face is a convex polygon;
|
|
// concave polygons may be supported in the future via functions which
|
|
// split the polygon into triangles
|
|
|
|
if( vertices.size() < 3 )
|
|
return 0.0;
|
|
|
|
// check if the values were already calculated
|
|
if( vertices.size() == vnweight.size() )
|
|
return 0.0;
|
|
|
|
WRLVEC3F lCPts[3];
|
|
|
|
std::vector< WRLVEC3F >::iterator sV = vertices.begin();
|
|
std::vector< WRLVEC3F >::iterator eV = vertices.end();
|
|
|
|
lCPts[0] = vertices.back();
|
|
lCPts[1] = *sV;
|
|
++sV;
|
|
lCPts[2] = *sV;
|
|
++sV;
|
|
|
|
face_normal = VCalcTriNorm( lCPts[1], lCPts[0], lCPts[2] );
|
|
|
|
vnweight.clear();
|
|
WRLVEC3F wnorm = face_normal;
|
|
|
|
// calculate area:
|
|
size_t nv = vertices.size();
|
|
float a1 = 0.0;
|
|
glm::vec3 sum( 0.0, 0.0, 0.0 );
|
|
size_t j = 0;
|
|
|
|
for( size_t i = 1; i < nv; ++i, ++j )
|
|
sum += glm::cross( vertices[j], vertices[i] );
|
|
|
|
a1 = fabs( glm::dot( face_normal, sum ) );
|
|
float a2 = acosf( VCalcCosAngle( lCPts[1], lCPts[0], lCPts[2] ) );
|
|
|
|
wnorm.x *= a1 * a2;
|
|
wnorm.y *= a1 * a2;
|
|
wnorm.z *= a1 * a2;
|
|
vnweight.push_back( wnorm );
|
|
|
|
float maxV = fabs( wnorm.x );
|
|
float tV = fabs( wnorm.y );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
tV = fabs( wnorm.z );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
while( sV != eV )
|
|
{
|
|
lCPts[0] = lCPts[1];
|
|
lCPts[1] = lCPts[2];
|
|
lCPts[2] = *sV;
|
|
++sV;
|
|
|
|
wnorm = face_normal;
|
|
a2 = acosf( VCalcCosAngle( lCPts[1], lCPts[0], lCPts[2] ) );
|
|
wnorm.x *= a1 * a2;
|
|
wnorm.y *= a1 * a2;
|
|
wnorm.z *= a1 * a2;
|
|
vnweight.push_back( wnorm );
|
|
|
|
tV = fabs( wnorm.x );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
tV = fabs( wnorm.y );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
tV = fabs( wnorm.z );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
}
|
|
|
|
lCPts[0] = lCPts[1];
|
|
lCPts[1] = lCPts[2];
|
|
lCPts[2] = vertices.front();
|
|
|
|
wnorm = face_normal;
|
|
a2 = acosf( VCalcCosAngle( lCPts[1], lCPts[0], lCPts[2] ) );
|
|
wnorm.x *= a1 * a2;
|
|
wnorm.y *= a1 * a2;
|
|
wnorm.z *= a1 * a2;
|
|
vnweight.push_back( wnorm );
|
|
|
|
tV = fabs( wnorm.x );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
tV = fabs( wnorm.y );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
tV = fabs( wnorm.z );
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
return maxV;
|
|
}
|
|
|
|
|
|
void FACET::CalcVertexNormal( int aIndex, std::list< FACET* > &aFacetList, float aCreaseLimit )
|
|
{
|
|
if( vertices.size() < 3 )
|
|
return;
|
|
|
|
if( vnweight.size() != vertices.size() )
|
|
return;
|
|
|
|
if( norms.size() != vertices.size() )
|
|
norms.resize( vertices.size() );
|
|
|
|
std::vector< int >::iterator sI = indices.begin();
|
|
std::vector< int >::iterator eI = indices.end();
|
|
int idx = 0;
|
|
|
|
WRLVEC3F fp[2]; // vectors to calculate facet angle
|
|
fp[0].x = 0.0;
|
|
fp[0].y = 0.0;
|
|
fp[0].z = 0.0;
|
|
|
|
while( sI != eI )
|
|
{
|
|
if( *sI == aIndex )
|
|
{
|
|
// first set the default (weighted) normal value
|
|
norms[idx] = vnweight[idx];
|
|
|
|
// iterate over adjacent facets
|
|
std::list< FACET* >::iterator sF = aFacetList.begin();
|
|
std::list< FACET* >::iterator eF = aFacetList.end();
|
|
|
|
while( sF != eF )
|
|
{
|
|
if( this == *sF )
|
|
{
|
|
++sF;
|
|
continue;
|
|
}
|
|
|
|
// check the crease angle limit
|
|
(*sF)->GetFaceNormal( fp[1] );
|
|
|
|
float thrs = VCalcCosAngle( fp[0], face_normal, fp[1] );
|
|
|
|
if( aCreaseLimit <= thrs && (*sF)->GetWeightedNormal( aIndex, fp[1] ) )
|
|
{
|
|
norms[idx].x += fp[1].x;
|
|
norms[idx].y += fp[1].y;
|
|
norms[idx].z += fp[1].z;
|
|
}
|
|
|
|
++sF;
|
|
}
|
|
|
|
// normalize the vector
|
|
float dn = sqrtf( norms[idx].x * norms[idx].x
|
|
+ norms[idx].y * norms[idx].y
|
|
+ norms[idx].z * norms[idx].z );
|
|
|
|
if( dn > LOWER_LIMIT )
|
|
{
|
|
norms[idx].x /= dn;
|
|
norms[idx].y /= dn;
|
|
norms[idx].z /= dn;
|
|
}
|
|
|
|
// if the normals is an invalid normal this test will pass
|
|
if( fabs( norms[idx].x ) < 0.5
|
|
&& fabs( norms[idx].y ) < 0.5
|
|
&& fabs( norms[idx].z ) < 0.5 )
|
|
{
|
|
norms[idx] = face_normal;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
++idx;
|
|
++sI;
|
|
}
|
|
}
|
|
|
|
|
|
bool FACET::GetWeightedNormal( int aIndex, WRLVEC3F& aNorm )
|
|
{
|
|
// the default weighted normal shall have no effect even if accidentally included
|
|
aNorm.x = 0.0;
|
|
aNorm.y = 0.0;
|
|
aNorm.z = 0.0;
|
|
|
|
if( vertices.size() < 3 )
|
|
return false;
|
|
|
|
if( vnweight.size() != vertices.size() )
|
|
return false;
|
|
|
|
std::vector< int >::iterator sI = indices.begin();
|
|
std::vector< int >::iterator eI = indices.end();
|
|
int idx = 0;
|
|
|
|
while( sI != eI )
|
|
{
|
|
if( *sI == aIndex )
|
|
{
|
|
aNorm = vnweight[idx];
|
|
return true;
|
|
}
|
|
|
|
++idx;
|
|
++sI;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool FACET::GetFaceNormal( WRLVEC3F& aNorm )
|
|
{
|
|
aNorm.x = 0.0;
|
|
aNorm.y = 0.0;
|
|
aNorm.z = 0.0;
|
|
|
|
if( vertices.size() < 3 )
|
|
return false;
|
|
|
|
if( vnweight.size() != vertices.size() )
|
|
return false;
|
|
|
|
aNorm = face_normal;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FACET::GetData( std::vector< WRLVEC3F >& aVertexList, std::vector< WRLVEC3F >& aNormalsList,
|
|
std::vector< SGCOLOR >& aColorsList, WRL1_ORDER aVertexOrder )
|
|
{
|
|
// if no normals are calculated we simply return
|
|
if( norms.empty() )
|
|
return false;
|
|
|
|
// the output must always be triangle sets in order to conform to the
|
|
// requirements of the SG* classes
|
|
int idx[3];
|
|
|
|
idx[0] = 0;
|
|
idx[1] = 1;
|
|
idx[2] = 2;
|
|
WRLVEC3F tnorm;
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CLOCKWISE )
|
|
{
|
|
aVertexList.push_back( vertices[idx[0]] );
|
|
aVertexList.push_back( vertices[idx[1]] );
|
|
aVertexList.push_back( vertices[idx[2]] );
|
|
|
|
aNormalsList.push_back( norms[idx[0]] );
|
|
aNormalsList.push_back( norms[idx[1]] );
|
|
aNormalsList.push_back( norms[idx[2]] );
|
|
}
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CCW )
|
|
{
|
|
aVertexList.push_back( vertices[idx[0]] );
|
|
aVertexList.push_back( vertices[idx[2]] );
|
|
aVertexList.push_back( vertices[idx[1]] );
|
|
|
|
tnorm = norms[idx[0]];
|
|
tnorm.x = -tnorm.x;
|
|
tnorm.y = -tnorm.y;
|
|
tnorm.z = -tnorm.z;
|
|
aNormalsList.push_back( tnorm );
|
|
|
|
tnorm = norms[idx[2]];
|
|
tnorm.x = -tnorm.x;
|
|
tnorm.y = -tnorm.y;
|
|
tnorm.z = -tnorm.z;
|
|
aNormalsList.push_back( tnorm );
|
|
|
|
tnorm = norms[idx[1]];
|
|
tnorm.x = -tnorm.x;
|
|
tnorm.y = -tnorm.y;
|
|
tnorm.z = -tnorm.z;
|
|
aNormalsList.push_back( tnorm );
|
|
}
|
|
|
|
bool hasColor = false;
|
|
bool perVC = false; // per-vertex colors?
|
|
|
|
if( !colors.empty() )
|
|
{
|
|
hasColor = true;
|
|
|
|
if( colors.size() >= vertices.size() )
|
|
perVC = true;
|
|
|
|
if( perVC )
|
|
{
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CLOCKWISE )
|
|
{
|
|
aColorsList.push_back( colors[idx[0]] );
|
|
aColorsList.push_back( colors[idx[1]] );
|
|
aColorsList.push_back( colors[idx[2]] );
|
|
}
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CCW )
|
|
{
|
|
aColorsList.push_back( colors[idx[0]] );
|
|
aColorsList.push_back( colors[idx[2]] );
|
|
aColorsList.push_back( colors[idx[1]] );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CLOCKWISE )
|
|
{
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
}
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CCW )
|
|
{
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
}
|
|
}
|
|
}
|
|
|
|
int lim = (int) vertices.size() - 1;
|
|
|
|
while( idx[2] < lim )
|
|
{
|
|
idx[1] = idx[2];
|
|
++idx[2];
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CLOCKWISE )
|
|
{
|
|
aVertexList.push_back( vertices[idx[0]] );
|
|
aVertexList.push_back( vertices[idx[1]] );
|
|
aVertexList.push_back( vertices[idx[2]] );
|
|
|
|
aNormalsList.push_back( norms[idx[0]] );
|
|
aNormalsList.push_back( norms[idx[1]] );
|
|
aNormalsList.push_back( norms[idx[2]] );
|
|
}
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CCW )
|
|
{
|
|
aVertexList.push_back( vertices[idx[0]] );
|
|
aVertexList.push_back( vertices[idx[2]] );
|
|
aVertexList.push_back( vertices[idx[1]] );
|
|
|
|
tnorm = norms[idx[0]];
|
|
tnorm.x = -tnorm.x;
|
|
tnorm.y = -tnorm.y;
|
|
tnorm.z = -tnorm.z;
|
|
aNormalsList.push_back( tnorm );
|
|
|
|
tnorm = norms[idx[2]];
|
|
tnorm.x = -tnorm.x;
|
|
tnorm.y = -tnorm.y;
|
|
tnorm.z = -tnorm.z;
|
|
aNormalsList.push_back( tnorm );
|
|
|
|
tnorm = norms[idx[1]];
|
|
tnorm.x = -tnorm.x;
|
|
tnorm.y = -tnorm.y;
|
|
tnorm.z = -tnorm.z;
|
|
aNormalsList.push_back( tnorm );
|
|
}
|
|
|
|
if( hasColor )
|
|
{
|
|
if( perVC )
|
|
{
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CLOCKWISE )
|
|
{
|
|
aColorsList.push_back( colors[idx[0]] );
|
|
aColorsList.push_back( colors[idx[1]] );
|
|
aColorsList.push_back( colors[idx[2]] );
|
|
}
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CCW )
|
|
{
|
|
aColorsList.push_back( colors[idx[0]] );
|
|
aColorsList.push_back( colors[idx[2]] );
|
|
aColorsList.push_back( colors[idx[1]] );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CLOCKWISE )
|
|
{
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
}
|
|
|
|
if( aVertexOrder != WRL1_ORDER::ORD_CCW )
|
|
{
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
aColorsList.push_back( colors[0] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void FACET::CollectVertices( std::vector< std::list< FACET* > >& aFacetList )
|
|
{
|
|
// check if this facet may contribute anything at all
|
|
if( vertices.size() < 3 )
|
|
return;
|
|
|
|
// note: in principle this should never be invoked
|
|
if( (maxIdx + 1) >= (int)aFacetList.size() )
|
|
aFacetList.resize( static_cast<std::size_t>( maxIdx ) + 1 );
|
|
|
|
std::vector< int >::iterator sI = indices.begin();
|
|
std::vector< int >::iterator eI = indices.end();
|
|
|
|
while( sI != eI )
|
|
{
|
|
aFacetList[*sI].push_back( this );
|
|
++sI;
|
|
}
|
|
}
|
|
|
|
|
|
void FACET::Renormalize( float aMaxValue )
|
|
{
|
|
if( vnweight.empty() || aMaxValue < LOWER_LIMIT )
|
|
return;
|
|
|
|
size_t vs = vnweight.size();
|
|
|
|
for( size_t i = 0; i < vs; ++i )
|
|
{
|
|
vnweight[i].x /= aMaxValue;
|
|
vnweight[i].y /= aMaxValue;
|
|
vnweight[i].z /= aMaxValue;
|
|
}
|
|
}
|
|
|
|
|
|
SHAPE::~SHAPE()
|
|
{
|
|
std::list< FACET* >::iterator sF = facets.begin();
|
|
std::list< FACET* >::iterator eF = facets.end();
|
|
|
|
while( sF != eF )
|
|
{
|
|
delete *sF;
|
|
++sF;
|
|
}
|
|
|
|
facets.clear();
|
|
return;
|
|
}
|
|
|
|
|
|
FACET* SHAPE::NewFacet()
|
|
{
|
|
FACET* fp = new FACET;
|
|
facets.push_back( fp );
|
|
return fp;
|
|
}
|
|
|
|
|
|
SGNODE* SHAPE::CalcShape( SGNODE* aParent, SGNODE* aColor, WRL1_ORDER aVertexOrder,
|
|
float aCreaseLimit, bool isVRML2 )
|
|
{
|
|
if( facets.empty() || !facets.front()->HasMinPoints() )
|
|
return nullptr;
|
|
|
|
std::vector< std::list< FACET* > > flist;
|
|
|
|
// determine the max. index and size flist as appropriate
|
|
std::list< FACET* >::iterator sF = facets.begin();
|
|
std::list< FACET* >::iterator eF = facets.end();
|
|
|
|
int maxIdx = 0;
|
|
int tmi;
|
|
float maxV = 0.0;
|
|
float tV = 0.0;
|
|
|
|
while( sF != eF )
|
|
{
|
|
tV = ( *sF )->CalcFaceNormal();
|
|
tmi = ( *sF )->GetMaxIndex();
|
|
|
|
if( tmi > maxIdx )
|
|
maxIdx = tmi;
|
|
|
|
if( tV > maxV )
|
|
maxV = tV;
|
|
|
|
++sF;
|
|
}
|
|
|
|
++maxIdx;
|
|
|
|
if( maxIdx < 3 )
|
|
return nullptr;
|
|
|
|
flist.resize( maxIdx );
|
|
|
|
// create the lists of facets common to indices
|
|
sF = facets.begin();
|
|
|
|
while( sF != eF )
|
|
{
|
|
( *sF )->Renormalize( tV );
|
|
( *sF )->CollectVertices( flist );
|
|
++sF;
|
|
}
|
|
|
|
// calculate the normals
|
|
size_t vs = flist.size();
|
|
|
|
for( size_t i = 0; i < vs; ++i )
|
|
{
|
|
sF = flist[i].begin();
|
|
eF = flist[i].end();
|
|
|
|
while( sF != eF )
|
|
{
|
|
( *sF )->CalcVertexNormal( static_cast<int>( i ), flist[i], aCreaseLimit );
|
|
++sF;
|
|
}
|
|
}
|
|
|
|
std::vector< WRLVEC3F > vertices;
|
|
std::vector< WRLVEC3F > normals;
|
|
std::vector< SGCOLOR > colors;
|
|
|
|
// push the facet data to the final output list
|
|
sF = facets.begin();
|
|
eF = facets.end();
|
|
|
|
while( sF != eF )
|
|
{
|
|
( *sF )->GetData( vertices, normals, colors, aVertexOrder );
|
|
++sF;
|
|
}
|
|
|
|
flist.clear();
|
|
|
|
if( vertices.size() < 3 )
|
|
return nullptr;
|
|
|
|
IFSG_SHAPE shapeNode( false );
|
|
|
|
if( !isVRML2 )
|
|
{
|
|
shapeNode.NewNode( aParent );
|
|
|
|
if( aColor )
|
|
{
|
|
if( nullptr == S3D::GetSGNodeParent( aColor ) )
|
|
shapeNode.AddChildNode( aColor );
|
|
else
|
|
shapeNode.AddRefNode( aColor );
|
|
}
|
|
}
|
|
|
|
std::vector< SGPOINT > lCPts; // vertex points in SGPOINT (double) format
|
|
std::vector< SGVECTOR > lCNorm; // per-vertex normals
|
|
vs = vertices.size();
|
|
|
|
for( size_t i = 0; i < vs; ++i )
|
|
{
|
|
SGPOINT pt;
|
|
pt.x = vertices[i].x;
|
|
pt.y = vertices[i].y;
|
|
pt.z = vertices[i].z;
|
|
lCPts.push_back( pt );
|
|
lCNorm.emplace_back( normals[i].x, normals[i].y, normals[i].z );
|
|
}
|
|
|
|
vertices.clear();
|
|
normals.clear();
|
|
|
|
IFSG_FACESET fsNode( false );
|
|
|
|
if( !isVRML2 )
|
|
fsNode.NewNode( shapeNode );
|
|
else
|
|
fsNode.NewNode( aParent );
|
|
|
|
IFSG_COORDS cpNode( fsNode );
|
|
cpNode.SetCoordsList( lCPts.size(), &lCPts[0] );
|
|
IFSG_COORDINDEX ciNode( fsNode );
|
|
|
|
for( int i = 0; i < (int)lCPts.size(); ++i )
|
|
ciNode.AddIndex( i );
|
|
|
|
IFSG_NORMALS nmNode( fsNode );
|
|
nmNode.SetNormalList( lCNorm.size(), &lCNorm[0] );
|
|
|
|
if( !colors.empty() )
|
|
{
|
|
IFSG_COLORS nmColor( fsNode );
|
|
nmColor.SetColorList( colors.size(), &colors[0] );
|
|
colors.clear();
|
|
}
|
|
|
|
if( !isVRML2 )
|
|
return shapeNode.GetRawPtr();
|
|
|
|
return fsNode.GetRawPtr();
|
|
}
|