+ Bugfix: changed Plugin Loader to expect 'GetPluginVersion' instead of
'GetVersion'. + Introduced normal calculations. This is buggy due to multiple equal face normals distorting the vertex normal; this will be fixed by removing the redundant face normals from the calculations.
This commit is contained in:
parent
1940bd71e4
commit
304cd81ebd
|
@ -159,3 +159,12 @@ bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
|
|||
|
||||
return NewNode( np );
|
||||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::CalcNormals( void )
|
||||
{
|
||||
if( m_node )
|
||||
return ((SGFACESET*)m_node)->CalcNormals();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -41,3 +41,14 @@ SGCOORDINDEX::~SGCOORDINDEX()
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SGCOORDINDEX::GatherCoordIndices( std::vector< int >& aIndexList )
|
||||
{
|
||||
if( index.empty() )
|
||||
return;
|
||||
|
||||
aIndexList.insert( aIndexList.end(), index.begin(), index.end() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,13 @@ class SGCOORDINDEX : public SGINDEX
|
|||
public:
|
||||
SGCOORDINDEX( SGNODE* aParent );
|
||||
virtual ~SGCOORDINDEX();
|
||||
|
||||
/**
|
||||
* Function GatherCoordIndices
|
||||
* adds all coordinate indices to the given list
|
||||
* in preparation for a normals calculation
|
||||
*/
|
||||
void GatherCoordIndices( std::vector< int >& aIndexList );
|
||||
};
|
||||
|
||||
#endif // SG_COORDINDEX_H
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <iostream>
|
||||
#include "3d_cache/sg/sg_coords.h"
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_normals.h"
|
||||
#include "3d_cache/sg/sg_faceset.h"
|
||||
|
||||
|
||||
SGCOORDS::SGCOORDS( SGNODE* aParent ) : SGNODE( aParent )
|
||||
|
@ -312,3 +314,37 @@ bool SGCOORDS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SGCOORDS::CalcNormals( void )
|
||||
{
|
||||
if( NULL == m_Parent )
|
||||
return false;
|
||||
|
||||
// the parent and all references must have indices; collect all
|
||||
// indices into one std::vector<>
|
||||
std::vector< int > ilist;
|
||||
((SGFACESET*)m_Parent)->GatherCoordIndices( ilist );
|
||||
|
||||
std::list< SGNODE* >::iterator sB = m_BackPointers.begin();
|
||||
std::list< SGNODE* >::iterator eB = m_BackPointers.end();
|
||||
|
||||
while( sB != eB )
|
||||
{
|
||||
SGFACESET* fp = (SGFACESET*)(*sB);
|
||||
fp->GatherCoordIndices( ilist );
|
||||
++sB;
|
||||
}
|
||||
|
||||
SGNORMALS* np = ((SGFACESET*)m_Parent)->m_Normals;
|
||||
|
||||
if( !np )
|
||||
np = new SGNORMALS( m_Parent );
|
||||
|
||||
if( S3D::CalcTriangleNormals( coords, ilist, np->norms ) )
|
||||
return true;
|
||||
|
||||
delete np;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,13 @@ public:
|
|||
void AddCoord( double aXValue, double aYValue, double aZValue );
|
||||
void AddCoord( const SGPOINT& aPoint );
|
||||
|
||||
/**
|
||||
* Function CalcNormals
|
||||
* calculates normals for this coordinate list and sets the
|
||||
* normals list in the parent SGFACESET
|
||||
*/
|
||||
bool CalcNormals( void );
|
||||
|
||||
void ReNameNodes( void );
|
||||
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
|
||||
|
||||
|
|
|
@ -1030,3 +1030,34 @@ bool SGFACESET::validate( void )
|
|||
valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
|
||||
{
|
||||
if( m_CoordIndices )
|
||||
m_CoordIndices->GatherCoordIndices( aIndexList );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool SGFACESET::CalcNormals( void )
|
||||
{
|
||||
if( m_RCoords )
|
||||
{
|
||||
SGFACESET* fp = (SGFACESET*) m_RCoords->GetParent();
|
||||
|
||||
if( !fp )
|
||||
return false;
|
||||
|
||||
return fp->CalcNormals();
|
||||
}
|
||||
|
||||
if( NULL == m_Coords || m_Coords->coords.empty() )
|
||||
return false;
|
||||
|
||||
if( m_Normals && !m_Normals->norms.empty( ) )
|
||||
return true;
|
||||
|
||||
return m_Coords->CalcNormals();
|
||||
}
|
||||
|
|
|
@ -76,11 +76,20 @@ public:
|
|||
bool AddRefNode( SGNODE* aNode );
|
||||
bool AddChildNode( SGNODE* aNode );
|
||||
|
||||
bool CalcNormals( void );
|
||||
|
||||
void ReNameNodes( void );
|
||||
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
|
||||
|
||||
bool WriteCache( std::ofstream& aFile, SGNODE* parentNode );
|
||||
bool ReadCache( std::ifstream& aFile, SGNODE* parentNode );
|
||||
|
||||
/**
|
||||
* Function GatherCoordIndices
|
||||
* adds all internal coordinate indices to the given list
|
||||
* in preparation for a normals calculation
|
||||
*/
|
||||
void GatherCoordIndices( std::vector< int >& aIndexList );
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <streambuf>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <map>
|
||||
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
@ -306,3 +308,192 @@ bool S3D::ReadColor( std::ifstream& aFile, SGCOLOR& aColor )
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct TRIAD
|
||||
{
|
||||
int p1;
|
||||
int p2;
|
||||
int p3;
|
||||
};
|
||||
|
||||
|
||||
bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
||||
std::vector< int >& index, std::vector< SGVECTOR >& norms )
|
||||
{
|
||||
size_t vsize = coords.size();
|
||||
|
||||
if( vsize < 3 )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
std::cerr << " * [INFO] invalid vertex set (fewer than 3 vertices)\n";
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t isize = index.size();
|
||||
|
||||
if( 0 != isize % 3 || index.empty() )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
std::cerr << " * [INFO] invalid index set (not multiple of 3)\n";
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !norms.empty() )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
std::cerr << " * [INFO] normals set is not empty\n";
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map< int, std::list< TRIAD > >vmap;
|
||||
|
||||
int p1, p2, p3;
|
||||
|
||||
// create the map of indices to facet sets
|
||||
for( size_t i = 0; i < isize; )
|
||||
{
|
||||
p1 = index[i++];
|
||||
p2 = index[i++];
|
||||
p3 = index[i++];
|
||||
|
||||
if( p1 < 0 || p1 >= vsize || p2 < 0 || p2 >= vsize ||
|
||||
p3 < 0 || p3 >= vsize )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
std::cerr << " * [INFO] invalid index set; index out of bounds\n";
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore degenerate triangle indices; note that it is still possible to
|
||||
// have degenerate vertices and these may cause problems
|
||||
if( p1 == p2 || p2 == p3 || p3 == p1 )
|
||||
continue;
|
||||
|
||||
TRIAD tri;
|
||||
tri.p1 = p1;
|
||||
tri.p2 = p2;
|
||||
tri.p3 = p3;
|
||||
|
||||
std::map< int, std::list< TRIAD > >::iterator ip = vmap.find( p1 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.insert( std::pair < int, std::list < TRIAD > > ( p1, std::list < TRIAD >( 1, tri ) ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p2 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.insert( std::pair < int, std::list < TRIAD > > ( p2, std::list < TRIAD >( 1, tri ) ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p2 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
ip->second.push_back( tri );
|
||||
}
|
||||
else
|
||||
{
|
||||
vmap.insert( std::pair < int, std::list < TRIAD > > ( p3, std::list < TRIAD >( 1, tri ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
std::map< int, std::list< TRIAD > >::iterator sM = vmap.begin();
|
||||
std::map< int, std::list< TRIAD > >::iterator eM = vmap.end();
|
||||
size_t idx = 0;
|
||||
|
||||
while( sM != eM )
|
||||
{
|
||||
size_t item = sM->first;
|
||||
|
||||
// assign any skipped coordinates a normal of (0,0,1)
|
||||
while( item > idx )
|
||||
{
|
||||
norms.push_back( SGVECTOR( 0, 0, 1 ) );
|
||||
++idx;
|
||||
}
|
||||
|
||||
std::list< TRIAD >::iterator sT = sM->second.begin();
|
||||
std::list< TRIAD >::iterator eT = sM->second.end();
|
||||
|
||||
double nx = 0.0;
|
||||
double ny = 0.0;
|
||||
double nz = 0.0;
|
||||
|
||||
// XXX - TODO:
|
||||
// eliminate equal face normals in order to prevent distortion of the true vertex normal
|
||||
|
||||
while( sT != eT )
|
||||
{
|
||||
double x0, x1, x2;
|
||||
double y0, y1, y2;
|
||||
double z0, z1, z2;
|
||||
|
||||
x1 = coords[sT->p2].x - coords[sT->p1].x;
|
||||
y1 = coords[sT->p2].y - coords[sT->p1].y;
|
||||
z1 = coords[sT->p2].z - coords[sT->p1].z;
|
||||
|
||||
x2 = coords[sT->p3].x - coords[sT->p1].x;
|
||||
y2 = coords[sT->p3].y - coords[sT->p1].y;
|
||||
z2 = coords[sT->p3].z - coords[sT->p1].z;
|
||||
|
||||
x0 = (y1 * z2) - (z1 * y2);
|
||||
y0 = (z1 * x2) - (x1 * z2);
|
||||
z0 = (x1 * y2) - (y1 * x2);
|
||||
|
||||
double m = sqrt( x0*x0 + y0*y0 + z0*z0 );
|
||||
|
||||
// add the normal to the normal accumulated for this facet
|
||||
|
||||
if( m < 1e-12 )
|
||||
{
|
||||
nz += 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nx += ( x0 / m );
|
||||
ny += ( y0 / m );
|
||||
nz += ( z0 / m );
|
||||
}
|
||||
|
||||
++sT;
|
||||
}
|
||||
|
||||
norms.push_back( SGVECTOR( nx, ny, nz ) );
|
||||
|
||||
++idx;
|
||||
++sM;
|
||||
}
|
||||
|
||||
if( norms.size() != coords.size() )
|
||||
{
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
std::cerr << " * [BUG] number of normals does not equal number of vertices\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,14 @@
|
|||
#include <fstream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "plugins/3dapi/sg_base.h"
|
||||
#include "plugins/3dapi/sg_types.h"
|
||||
|
||||
class SGNORMALS;
|
||||
class SGCOORDS;
|
||||
class SGCOORDINDEX;
|
||||
|
||||
// Function to drop references within an SGNODE
|
||||
// The node being destroyed must remove itself from the object reference's
|
||||
// backpointer list in order to avoid a segfault.
|
||||
|
@ -148,6 +153,29 @@
|
|||
|
||||
namespace S3D
|
||||
{
|
||||
//
|
||||
// Normals calculations from triangles
|
||||
//
|
||||
|
||||
/*
|
||||
* Function CalcTriangleNormals
|
||||
* takes an array of 3D coordinates and its corresponding index set and calculates
|
||||
* the normals assuming that indices are given in CCW order. Care must be taken in
|
||||
* using this function to ensure that:
|
||||
* (a) all coordinates are indexed; unindexed coordinates are assigned normal(0,0,1);
|
||||
* when dealing with VRML models which may list and reuse one large coordinate set it
|
||||
* is necessary to gather all index sets and perform this operation only once.
|
||||
* (b) index sets must represent triangles (multiple of 3 indices) and must not be
|
||||
* degenerate - that is all indices and coordinates in a triad must be unique.
|
||||
*
|
||||
* @param coords is the array of 3D vertices
|
||||
* @param index is the array of 3x vertex indices (triads)
|
||||
* @param norms is an empty array which holds the normals corresponding to each vector
|
||||
* @return true on success; otherwise false.
|
||||
*/
|
||||
bool CalcTriangleNormals( std::vector< SGPOINT > coords, std::vector< int >& index,
|
||||
std::vector< SGVECTOR >& norms );
|
||||
|
||||
//
|
||||
// VRML related functions
|
||||
//
|
||||
|
|
|
@ -76,10 +76,10 @@ namespace S3D
|
|||
class SGNODE
|
||||
{
|
||||
private:
|
||||
std::list< SGNODE* > m_BackPointers; // nodes which hold a reference to this
|
||||
SGNODE** m_Association; // handle to the instance held by a wrapper
|
||||
|
||||
protected:
|
||||
std::list< SGNODE* > m_BackPointers; // nodes which hold a reference to this
|
||||
SGNODE* m_Parent; // pointer to parent node; may be NULL for top level transform
|
||||
S3D::SGTYPES m_SGtype; // type of SG node
|
||||
std::string m_Name; // name to use for referencing the entity by name
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
bool Attach( SGNODE* aNode );
|
||||
bool NewNode( SGNODE* aParent );
|
||||
bool NewNode( IFSG_NODE& aParent );
|
||||
|
||||
bool CalcNormals( void );
|
||||
};
|
||||
|
||||
#endif // IFSG_FACESET_H
|
||||
|
|
|
@ -204,14 +204,13 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
IFSG_COORDINDEX* coordIdx = new IFSG_COORDINDEX( *face );
|
||||
coordIdx->SetIndices( indices.size(), &indices[0] );
|
||||
|
||||
// XXX - TO BE IMPLEMENTED : add correct normals and colors
|
||||
std::vector< SGVECTOR > norms;
|
||||
|
||||
for( size_t i = 0; i < nvert; ++i )
|
||||
norms.push_back( SGVECTOR( 0.0, 0.0, 1.0 ) );
|
||||
|
||||
IFSG_NORMALS* np = new IFSG_NORMALS( *face );
|
||||
np->SetNormalList( nvert, &norms[0] );
|
||||
if( !face->CalcNormals() )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
std::cerr << " * [INFO] cannot calculate normals\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
// magenta
|
||||
IFSG_APPEARANCE* material = new IFSG_APPEARANCE( *shape);
|
||||
|
@ -222,13 +221,20 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
|
||||
SCENEGRAPH* data = (SCENEGRAPH*)tx0->GetRawPtr();
|
||||
|
||||
// XXX - DEBUG - WRITE OUT IDF FILE TO CONFIRM NORMALS
|
||||
wxFileName fn( aFileName );
|
||||
wxString fnam = fn.GetName();
|
||||
fnam.append( wxT(".wrl") );
|
||||
std::cerr << "XXX: FILE NAME: " << fnam.ToUTF8() << "\n";
|
||||
S3D::WriteVRML( fnam, true, (SGNODE*)(data), true, true );
|
||||
|
||||
|
||||
// delete the API wrappers
|
||||
delete shape;
|
||||
delete face;
|
||||
delete coordIdx;
|
||||
delete material;
|
||||
delete cp;
|
||||
delete np;
|
||||
delete tx0;
|
||||
|
||||
return data;
|
||||
|
|
|
@ -84,7 +84,7 @@ bool KICAD_PLUGIN_LDR::open( const wxString& aFullFileName, const char* aPluginC
|
|||
LINK_ITEM( m_getClassVersion, GET_CLASS_VERSION, "GetClassVersion" );
|
||||
LINK_ITEM( m_checkClassVersion, CHECK_CLASS_VERSION , "CheckClassVersion" );
|
||||
LINK_ITEM( m_getPluginName, GET_PLUGIN_NAME, "GetKicadPluginName" );
|
||||
LINK_ITEM( m_getVersion, GET_VERSION, "GetVersion" );
|
||||
LINK_ITEM( m_getVersion, GET_VERSION, "GetPluginVersion" );
|
||||
|
||||
#ifdef DEBUG
|
||||
bool fail = false;
|
||||
|
|
Loading…
Reference in New Issue