KiCad PCB EDA Suite
vrml1_node.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) 2015-2016 Cirilo Bernardo <[email protected]>
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 <set>
27 #include <map>
28 #include <utility>
29 #include <iterator>
30 #include <cctype>
31 #include <iostream>
32 #include <algorithm>
33 #include <sstream>
34 #include <wx/log.h>
35 
36 #include "vrml1_node.h"
37 
38 
39 bool NAMEREGISTER::AddName( const std::string& aName, WRL1NODE* aNode )
40 {
41  if( aName.empty() )
42  return false;
43 
44  std::map< std::string, WRL1NODE* >::iterator ir = reg.find( aName );
45 
46  if( ir != reg.end() )
47  reg.erase( ir );
48 
49  reg.insert( std::pair< std::string, WRL1NODE* >( aName, aNode ) );
50 
51  return true;
52 }
53 
54 
55 bool NAMEREGISTER::DelName( const std::string& aName, WRL1NODE* aNode )
56 {
57  if( aName.empty() )
58  return false;
59 
60  std::map< std::string, WRL1NODE* >::iterator ir = reg.find( aName );
61 
62  if( ir != reg.end() && ir->second == aNode )
63  {
64  reg.erase( ir );
65  return true;
66  }
67 
68  return false;
69 }
70 
71 
72 WRL1NODE* NAMEREGISTER::FindName( const std::string& aName )
73 {
74  if( aName.empty() )
75  return nullptr;
76 
77  std::map< std::string, WRL1NODE* >::iterator ir = reg.find( aName );
78 
79  if( ir != reg.end() )
80  return ir->second;
81 
82  return nullptr;
83 }
84 
85 
86 typedef std::pair< std::string, WRL1NODES > NODEITEM;
87 typedef std::map< std::string, WRL1NODES > NODEMAP;
89 
90 
92 {
93  m_sgNode = nullptr;
94  m_Parent = nullptr;
96  m_dictionary = aDictionary;
97 
98  if( nodenames.empty() )
99  {
100  nodenames.insert( NODEITEM( "AsciiText", WRL1NODES::WRL1_ASCIITEXT ) );
101  nodenames.insert( NODEITEM( "Cone", WRL1NODES::WRL1_CONE ) );
102  nodenames.insert( NODEITEM( "Coordinate3", WRL1NODES::WRL1_COORDINATE3 ) );
103  nodenames.insert( NODEITEM( "Cube", WRL1NODES::WRL1_CUBE ) );
104  nodenames.insert( NODEITEM( "Cylinder", WRL1NODES::WRL1_CYLINDER ) );
105  nodenames.insert( NODEITEM( "DirectionalLight", WRL1NODES::WRL1_DIRECTIONALLIGHT ) );
106  nodenames.insert( NODEITEM( "FontStyle", WRL1NODES::WRL1_FONTSTYLE ) );
107  nodenames.insert( NODEITEM( "Group", WRL1NODES::WRL1_GROUP ) );
108  nodenames.insert( NODEITEM( "IndexedFaceSet", WRL1NODES::WRL1_INDEXEDFACESET ) );
109  nodenames.insert( NODEITEM( "IndexedLineSet", WRL1NODES::WRL1_INDEXEDLINESET ) );
110  nodenames.insert( NODEITEM( "Info", WRL1NODES::WRL1_INFO ) );
111  nodenames.insert( NODEITEM( "LOD", WRL1NODES::WRL1_LOD ) );
112  nodenames.insert( NODEITEM( "Material", WRL1NODES::WRL1_MATERIAL ) );
113  nodenames.insert( NODEITEM( "MaterialBinding", WRL1NODES::WRL1_MATERIALBINDING ) );
114  nodenames.insert( NODEITEM( "MatrixTransform", WRL1NODES::WRL1_MATRIXTRANSFORM ) );
115  nodenames.insert( NODEITEM( "Normal", WRL1NODES::WRL1_NORMAL ) );
116  nodenames.insert( NODEITEM( "NormalBinding", WRL1NODES::WRL1_NORMALBINDING ) );
117  nodenames.insert( NODEITEM( "OrthographicCamera", WRL1NODES::WRL1_ORTHOCAMERA ) );
118  nodenames.insert( NODEITEM( "PerspectiveCamera", WRL1NODES::WRL1_PERSPECTIVECAMERA ) );
119  nodenames.insert( NODEITEM( "PointLight", WRL1NODES::WRL1_POINTLIGHT ) );
120  nodenames.insert( NODEITEM( "PointSet", WRL1NODES::WRL1_POINTSET ) );
121  nodenames.insert( NODEITEM( "Rotation", WRL1NODES::WRL1_ROTATION ) );
122  nodenames.insert( NODEITEM( "Scale", WRL1NODES::WRL1_SCALE ) );
123  nodenames.insert( NODEITEM( "Separator", WRL1NODES::WRL1_SEPARATOR ) );
124  nodenames.insert( NODEITEM( "ShapeHints", WRL1NODES::WRL1_SHAPEHINTS ) );
125  nodenames.insert( NODEITEM( "Sphere", WRL1NODES::WRL1_SPHERE ) );
126  nodenames.insert( NODEITEM( "SpotLight", WRL1NODES::WRL1_SPOTLIGHT ) );
127  nodenames.insert( NODEITEM( "Switch", WRL1NODES::WRL1_SWITCH ) );
128  nodenames.insert( NODEITEM( "Texture2", WRL1NODES::WRL1_TEXTURE2 ) );
129  nodenames.insert( NODEITEM( "Testure2Transform", WRL1NODES::WRL1_TEXTURE2TRANSFORM ) );
130  nodenames.insert( NODEITEM( "TextureCoordinate2", WRL1NODES::WRL1_TEXTURECOORDINATE2 ) );
131  nodenames.insert( NODEITEM( "Transform", WRL1NODES::WRL1_TRANSFORM ) );
132  nodenames.insert( NODEITEM( "Translation", WRL1NODES::WRL1_TRANSLATION ) );
133  nodenames.insert( NODEITEM( "WWWAnchor", WRL1NODES::WRL1_WWWANCHOR ) );
134  nodenames.insert( NODEITEM( "WWWInline", WRL1NODES::WRL1_WWWINLINE ) );
135  }
136 }
137 
138 
140 {
141  wxLogTrace( traceVrmlPlugin,
142  wxT( " * [INFO] ^^ Destroying Type %d with %lu children, %lu references, and %lu "
143  "back pointers." ),
144  m_Type, m_Children.size(), m_Refs.size(), m_BackPointers.size() );
145 
146  m_Items.clear();
147 
148  if( m_dictionary && !m_Name.empty() )
149  m_dictionary->DelName( m_Name, this );
150 
151  if( m_Parent )
152  m_Parent->unlinkChildNode( this );
153 
154  std::list< WRL1NODE* >::iterator sBP = m_BackPointers.begin();
155  std::list< WRL1NODE* >::iterator eBP = m_BackPointers.end();
156 
157  while( sBP != eBP )
158  {
159  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO]%sType %d is unlinking ref #%d" ),
160  wxString( ' ', (size_t) std::distance( sBP, m_BackPointers.begin() ) * 2 ),
161  m_Type, std::distance( sBP, m_BackPointers.begin() ) );
162 
163  (*sBP)->unlinkRefNode( this );
164 
165  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO]%sType %d has unlinked ref #%d" ),
166  wxString( ' ', (size_t) std::distance( sBP, m_BackPointers.begin() ) * 2 ),
167  m_Type, std::distance( sBP, m_BackPointers.begin() ) );
168 
169  ++sBP;
170  }
171 
172  m_Refs.clear();
173 
174  std::list< WRL1NODE* >::iterator sC = m_Children.begin();
175  std::list< WRL1NODE* >::iterator eC = m_Children.end();
176 
177  while( sC != eC )
178  {
179  (*sC)->SetParent( nullptr, false );
180 
181  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO]%sType %d has unlinked child #%d" ),
182  wxString( ' ', (size_t) std::distance( sC, m_Children.begin() ) * 2 ),
183  m_Type, std::distance( sC, m_Children.begin() ) );
184 
185  delete *sC;
186 
187  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO]%sType %d has deleted child #%d" ),
188  wxString( ' ', (size_t) std::distance( sC, m_Children.begin() ) * 2 ),
189  m_Type, std::distance( sC, m_Children.begin() ) );
190 
191  ++sC;
192  }
193 
194  m_Children.clear();
195 }
196 
197 
199 {
200  std::list< WRL1NODE* >::iterator sC = m_Children.begin();
201  std::list< WRL1NODE* >::iterator eC = m_Children.end();
202 
203  while( sC != eC )
204  {
205  (*sC)->cancelDict();
206  ++sC;
207  }
208 
209  if( m_Type == WRL1NODES::WRL1_BASE && nullptr != m_dictionary )
210  delete m_dictionary;
211 
212  m_dictionary = nullptr;
213 }
214 
215 
217 {
218  // the parent node must never be added as a backpointer
219  if( aNode == m_Parent )
220  return;
221 
222  std::list< WRL1NODE* >::iterator sR = m_BackPointers.begin();
223  std::list< WRL1NODE* >::iterator eR = m_BackPointers.end();
224 
225  while( sR != eR )
226  {
227  if( *sR == aNode )
228  return;
229 
230  ++sR;
231  }
232 
233  m_BackPointers.push_back( aNode );
234 }
235 
236 
238 {
239  std::list< WRL1NODE* >::iterator np = std::find( m_BackPointers.begin(),
240  m_BackPointers.end(), aNode );
241 
242  if( np != m_BackPointers.end() )
243  {
244  m_BackPointers.erase( np );
245  return;
246  }
247 
248  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
249  " * [BUG] delNodeRef() did not find its target." ),
250  __FILE__, __FUNCTION__, __LINE__ );
251 }
252 
253 
255 {
256  return m_Type;
257 }
258 
259 
261 {
262  return m_Parent;
263 }
264 
265 
266 std::string WRL1NODE::GetName( void )
267 {
268  return m_Name;
269 }
270 
271 
272 bool WRL1NODE::SetName( const std::string& aName )
273 {
274  if( aName.empty() )
275  return false;
276 
277  if( isdigit( aName[0] ) )
278  {
279  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
280  " * [INFO] invalid node name '%s' (begins with digit)" ),
281  __FILE__, __FUNCTION__, __LINE__, aName );
282 
283  return false;
284  }
285 
286  // The character '+' is not allowed in names as per the VRML1 specification;
287  // however many parsers accept them and many bad generators use them so the rules
288  // have been relaxed here.
289  #define BAD_CHARS1 "\"\'#,.\\[]{}\x00\x01\x02\x03\x04\x05\x06\x09\x0A\x0B\x0C\x0D\x0E\x0F"
290  #define BAD_CHARS2 "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
291 
292  if( std::string::npos != aName.find_first_of( BAD_CHARS1 )
293  || std::string::npos != aName.find_first_of( BAD_CHARS2 ) )
294  {
295  wxLogTrace( traceVrmlPlugin,
296  wxT( "%s:%s:%d\n"
297  " * [INFO] invalid node name '%s' (contains invalid character)" ),
298  __FILE__, __FUNCTION__, __LINE__, aName );
299 
300  return false;
301  }
302 
303  m_Name = aName;
304 
305  if( m_dictionary )
306  m_dictionary->AddName( aName, this );
307 
308  return true;
309 }
310 
311 
312 const char* WRL1NODE::GetNodeTypeName( WRL1NODES aNodeType ) const
313 {
314  if( aNodeType < WRL1NODES::WRL1_BASE || aNodeType >= WRL1NODES::WRL1_END )
315  return "*INVALID_TYPE*";
316 
317  if( aNodeType == WRL1NODES::WRL1_BASE )
318  return "*VIRTUAL_BASE*";
319 
320  NODEMAP::iterator it = nodenames.begin();
321  advance( it, ( static_cast<int>( aNodeType ) - static_cast<int>( WRL1NODES::WRL1_BEGIN ) ) );
322 
323  return it->first.c_str();
324 }
325 
326 
327 WRL1NODES WRL1NODE::getNodeTypeID( const std::string& aNodeName )
328 {
329  NODEMAP::iterator it = nodenames.find( aNodeName );
330 
331  if( nodenames.end() != it )
332  return it->second;
333 
335 }
336 
337 
338 size_t WRL1NODE::GetNItems( void ) const
339 {
340  return m_Items.size();
341 }
342 
343 
344 std::string WRL1NODE::GetError( void )
345 {
346  return m_error;
347 }
348 
349 
350 WRL1NODE* WRL1NODE::FindNode( const std::string& aNodeName )
351 {
352  if( nullptr == m_dictionary )
353  return nullptr;
354 
355  return m_dictionary->FindName( aNodeName );
356 }
357 
358 
359 bool WRL1NODE::SetParent( WRL1NODE* aParent, bool doUnlink )
360 {
361  if( aParent == m_Parent )
362  return true;
363 
364  if( nullptr != m_Parent && doUnlink )
365  m_Parent->unlinkChildNode( this );
366 
367  m_Parent = aParent;
368 
369  if( nullptr != m_Parent )
370  m_Parent->AddChildNode( this );
371 
372  return true;
373 }
374 
375 
377 {
378  wxCHECK_MSG( aNode, false, wxT( "Invalid node pointer." ) );
379  wxCHECK_MSG( aNode->GetNodeType() != WRL1NODES::WRL1_BASE, false,
380  wxT( "Attempting to add a base node to another node." ) );
381 
382  std::list< WRL1NODE* >::iterator sC = m_Children.begin();
383  std::list< WRL1NODE* >::iterator eC = m_Children.end();
384 
385  while( sC != eC )
386  {
387  if( *sC == aNode )
388  return false;
389 
390  ++sC;
391  }
392 
393  m_Children.push_back( aNode );
394  addItem( aNode );
395 
396  if( aNode->GetParent() != this )
397  aNode->SetParent( this );
398 
399  return true;
400 }
401 
402 
404 {
405  wxCHECK_MSG( aNode, false, wxT( "Invalid node pointer." ) );
406  wxCHECK_MSG( aNode->GetNodeType() != WRL1NODES::WRL1_BASE, false,
407  wxT( "Attempt to add a base node reference to another base node" ) );
408 
409  // note: the VRML1 spec does not prevent the reuse of a node at
410  // the same level; for example a Coordinate3 node can be recalled
411  // at any time to set the current coordinate set.
412  m_Refs.push_back( aNode );
413  aNode->addNodeRef( this );
414  addItem( aNode );
415 
416  return true;
417 }
418 
419 
421 {
422  std::list< WRL1NODE* >::iterator sL = m_Children.begin();
423  std::list< WRL1NODE* >::iterator eL = m_Children.end();
424 
425  while( sL != eL )
426  {
427  if( *sL == aNode )
428  {
429  m_Children.erase( sL );
430  delItem( aNode );
431  return;
432  }
433 
434  ++sL;
435  }
436 }
437 
438 
439 void WRL1NODE::unlinkRefNode( const WRL1NODE* aNode )
440 {
441  std::list< WRL1NODE* >::iterator sL = m_Refs.begin();
442  std::list< WRL1NODE* >::iterator eL = m_Refs.end();
443 
444  while( sL != eL )
445  {
446  if( *sL == aNode )
447  {
448  m_Refs.erase( sL );
449  delItem( aNode );
450  return;
451  }
452 
453  ++sL;
454  }
455 }
456 
457 
459 {
460  m_Items.push_back( aNode );
461 }
462 
463 
464 void WRL1NODE::delItem( const WRL1NODE* aNode )
465 {
466  std::list< WRL1NODE* >::iterator sL = m_Items.begin();
467  std::list< WRL1NODE* >::iterator eL = m_Items.end();
468 
469  while( sL != eL )
470  {
471  if( *sL == aNode )
472  {
473  m_Items.erase( sL );
474  return;
475  }
476 
477  ++sL;
478  }
479 }
void delNodeRef(WRL1NODE *aNode)
Remove a pointer to a node which references, but does not own, this node.
Definition: vrml1_node.cpp:237
virtual WRL1NODE * FindNode(const std::string &aNodeName)
Search the tree of linked nodes and returns a reference to the current node with the given name.
Definition: vrml1_node.cpp:350
const char * GetNodeTypeName(WRL1NODES aNodeType) const
Definition: vrml1_node.cpp:312
void cancelDict(void)
Definition: vrml1_node.cpp:198
void addNodeRef(WRL1NODE *aNode)
Add a pointer to a node which references, but does not own, this node.
Definition: vrml1_node.cpp:216
virtual ~WRL1NODE()
Definition: vrml1_node.cpp:139
virtual void unlinkRefNode(const WRL1NODE *aNode)
Remove pointers to a referenced node; it is invoked by the referenced node upon destruction to ensure...
Definition: vrml1_node.cpp:439
WRL1NODES getNodeTypeID(const std::string &aNodeName)
Return the ID based on the given aNodeName or WRL1_INVALID (WRL1_END) if no such node name exists.
Definition: vrml1_node.cpp:327
std::string m_Name
Definition: vrml1_node.h:228
std::list< WRL1NODE * > m_BackPointers
Definition: vrml1_node.h:230
std::map< std::string, std::vector< SGNODE * > > NODEMAP
Definition: loadmodel.cpp:101
size_t GetNItems(void) const
Definition: vrml1_node.cpp:338
std::string GetError(void)
Definition: vrml1_node.cpp:344
std::map< std::string, WRL1NODE * > reg
Definition: vrml1_node.h:55
bool DelName(const std::string &aName, WRL1NODE *aNode)
Definition: vrml1_node.cpp:55
bool AddName(const std::string &aName, WRL1NODE *aNode)
Definition: vrml1_node.cpp:39
std::list< WRL1NODE * > m_Refs
Definition: vrml1_node.h:232
WRL1NODE * GetParent(void) const
Return a pointer to the parent SGNODE of this object or NULL if the object has no parent (ie.
Definition: vrml1_node.cpp:260
virtual void unlinkChildNode(const WRL1NODE *aNode)
Remove references to an owned child; it is invoked by the child upon destruction to ensure that the p...
Definition: vrml1_node.cpp:420
virtual bool AddRefNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:403
The base class of all VRML1 nodes.
Definition: vrml1_node.h:116
WRL1NODE(NAMEREGISTER *aDictionary)
Definition: vrml1_node.cpp:91
void delItem(const WRL1NODE *aNode)
Definition: vrml1_node.cpp:464
std::string m_error
Definition: vrml1_node.h:234
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
virtual bool AddChildNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:376
WRL1NODE * FindName(const std::string &aName)
Definition: vrml1_node.cpp:72
NAMEREGISTER * m_dictionary
Definition: vrml1_node.h:246
static NODEMAP nodenames
Definition: vrml1_node.cpp:88
virtual bool SetParent(WRL1NODE *aParent, bool doUnlink=true)
Set the parent WRL1NODE of this object.
Definition: vrml1_node.cpp:359
WRL1NODES GetNodeType(void) const
Return the type of this node instance.
Definition: vrml1_node.cpp:254
WRL1NODES m_Type
Definition: vrml1_node.h:227
std::map< std::string, WRL1NODES > NODEMAP
Definition: vrml1_node.cpp:87
std::list< WRL1NODE * > m_Items
Definition: vrml1_node.h:233
#define BAD_CHARS2
WRL1NODES
Definition: wrltypes.h:55
std::pair< std::string, WRL1NODES > NODEITEM
Definition: vrml1_node.cpp:86
WRL1NODE * m_Parent
Definition: vrml1_node.h:226
void addItem(WRL1NODE *aNode)
Definition: vrml1_node.cpp:458
#define BAD_CHARS1
SGNODE * m_sgNode
Definition: vrml1_node.h:237
virtual std::string GetName(void)
Definition: vrml1_node.cpp:266
virtual bool SetName(const std::string &aName)
Definition: vrml1_node.cpp:272
std::list< WRL1NODE * > m_Children
Definition: vrml1_node.h:231