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
39bool 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.emplace( aName, aNode );
50
51 return true;
52}
53
54
55bool 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
72WRL1NODE* 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
86typedef std::pair< std::string, WRL1NODES > NODEITEM;
87typedef 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.emplace( NODEITEM( "AsciiText", WRL1NODES::WRL1_ASCIITEXT ) );
101 nodenames.emplace( NODEITEM( "Cone", WRL1NODES::WRL1_CONE ) );
102 nodenames.emplace( NODEITEM( "Coordinate3", WRL1NODES::WRL1_COORDINATE3 ) );
103 nodenames.emplace( NODEITEM( "Cube", WRL1NODES::WRL1_CUBE ) );
104 nodenames.emplace( NODEITEM( "Cylinder", WRL1NODES::WRL1_CYLINDER ) );
105 nodenames.emplace( NODEITEM( "DirectionalLight", WRL1NODES::WRL1_DIRECTIONALLIGHT ) );
106 nodenames.emplace( NODEITEM( "FontStyle", WRL1NODES::WRL1_FONTSTYLE ) );
107 nodenames.emplace( NODEITEM( "Group", WRL1NODES::WRL1_GROUP ) );
108 nodenames.emplace( NODEITEM( "IndexedFaceSet", WRL1NODES::WRL1_INDEXEDFACESET ) );
109 nodenames.emplace( NODEITEM( "IndexedLineSet", WRL1NODES::WRL1_INDEXEDLINESET ) );
110 nodenames.emplace( NODEITEM( "Info", WRL1NODES::WRL1_INFO ) );
111 nodenames.emplace( NODEITEM( "LOD", WRL1NODES::WRL1_LOD ) );
112 nodenames.emplace( NODEITEM( "Material", WRL1NODES::WRL1_MATERIAL ) );
113 nodenames.emplace( NODEITEM( "MaterialBinding", WRL1NODES::WRL1_MATERIALBINDING ) );
114 nodenames.emplace( NODEITEM( "MatrixTransform", WRL1NODES::WRL1_MATRIXTRANSFORM ) );
115 nodenames.emplace( NODEITEM( "Normal", WRL1NODES::WRL1_NORMAL ) );
116 nodenames.emplace( NODEITEM( "NormalBinding", WRL1NODES::WRL1_NORMALBINDING ) );
117 nodenames.emplace( NODEITEM( "OrthographicCamera", WRL1NODES::WRL1_ORTHOCAMERA ) );
118 nodenames.emplace( NODEITEM( "PerspectiveCamera", WRL1NODES::WRL1_PERSPECTIVECAMERA ) );
119 nodenames.emplace( NODEITEM( "PointLight", WRL1NODES::WRL1_POINTLIGHT ) );
120 nodenames.emplace( NODEITEM( "PointSet", WRL1NODES::WRL1_POINTSET ) );
121 nodenames.emplace( NODEITEM( "Rotation", WRL1NODES::WRL1_ROTATION ) );
122 nodenames.emplace( NODEITEM( "Scale", WRL1NODES::WRL1_SCALE ) );
123 nodenames.emplace( NODEITEM( "Separator", WRL1NODES::WRL1_SEPARATOR ) );
124 nodenames.emplace( NODEITEM( "ShapeHints", WRL1NODES::WRL1_SHAPEHINTS ) );
125 nodenames.emplace( NODEITEM( "Sphere", WRL1NODES::WRL1_SPHERE ) );
126 nodenames.emplace( NODEITEM( "SpotLight", WRL1NODES::WRL1_SPOTLIGHT ) );
127 nodenames.emplace( NODEITEM( "Switch", WRL1NODES::WRL1_SWITCH ) );
128 nodenames.emplace( NODEITEM( "Texture2", WRL1NODES::WRL1_TEXTURE2 ) );
129 nodenames.emplace( NODEITEM( "Testure2Transform", WRL1NODES::WRL1_TEXTURE2TRANSFORM ) );
130 nodenames.emplace( NODEITEM( "TextureCoordinate2", WRL1NODES::WRL1_TEXTURECOORDINATE2 ) );
131 nodenames.emplace( NODEITEM( "Transform", WRL1NODES::WRL1_TRANSFORM ) );
132 nodenames.emplace( NODEITEM( "Translation", WRL1NODES::WRL1_TRANSLATION ) );
133 nodenames.emplace( NODEITEM( "WWWAnchor", WRL1NODES::WRL1_WWWANCHOR ) );
134 nodenames.emplace( 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
266std::string WRL1NODE::GetName( void )
267{
268 return m_Name;
269}
270
271
272bool 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
312const 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
327WRL1NODES 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
338size_t WRL1NODE::GetNItems( void ) const
339{
340 return m_Items.size();
341}
342
343
344std::string WRL1NODE::GetError( void )
345{
346 return m_error;
347}
348
349
350WRL1NODE* 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
359bool 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
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
464void 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}
bool AddName(const std::string &aName, WRL1NODE *aNode)
Definition: vrml1_node.cpp:39
WRL1NODE * FindName(const std::string &aName)
Definition: vrml1_node.cpp:72
bool DelName(const std::string &aName, WRL1NODE *aNode)
Definition: vrml1_node.cpp:55
std::map< std::string, WRL1NODE * > reg
Definition: vrml1_node.h:55
The base class of all VRML1 nodes.
Definition: vrml1_node.h:117
std::string m_Name
Definition: vrml1_node.h:228
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
std::string GetError(void)
Definition: vrml1_node.cpp:344
void delNodeRef(WRL1NODE *aNode)
Remove a pointer to a node which references, but does not own, this node.
Definition: vrml1_node.cpp:237
WRL1NODE(NAMEREGISTER *aDictionary)
Definition: vrml1_node.cpp:91
WRL1NODES m_Type
Definition: vrml1_node.h:227
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::list< WRL1NODE * > m_Items
Definition: vrml1_node.h:233
NAMEREGISTER * m_dictionary
Definition: vrml1_node.h:246
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
void addNodeRef(WRL1NODE *aNode)
Add a pointer to a node which references, but does not own, this node.
Definition: vrml1_node.cpp:216
void cancelDict(void)
Definition: vrml1_node.cpp:198
virtual bool AddRefNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:403
virtual bool AddChildNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:376
virtual std::string GetName(void)
Definition: vrml1_node.cpp:266
virtual bool SetParent(WRL1NODE *aParent, bool doUnlink=true)
Set the parent WRL1NODE of this object.
Definition: vrml1_node.cpp:359
std::list< WRL1NODE * > m_BackPointers
Definition: vrml1_node.h:230
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
std::list< WRL1NODE * > m_Children
Definition: vrml1_node.h:231
virtual ~WRL1NODE()
Definition: vrml1_node.cpp:139
size_t GetNItems(void) const
Definition: vrml1_node.cpp:338
std::string m_error
Definition: vrml1_node.h:234
virtual bool SetName(const std::string &aName)
Definition: vrml1_node.cpp:272
WRL1NODE * m_Parent
Definition: vrml1_node.h:226
void addItem(WRL1NODE *aNode)
Definition: vrml1_node.cpp:458
const char * GetNodeTypeName(WRL1NODES aNodeType) const
Definition: vrml1_node.cpp:312
std::list< WRL1NODE * > m_Refs
Definition: vrml1_node.h:232
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
SGNODE * m_sgNode
Definition: vrml1_node.h:237
WRL1NODES GetNodeType(void) const
Return the type of this node instance.
Definition: vrml1_node.cpp:254
void delItem(const WRL1NODE *aNode)
Definition: vrml1_node.cpp:464
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
std::map< std::string, std::vector< SGNODE * > > NODEMAP
Definition: loadmodel.cpp:102
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
#define BAD_CHARS2
#define BAD_CHARS1
static NODEMAP nodenames
Definition: vrml1_node.cpp:88
std::map< std::string, WRL1NODES > NODEMAP
Definition: vrml1_node.cpp:87
std::pair< std::string, WRL1NODES > NODEITEM
Definition: vrml1_node.cpp:86
WRL1NODES
Definition: wrltypes.h:56
@ WRL1_NORMALBINDING
@ WRL1_INDEXEDFACESET
@ WRL1_PERSPECTIVECAMERA
@ WRL1_DIRECTIONALLIGHT
@ WRL1_COORDINATE3
@ WRL1_TRANSLATION
@ WRL1_MATERIALBINDING
@ WRL1_INDEXEDLINESET
@ WRL1_MATRIXTRANSFORM
@ WRL1_ORTHOCAMERA
@ WRL1_TEXTURECOORDINATE2
@ WRL1_TEXTURE2TRANSFORM