KiCad PCB EDA Suite
x3d_ifaceset.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
5  * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 
26 #include <iostream>
27 #include <sstream>
28 #include <cmath>
29 #include <wx/log.h>
30 #include <wx/xml/xml.h>
31 #include <wx/tokenzr.h>
32 #include "x3d_ops.h"
33 #include "x3d_ifaceset.h"
34 #include "x3d_coords.h"
35 #include "plugins/3dapi/ifsg_all.h"
36 #include "wrlfacet.h"
37 
38 
40 {
42  coord = nullptr;
43  init();
44 }
45 
46 
48 {
50  coord = nullptr;
51  init();
52 
53  if( nullptr != aParent )
54  {
55  X3DNODES ptype = aParent->GetNodeType();
56 
57  if( X3D_SHAPE == ptype )
58  m_Parent = aParent;
59  }
60 
61  if( nullptr != m_Parent )
62  m_Parent->AddChildNode( this );
63 }
64 
65 
67 {
68  wxLogTrace( traceVrmlPlugin, " * [INFO] Destroying IndexedFaceSet." );
69 }
70 
71 
73 {
74  coord = nullptr;
75 
76  ccw = true;
77  creaseAngle = 0.733f; // approx 42 degrees; this is larger than VRML spec.
78  creaseLimit = 0.74317f; // cos( 0.733 )
79 }
80 
81 
82 void X3DIFACESET::readFields( wxXmlNode* aNode )
83 {
84  // DEF
85  // ccw
86  // creaseAngle
87  // coordIndex
88 
89  wxXmlAttribute* prop;
90 
91  for( prop = aNode->GetAttributes(); prop != nullptr; prop = prop->GetNext() )
92  {
93  const wxString& pname = prop->GetName();
94 
95  if( pname == "DEF" )
96  {
97  m_Name = prop->GetValue();
98  m_Dict->AddName( m_Name, this );
99  }
100  else if( pname == "ccw" )
101  {
102  X3D::ParseSFBool( prop->GetValue(), ccw );
103  }
104  else if( pname == "creaseAngle" )
105  {
106  X3D::ParseSFFloat( prop->GetValue(), creaseAngle );
107 
108  if( creaseAngle < 0.0f )
109  creaseAngle = 0.0f;
110  else if( creaseAngle > static_cast<float>( M_PI * 0.34f ) )
111  creaseAngle = static_cast<float>( M_PI / 3.0f );
112 
113  creaseLimit = cosf( creaseAngle );
114  }
115  else if( pname == "coordIndex" )
116  {
117  wxStringTokenizer indices( prop->GetValue() );
118 
119  while( indices.HasMoreTokens() )
120  {
121  long index = 0;
122  indices.GetNextToken().ToLong( &index );
123  coordIndex.push_back( (int) index );
124  }
125  }
126  }
127 }
128 
129 
130 bool X3DIFACESET::Read( wxXmlNode* aNode, X3DNODE* aTopNode, X3D_DICT& aDict )
131 {
132  if( nullptr == aTopNode || nullptr == aNode )
133  return false;
134 
135  m_Dict = &aDict;
136  readFields( aNode );
137  bool ok = false;
138 
139  for( wxXmlNode* child = aNode->GetChildren(); child != nullptr; child = child->GetNext() )
140  {
141  if( child->GetName() == "Coordinate" )
142  ok = X3D::ReadCoordinates( child, this, aDict );
143 
144  }
145 
146  if( false == ok )
147  return false;
148 
149  if( !SetParent( aTopNode ) )
150  return false;
151 
152  return true;
153 }
154 
155 
156 bool X3DIFACESET::SetParent( X3DNODE* aParent, bool doUnlink )
157 {
158  if( aParent == m_Parent )
159  return true;
160 
161  if( nullptr != aParent )
162  {
163  X3DNODES nt = aParent->GetNodeType();
164 
165  if( nt != X3D_SHAPE )
166  return false;
167  }
168 
169  if( nullptr != m_Parent && doUnlink )
170  m_Parent->unlinkChildNode( this );
171 
172  m_Parent = aParent;
173 
174  if( nullptr != m_Parent )
175  m_Parent->AddChildNode( this );
176 
177  return true;
178 }
179 
180 
182 {
183  if( nullptr == aNode )
184  return false;
185 
186  if( aNode->GetNodeType() != X3D_COORDINATE )
187  return false;
188 
189  if( aNode == coord )
190  return true;
191 
192  if( nullptr != coord )
193  return false;
194 
195  m_Children.push_back( aNode );
196  coord = aNode;
197 
198  if( aNode->GetParent() != this )
199  aNode->SetParent( this );
200 
201  return true;
202 }
203 
204 
206 {
207  if( nullptr == aNode )
208  return false;
209 
210  if( aNode->GetNodeType() != X3D_COORDINATE )
211  return false;
212 
213  if( aNode == coord )
214  return true;
215 
216  if( nullptr != coord )
217  return false;
218 
219  m_Refs.push_back( aNode );
220  aNode->addNodeRef( this );
221  coord = aNode;
222  return true;
223 }
224 
225 
227 {
228  S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent );
229 
230  wxCHECK_MSG( aParent && ( ptype == S3D::SGTYPE_SHAPE ), nullptr,
231  wxString::Format( wxT( "IndexedFaceSet does not have a valid Shape parent "
232  "(parent ID: %d)" ),
233  ptype ) );
234 
235  wxLogTrace( traceVrmlPlugin,
236  wxT( " * [INFO] Translating IndexedFaceSet with %zu children, %zu references, "
237  "%zu back pointers, and %zu coordinate indices." ),
238  m_Children.size(), m_Refs.size(), m_BackPointers.size(), coordIndex.size() );
239 
240  if( m_sgNode )
241  {
242  if( nullptr != aParent )
243  {
244  if( nullptr == S3D::GetSGNodeParent( m_sgNode )
245  && !S3D::AddSGNodeChild( aParent, m_sgNode ) )
246  {
247  return nullptr;
248  }
249  else if( aParent != S3D::GetSGNodeParent( m_sgNode )
250  && !S3D::AddSGNodeRef( aParent, m_sgNode ) )
251  {
252  return nullptr;
253  }
254  }
255 
256  return m_sgNode;
257  }
258 
259  size_t vsize = coordIndex.size();
260 
261  if( nullptr == coord || vsize < 3 )
262  return nullptr;
263 
264  WRLVEC3F* pcoords;
265  size_t coordsize;
266  ((X3DCOORDS*) coord)->GetCoords( pcoords, coordsize );
267 
268  if( coordsize < 3 )
269  return nullptr;
270 
271  // check that all indices are valid
272  for( size_t idx = 0; idx < vsize; ++idx )
273  {
274  if( coordIndex[idx] < 0 )
275  continue;
276 
277  if( coordIndex[idx] >= (int)coordsize )
278  return nullptr;
279  }
280 
281  SHAPE lShape;
282  FACET* fp = nullptr;
283  size_t iCoord;
284  int idx; // coordinate index
285 
286  // no per-vertex colors; we can save a few CPU cycles
287  for( iCoord = 0; iCoord < vsize; ++iCoord )
288  {
289  idx = coordIndex[iCoord];
290 
291  if( idx < 0 )
292  {
293  if( nullptr != fp )
294  {
295  if( fp->HasMinPoints() )
296  fp = nullptr;
297  else
298  fp->Init();
299  }
300 
301  continue;
302  }
303 
304  // if the coordinate is bad then skip it
305  if( idx >= (int)coordsize )
306  continue;
307 
308  if( nullptr == fp )
309  fp = lShape.NewFacet();
310 
311  // push the vertex value and index
312  fp->AddVertex( pcoords[idx], idx );
313  }
314 
315  SGNODE* np = nullptr;
316 
317  if( ccw )
318  np = lShape.CalcShape( aParent, nullptr, WRL1_ORDER::ORD_CCW, creaseLimit, true );
319  else
320  np = lShape.CalcShape( aParent, nullptr, WRL1_ORDER::ORD_CLOCKWISE, creaseLimit, true );
321 
322  return np;
323 }
void readFields(wxXmlNode *aNode)
float creaseLimit
Definition: x3d_ifaceset.h:57
SGNODE * CalcShape(SGNODE *aParent, SGNODE *aColor, WRL1_ORDER aVertexOrder, float aCreaseLimit=0.74317, bool isVRML2=false)
Definition: wrlfacet.cpp:703
virtual bool SetParent(X3DNODE *aParent, bool doUnlink=true)=0
Set the parent X3DNODE of this object.
X3DNODE * coord
Definition: x3d_ifaceset.h:53
glm::vec3 WRLVEC3F
Definition: wrltypes.h:188
std::list< X3DNODE * > m_BackPointers
Definition: x3d_base.h:163
X3DNODES m_Type
Definition: x3d_base.h:160
X3DNODE * GetParent(void) const
Return a pointer to the parent node of this object or NULL if the object has no parent (ie.
Definition: x3d_base.cpp:190
void AddVertex(WRLVEC3F &aVertex, int aIndex)
Add the vertex and its associated index to the internal list of polygon vertices.
Definition: wrlfacet.cpp:191
void Init()
Definition: wrlfacet.cpp:158
wxString m_Name
Definition: x3d_base.h:168
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:492
void addNodeRef(X3DNODE *aNode)
Add a pointer to a node which references, but does not own, this node.
Definition: x3d_base.cpp:142
The base class of all Scene Graph nodes.
Definition: sg_node.h:74
collects header files for all SG* wrappers and the API
SGLIB_API bool AddSGNodeRef(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:501
std::list< X3DNODE * > m_Children
Definition: x3d_base.h:164
bool AddChildNode(X3DNODE *aNode) override
The base class of all X3D nodes.
Definition: x3d_base.h:74
declares classes to help manage normals calculations from VRML files
SGNODE * TranslateToSG(SGNODE *aParent) override
Produce a representation of the data using the intermediate scenegraph structures of the kicad_3dsg l...
bool SetParent(X3DNODE *aParent, bool doUnlink=true) override
Set the parent X3DNODE of this object.
SGLIB_API bool AddSGNodeChild(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:510
bool ParseSFFloat(const wxString &aSource, float &aResult)
Definition: x3d_ops.cpp:252
An abstract shape on 2D plane.
Definition: shape.h:116
virtual bool AddChildNode(X3DNODE *aNode)=0
X3DNODES GetNodeType(void) const
Return the type of this node instance.
Definition: x3d_base.cpp:184
virtual void unlinkChildNode(const X3DNODE *aNode)
Remove references to an owned child; it is invoked by the child upon destruction to ensure that the p...
Definition: x3d_base.cpp:102
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
std::vector< int > coordIndex
Definition: x3d_ifaceset.h:58
bool AddName(const wxString &aName, X3DNODE *aNode)
Definition: x3d_base.cpp:35
bool AddRefNode(X3DNODE *aNode) override
SGTYPES
Definition: sg_types.h:34
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
SGNODE * m_sgNode
Definition: x3d_base.h:169
bool ParseSFBool(const wxString &aSource, bool &aResult)
Definition: x3d_ops.cpp:231
SGLIB_API S3D::SGTYPES GetSGNodeType(SGNODE *aNode)
Definition: ifsg_api.cpp:483
X3DNODE * m_Parent
Definition: x3d_base.h:159
FACET * NewFacet()
Definition: wrlfacet.cpp:695
Definition: wrlfacet.h:42
virtual ~X3DIFACESET()
float creaseAngle
Definition: x3d_ifaceset.h:56
X3DNODES
Definition: x3d_base.h:59
X3D_DICT * m_Dict
Definition: x3d_base.h:161
bool ReadCoordinates(wxXmlNode *aNode, X3DNODE *aParent, X3D_DICT &aDict)
Definition: x3d_ops.cpp:193
bool Read(wxXmlNode *aNode, X3DNODE *aTopNode, X3D_DICT &aDict) override
bool HasMinPoints()
Definition: wrlfacet.cpp:173
std::list< X3DNODE * > m_Refs
Definition: x3d_base.h:165