KiCad PCB EDA Suite
vrml1_base.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 <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 #include <iostream>
26 #include <sstream>
27 #include <wx/log.h>
28 
29 #include "vrml1_base.h"
30 #include "vrml1_group.h"
31 #include "vrml1_separator.h"
32 #include "vrml1_material.h"
33 #include "vrml1_matbinding.h"
34 #include "vrml1_coords.h"
35 #include "vrml1_switch.h"
36 #include "vrml1_faceset.h"
37 #include "vrml1_transform.h"
38 #include "vrml1_shapehints.h"
39 #include "plugins/3dapi/ifsg_all.h"
40 
41 
43 {
46  return;
47 }
48 
49 
51 {
52  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] Destroying virtual base node." ) );
53 
54  cancelDict();
55 }
56 
57 
58 bool WRL1BASE::SetParent( WRL1NODE* aParent, bool /* doUnlink */ )
59 {
60  wxCHECK_MSG( false, false, wxT( "Attempt to set parent on WRL1BASE node." ) );
61 }
62 
63 
64 std::string WRL1BASE::GetName( void )
65 {
66  wxCHECK_MSG( false, std::string( "" ),
67  wxT( "Attempt to extract name from virtual base node." ) );
68 }
69 
70 
71 bool WRL1BASE::SetName( const std::string& aName )
72 {
73  wxCHECK_MSG( false, false, wxT( "Attempt to set name on virtual base node." ) );
74 }
75 
76 
77 bool WRL1BASE::Read( WRLPROC& proc )
78 {
79  wxCHECK_MSG( proc.GetVRMLType() == WRLVERSION::VRML_V1, false,
80  wxT( "No open file or file is not a VRML1 file" ) );
81 
82  // Note: according to the VRML1 specification, a file may contain
83  // only one grouping node at the top level. The following code
84  // supports non-conformant VRML1 files by processing all top level
85  // nodes as if the vrml1_base were the equivalent of a vrml1_separator
86 
87  while( proc.Peek() )
88  {
89  if( !ReadNode( proc, this, nullptr ) )
90  {
91  wxLogTrace( traceVrmlPlugin,
92  wxT( "%s:%s:%d\n * [INFO] bad file format; unexpected eof %s" ),
93  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition() );
94 
95  return false;
96  }
97  }
98 
99  if( !proc.eof() )
100  {
101  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n%s" ),
102  __FILE__, __FUNCTION__, __LINE__, proc.GetError() );
103 
104  return false;
105  }
106 
107  return true;
108 }
109 
110 
111 bool WRL1BASE::implementUse( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
112 {
113  if( nullptr != aNode )
114  *aNode = nullptr;
115 
116  wxCHECK_MSG( aParent, false, wxT( "Invoked with invalid parent." ) );
117 
118  std::string glob;
119 
120  if( !proc.ReadName( glob ) )
121  {
122  wxLogTrace( traceVrmlPlugin, wxT( "%s" ), proc.GetError() );
123 
124  return false;
125  }
126 
127  WRL1NODE* ref = aParent->FindNode( glob );
128 
129  // return 'true' - the file may be defective but it may still be somewhat OK
130  if( nullptr == ref )
131  {
132  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n * [INFO] node '%s' not found." ),
133  __FILE__, __FUNCTION__, __LINE__, glob );
134 
135  return true;
136  }
137 
138  if( !aParent->AddRefNode( ref ) )
139  {
140  wxLogTrace( traceVrmlPlugin,
141  wxT( "%s:%s:%d\n * [INFO] failed to add node '%s' (%s) to parent of type %s." ),
142  __FILE__, __FUNCTION__, __LINE__, glob,
143  ref->GetNodeTypeName( ref->GetNodeType() ),
144  aParent->GetNodeTypeName( aParent->GetNodeType() ) );
145 
146  return false;
147  }
148 
149  if( nullptr != aNode )
150  *aNode = ref;
151 
152  return true;
153 }
154 
155 
156 bool WRL1BASE::implementDef( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
157 {
158  if( nullptr != aNode )
159  *aNode = nullptr;
160 
161  wxCHECK_MSG( nullptr != aParent, false, wxT( "Invalid parent pointer." ) );
162 
163  std::string glob;
164  WRL1NODE* lnode = nullptr;
165 
166  if( !proc.ReadName( glob ) )
167  {
168  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n%s" ),
169  __FILE__, __FUNCTION__, __LINE__, proc.GetError() );
170 
171  return false;
172  }
173 
174  if( ReadNode( proc, aParent, &lnode ) )
175  {
176  if( nullptr != aNode )
177  *aNode = lnode;
178 
179  if( lnode && !lnode->SetName( glob ) )
180  {
181  wxLogTrace( traceVrmlPlugin,
182  wxT( "%s:%s:%d\n * [INFO] bad formatting (invalid name) %s." ),
183  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition() );
184 
185  return false;
186  }
187 
188  if( !m_dictionary )
189  return false;
190 
191  m_dictionary->AddName( glob, lnode );
192 
193  return true;
194  }
195 
196  return false;
197 }
198 
199 
200 bool WRL1BASE::ReadNode( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
201 {
202  // This function reads a node and stores a pointer to it in aNode.
203  // A value 'true' is returned if a node is successfully read or,
204  // if the node is not supported, successfully discarded. Callers
205  // must always check the value of aNode when the function returns
206  // 'true' since it will be NULL if the node type is not supported.
207 
208  if( nullptr != aNode )
209  *aNode = nullptr;
210 
211  wxCHECK_MSG( aParent, false, wxT( "Invalid parent pointer." ) );
212 
213  std::string glob;
214  WRL1NODES ntype;
215 
216  if( !proc.ReadName( glob ) )
217  {
218  if( !proc.eof() )
219  {
220  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n%s" ),
221  __FILE__, __FUNCTION__, __LINE__, proc.GetError() );
222  }
223 
224  return false;
225  }
226 
227  // Process node name:
228  // the names encountered at this point should be one of the
229  // built-in node names or one of:
230  // DEF, USE
231  if( !glob.compare( "USE" ) )
232  {
233  if( !implementUse( proc, aParent, aNode ) )
234  return false;
235 
236  return true;
237  }
238 
239  if( !glob.compare( "DEF" ) )
240  {
241  if( !implementDef( proc, aParent, aNode ) )
242  return false;
243 
244  return true;
245  }
246 
247  ntype = getNodeTypeID( glob );
248 
249  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] Processing node '%s' ID: %d." ), glob, ntype );
250 
251  switch( ntype )
252  {
254 
255  if( !readGroup( proc, aParent, aNode ) )
256  return false;
257 
258  break;
259 
261 
262  if( !readSeparator( proc, aParent, aNode ) )
263  return false;
264 
265  break;
266 
268 
269  if( !readSwitch( proc, aParent, aNode ) )
270  return false;
271 
272  break;
273 
275 
276  if( !readMaterial( proc, aParent, aNode ) )
277  return false;
278 
279  break;
280 
282 
283  if( !readMatBinding( proc, aParent, aNode ) )
284  return false;
285 
286  break;
287 
289 
290  if( !readCoords( proc, aParent, aNode ) )
291  return false;
292 
293  break;
294 
296 
297  if( !readFaceSet( proc, aParent, aNode ) )
298  return false;
299 
300  break;
301 
306 
307  if( !readTransform( proc, aParent, aNode ) )
308  return false;
309 
310  break;
311 
313 
314  if( !readShapeHints( proc, aParent, aNode ) )
315  return false;
316 
317  break;
318 
319  //
320  // items not implemented or for optional future implementation:
321  //
322  default:
323 
324  if( !proc.DiscardNode() )
325  {
326  wxLogTrace( traceVrmlPlugin,
327  wxT( "%s:%s:%d\n * [INFO] could not discard node %s." ),
328  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition() );
329 
330  return false;
331  }
332  else
333  {
334  wxLogTrace( traceVrmlPlugin,
335  wxT( " * [INFO] discarded node '%s' %s (currently unsupported)." ),
336  glob, proc.GetFilePosition() );
337  }
338 
339  break;
340  }
341 
342  return true;
343 }
344 
345 
346 bool WRL1BASE::Read( WRLPROC& proc, WRL1BASE* aTopNode )
347 {
348  wxCHECK_MSG( false, false, wxT( "This method must never be invoked on a WRL1BASE object" ) );
349 }
350 
351 
352 bool WRL1BASE::readGroup( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
353 {
354  if( nullptr != aNode )
355  *aNode = nullptr;
356 
357  WRL1GROUP* np = new WRL1GROUP( m_dictionary, aParent );
358 
359  if( !np->Read( proc, this ) )
360  {
361  delete np;
362  return false;
363  }
364 
365  if( nullptr != aNode )
366  *aNode = (WRL1NODE*) np;
367 
368  return true;
369 }
370 
371 
372 bool WRL1BASE::readSeparator( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
373 {
374  if( nullptr != aNode )
375  *aNode = nullptr;
376 
377  WRL1SEPARATOR* np = new WRL1SEPARATOR( m_dictionary, aParent );
378 
379  if( !np->Read( proc, this ) )
380  {
381  delete np;
382  return false;
383  }
384 
385  if( nullptr != aNode )
386  *aNode = (WRL1NODE*) np;
387 
388  return true;
389 }
390 
391 
392 bool WRL1BASE::readSwitch( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
393 {
394  WRL1SWITCH* np = new WRL1SWITCH( m_dictionary, aParent );
395 
396  if( !np->Read( proc, this ) )
397  {
398  delete np;
399  return false;
400  }
401 
402  if( nullptr != aNode )
403  *aNode = (WRL1NODE*) np;
404 
405  return true;
406 }
407 
408 
409 bool WRL1BASE::readMaterial( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
410 {
411  if( nullptr != aNode )
412  *aNode = nullptr;
413 
414  WRL1MATERIAL* np = new WRL1MATERIAL( m_dictionary, aParent );
415 
416  if( !np->Read( proc, this ) )
417  {
418  delete np;
419  return false;
420  }
421 
422  if( nullptr != aNode )
423  *aNode = (WRL1NODE*) np;
424 
425  return true;
426 }
427 
428 
429 bool WRL1BASE::readMatBinding( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
430 {
431  if( nullptr != aNode )
432  *aNode = nullptr;
433 
434  WRL1MATBINDING* np = new WRL1MATBINDING( m_dictionary, aParent );
435 
436  if( !np->Read( proc, this ) )
437  {
438  delete np;
439  return false;
440  }
441 
442  if( nullptr != aNode )
443  *aNode = (WRL1NODE*) np;
444 
445  return true;
446 }
447 
448 
449 bool WRL1BASE::readCoords( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
450 {
451  if( nullptr != aNode )
452  *aNode = nullptr;
453 
454  WRL1COORDS* np = new WRL1COORDS( m_dictionary, aParent );
455 
456  if( !np->Read( proc, this ) )
457  {
458  delete np;
459  return false;
460  }
461 
462  if( nullptr != aNode )
463  *aNode = (WRL1NODE*) np;
464 
465  return true;
466 }
467 
468 
469 bool WRL1BASE::readFaceSet( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
470 {
471  if( nullptr != aNode )
472  *aNode = nullptr;
473 
474  WRL1FACESET* np = new WRL1FACESET( m_dictionary, aParent );
475 
476  if( !np->Read( proc, this ) )
477  {
478  delete np;
479  return false;
480  }
481 
482  if( nullptr != aNode )
483  *aNode = (WRL1NODE*) np;
484 
485  return true;
486 }
487 
488 
489 bool WRL1BASE::readTransform( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
490 {
491  if( nullptr != aNode )
492  *aNode = nullptr;
493 
494  WRL1TRANSFORM* np = new WRL1TRANSFORM( m_dictionary, aParent );
495 
496  if( !np->Read( proc, this ) )
497  {
498  delete np;
499  return false;
500  }
501 
502  if( nullptr != aNode )
503  *aNode = (WRL1NODE*) np;
504 
505  return true;
506 }
507 
508 
509 bool WRL1BASE::readShapeHints( WRLPROC& proc, WRL1NODE* aParent, WRL1NODE** aNode )
510 {
511  if( nullptr != aNode )
512  *aNode = nullptr;
513 
514  WRL1SHAPEHINTS* np = new WRL1SHAPEHINTS( m_dictionary, aParent );
515 
516  if( !np->Read( proc, this ) )
517  {
518  delete np;
519  return false;
520  }
521 
522  if( nullptr != aNode )
523  *aNode = (WRL1NODE*) np;
524 
525  return true;
526 }
527 
528 
530 {
531  wxLogTrace( traceVrmlPlugin, wxT( " * [INFO] Translating VRML1 Base with %zu items." ),
532  m_Items.size() );
533 
534  if( m_Items.empty() )
535  return nullptr;
536 
537  if( m_Items.size() == 1 )
538  return ( *m_Items.begin() )->TranslateToSG( nullptr, nullptr );
539 
540  // Note: according to the VRML1 specification, a file may contain
541  // only one grouping node at the top level. The following code
542  // supports non-conformant VRML1 files.
543 
544  m_current.Init();
545 
546  IFSG_TRANSFORM txNode( true );
547  bool hasContent = false;
548 
549  std::list< WRL1NODE* >::iterator sI = m_Items.begin();
550  std::list< WRL1NODE* >::iterator eI = m_Items.end();
551 
552  SGNODE* node = txNode.GetRawPtr();
553 
554  while( sI != eI )
555  {
556  if( nullptr != (*sI)->TranslateToSG( node, &m_current ) )
557  hasContent = true;
558 
559  ++sI;
560  }
561 
562  if( !hasContent )
563  {
564  txNode.Destroy();
565  return nullptr;
566  }
567 
568  return node;
569 }
Represent the top node of a VRML1 model.
Definition: vrml1_base.h:45
bool implementUse(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:111
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
bool SetParent(WRL1NODE *aParent, bool doUnlink=true) override
Set the parent WRL1NODE of this object.
Definition: vrml1_base.cpp:58
const char * GetNodeTypeName(WRL1NODES aNodeType) const
Definition: vrml1_node.cpp:312
bool readSeparator(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:372
void cancelDict(void)
Definition: vrml1_node.cpp:198
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
virtual std::string GetName(void) override
Definition: vrml1_base.cpp:64
WRLVERSION GetVRMLType(void)
Definition: wrlproc.cpp:230
WRL1STATUS m_current
Definition: vrml1_node.h:236
bool Read(WRLPROC &proc)
Definition: vrml1_base.cpp:77
The base class of all Scene Graph nodes.
Definition: sg_node.h:74
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
collects header files for all SG* wrappers and the API
void Init()
Definition: vrml1_node.h:74
SGNODE * GetRawPtr(void) noexcept
Function GetRawPtr() returns the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:65
bool readSwitch(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:392
bool readGroup(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:352
virtual ~WRL1BASE()
Definition: vrml1_base.cpp:50
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
bool AddName(const std::string &aName, WRL1NODE *aNode)
Definition: vrml1_node.cpp:39
bool readCoords(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:449
bool readTransform(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:489
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
SGNODE * TranslateToSG(SGNODE *aParent, WRL1STATUS *sp) override
Produce a representation of the data using the intermediate scenegraph structures of the kicad_3dsg l...
Definition: vrml1_base.cpp:529
virtual bool AddRefNode(WRL1NODE *aNode)
Definition: vrml1_node.cpp:403
bool ReadNode(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:200
The base class of all VRML1 nodes.
Definition: vrml1_node.h:116
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
bool DiscardNode(void)
Definition: wrlproc.cpp:368
std::string GetFilePosition() const
Definition: wrlproc.cpp:1982
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
char Peek(void)
Definition: wrlproc.cpp:2007
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
Definition: vrml1_group.cpp:66
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
NAMEREGISTER * m_dictionary
Definition: vrml1_node.h:246
bool implementDef(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:156
bool readShapeHints(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:509
WRL1NODES GetNodeType(void) const
Return the type of this node instance.
Definition: vrml1_node.cpp:254
WRL1NODES m_Type
Definition: vrml1_node.h:227
virtual bool SetName(const std::string &aName) override
Definition: vrml1_base.cpp:71
bool ReadName(std::string &aName)
Definition: wrlproc.cpp:289
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
bool readMatBinding(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:429
std::list< WRL1NODE * > m_Items
Definition: vrml1_node.h:233
IFSG_TRANSFORM is the wrapper for the VRML compatible TRANSFORM block class SCENEGRAPH.
WRL1NODES
Definition: wrltypes.h:55
std::string GetError(void)
Definition: wrlproc.cpp:1960
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
Definition: ifsg_node.cpp:55
bool readMaterial(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:409
bool eof(void)
Definition: wrlproc.cpp:1954
virtual bool SetName(const std::string &aName)
Definition: vrml1_node.cpp:272
bool Read(WRLPROC &proc, WRL1BASE *aTopNode) override
bool readFaceSet(WRLPROC &proc, WRL1NODE *aParent, WRL1NODE **aNode)
Definition: vrml1_base.cpp:469