2015-12-08 07:31:57 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file sg_helpers.h
|
|
|
|
* defines a number of macro functions to aid in repetitious code which
|
|
|
|
* is probably best expressed as a preprocessor macro rather than as
|
|
|
|
* a template. This header also declares a number of functions which are
|
|
|
|
* only of use within the sg_* classes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SG_HELPERS_H
|
|
|
|
#define SG_HELPERS_H
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <string>
|
|
|
|
#include <algorithm>
|
2015-12-15 07:53:03 +00:00
|
|
|
#include <vector>
|
2015-12-09 07:30:48 +00:00
|
|
|
#include "plugins/3dapi/sg_base.h"
|
|
|
|
#include "plugins/3dapi/sg_types.h"
|
2015-12-17 02:55:35 +00:00
|
|
|
#include <glm/glm.hpp>
|
2015-12-08 07:31:57 +00:00
|
|
|
|
2015-12-15 07:53:03 +00:00
|
|
|
class SGNORMALS;
|
|
|
|
class SGCOORDS;
|
|
|
|
class SGCOORDINDEX;
|
|
|
|
|
2015-12-08 07:31:57 +00:00
|
|
|
// 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.
|
|
|
|
#define DROP_REFS( aType, aList ) do { \
|
|
|
|
std::vector< aType* >::iterator sL = aList.begin(); \
|
|
|
|
std::vector< aType* >::iterator eL = aList.end(); \
|
|
|
|
while( sL != eL ) { \
|
|
|
|
((SGNODE*)*sL)->delNodeRef( this ); \
|
|
|
|
++sL; \
|
|
|
|
} \
|
|
|
|
aList.clear(); \
|
|
|
|
} while( 0 )
|
|
|
|
|
|
|
|
|
|
|
|
// Function to delete owned objects within an SGNODE
|
|
|
|
// The owned object's parent is set to NULL before
|
|
|
|
// deletion to avoid a redundant 'unlinkChildNode' call.
|
|
|
|
#define DEL_OBJS( aType, aList ) do { \
|
|
|
|
std::vector< aType* >::iterator sL = aList.begin(); \
|
|
|
|
std::vector< aType* >::iterator eL = aList.end(); \
|
|
|
|
while( sL != eL ) { \
|
|
|
|
((SGNODE*)*sL)->SetParent( NULL, false ); \
|
|
|
|
delete *sL; \
|
|
|
|
++sL; \
|
|
|
|
} \
|
|
|
|
aList.clear(); \
|
|
|
|
} while( 0 )
|
|
|
|
|
|
|
|
|
|
|
|
// Function to unlink a child or reference node when that child or
|
|
|
|
// reference node is being destroyed.
|
|
|
|
#define UNLINK_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) do { \
|
|
|
|
if( aNodeID == aNode->GetNodeType() ) { \
|
|
|
|
std::vector< aType* >* oSL; \
|
|
|
|
std::vector< aType* >::iterator sL; \
|
|
|
|
std::vector< aType* >::iterator eL; \
|
|
|
|
if( isChild ) { \
|
|
|
|
oSL = &aOwnedList; \
|
2016-04-07 01:41:52 +00:00
|
|
|
sL = oSL->begin(); \
|
|
|
|
eL = oSL->end(); \
|
2016-03-14 01:30:59 +00:00
|
|
|
while( sL != eL ) { \
|
|
|
|
if( (SGNODE*)*sL == aNode ) { \
|
|
|
|
oSL->erase( sL ); \
|
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
++sL; \
|
|
|
|
} \
|
2015-12-08 07:31:57 +00:00
|
|
|
} else { \
|
|
|
|
oSL = &aRefList; \
|
2016-04-07 01:41:52 +00:00
|
|
|
sL = oSL->begin(); \
|
|
|
|
eL = oSL->end(); \
|
2016-03-14 01:30:59 +00:00
|
|
|
while( sL != eL ) { \
|
|
|
|
if( (SGNODE*)*sL == aNode ) { \
|
|
|
|
delNodeRef( this ); \
|
|
|
|
oSL->erase( sL ); \
|
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
++sL; \
|
2015-12-08 07:31:57 +00:00
|
|
|
} \
|
|
|
|
} \
|
|
|
|
return; \
|
|
|
|
} } while( 0 )
|
|
|
|
|
|
|
|
|
|
|
|
// Function to check a node type, check for an existing reference,
|
|
|
|
// and add the node type to the reference list if applicable
|
|
|
|
#define ADD_NODE( aNodeID, aType, aNode, aOwnedList, aRefList, isChild ) do { \
|
|
|
|
if( aNodeID == aNode->GetNodeType() ) { \
|
|
|
|
std::vector< aType* >::iterator sL; \
|
|
|
|
sL = std::find( aOwnedList.begin(), aOwnedList.end(), aNode ); \
|
|
|
|
if( sL != aOwnedList.end() ) return true; \
|
|
|
|
sL = std::find( aRefList.begin(), aRefList.end(), aNode ); \
|
|
|
|
if( sL != aRefList.end() ) return true; \
|
|
|
|
if( isChild ) { \
|
|
|
|
SGNODE* ppn = (SGNODE*)aNode->GetParent(); \
|
|
|
|
if( NULL != ppn ) { \
|
|
|
|
if( this != ppn ) { \
|
|
|
|
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
|
|
|
|
std::cerr << " * [BUG] object '" << aNode->GetName(); \
|
|
|
|
std::cerr << "' has multiple parents '" << ppn->GetName() << "', '"; \
|
|
|
|
std::cerr << m_Name << "'\n"; \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
aOwnedList.push_back( (aType*)aNode ); \
|
|
|
|
aNode->SetParent( this, false ); \
|
|
|
|
} else { \
|
|
|
|
if( NULL == aNode->GetParent() ) { \
|
|
|
|
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n"; \
|
|
|
|
std::cerr << " * [BUG] object '" << aNode->GetName(); \
|
|
|
|
std::cerr << "' has no parent\n"; \
|
|
|
|
std::cerr << " * [INFO] possible copy assignment or copy constructor bug\n"; \
|
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
aRefList.push_back( (aType*)aNode ); \
|
|
|
|
aNode->addNodeRef( this ); \
|
|
|
|
} \
|
|
|
|
return true; \
|
|
|
|
} } while( 0 )
|
|
|
|
|
|
|
|
|
|
|
|
// Function to find a node object given a (non-unique) node name
|
|
|
|
#define FIND_NODE( aType, aName, aNodeList, aCallingNode ) do { \
|
|
|
|
std::vector< aType* >::iterator sLA = aNodeList.begin(); \
|
|
|
|
std::vector< aType* >::iterator eLA = aNodeList.end(); \
|
|
|
|
SGNODE* psg = NULL; \
|
|
|
|
while( sLA != eLA ) { \
|
|
|
|
if( (SGNODE*)*sLA != aCallingNode ) { \
|
|
|
|
psg = (SGNODE*) (*sLA)->FindNode( aName, this ); \
|
|
|
|
if( NULL != psg) \
|
|
|
|
return psg; \
|
|
|
|
} \
|
|
|
|
++sLA; \
|
|
|
|
} } while ( 0 )
|
|
|
|
|
|
|
|
namespace S3D
|
|
|
|
{
|
2015-12-17 02:55:35 +00:00
|
|
|
bool degenerate( glm::dvec3* pts );
|
|
|
|
|
2015-12-15 07:53:03 +00:00
|
|
|
//
|
|
|
|
// 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 );
|
|
|
|
|
2015-12-08 07:31:57 +00:00
|
|
|
//
|
|
|
|
// VRML related functions
|
|
|
|
//
|
|
|
|
|
|
|
|
// formats a floating point number for text output to a VRML file
|
|
|
|
void FormatFloat( std::string& result, double value );
|
|
|
|
|
|
|
|
// format orientation data for VRML output
|
|
|
|
void FormatOrientation( std::string& result, const SGVECTOR& axis, double rotation );
|
|
|
|
|
|
|
|
// format point data for VRML output
|
|
|
|
void FormatPoint( std::string& result, const SGPOINT& point );
|
|
|
|
|
|
|
|
// format vector data for VRML output
|
|
|
|
void FormatVector( std::string& result, const SGVECTOR& aVector );
|
|
|
|
|
|
|
|
// format Color data for VRML output
|
|
|
|
void FormatColor( std::string& result, const SGCOLOR& aColor );
|
|
|
|
|
|
|
|
//
|
|
|
|
// Cache related WRITE functions
|
|
|
|
//
|
|
|
|
|
|
|
|
// write out an XYZ vertex
|
|
|
|
bool WritePoint( std::ofstream& aFile, const SGPOINT& aPoint );
|
|
|
|
|
|
|
|
// write out a unit vector
|
|
|
|
bool WriteVector( std::ofstream& aFile, const SGVECTOR& aVector );
|
|
|
|
|
|
|
|
// write out an RGB color
|
|
|
|
bool WriteColor( std::ofstream& aFile, const SGCOLOR& aColor );
|
|
|
|
|
|
|
|
//
|
|
|
|
// Cache related READ functions
|
|
|
|
//
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function ReadTag
|
|
|
|
* reads the text tag of a binary cache file which is the
|
|
|
|
* NodeTag and unique ID number combined
|
|
|
|
*
|
|
|
|
* @param aFile is a binary file open for reading
|
|
|
|
* @param aName will hold the tag name on successful return
|
|
|
|
* @return will be the NodeType which the tag represents or
|
|
|
|
* S3D::SGTYPES::SGTYPE_END on failure
|
|
|
|
*/
|
|
|
|
S3D::SGTYPES ReadTag( std::ifstream& aFile, std::string& aName );
|
|
|
|
|
|
|
|
// read an XYZ vertex
|
|
|
|
bool ReadPoint( std::ifstream& aFile, SGPOINT& aPoint );
|
|
|
|
|
|
|
|
// read a unit vector
|
|
|
|
bool ReadVector( std::ifstream& aFile, SGVECTOR& aVector );
|
|
|
|
|
|
|
|
// read an RGB color
|
|
|
|
bool ReadColor( std::ifstream& aFile, SGCOLOR& aColor );
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // SG_HELPERS_H
|