KiCad PCB EDA Suite
vrml2_shape.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  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include <iostream>
26 #include <sstream>
27 #include <wx/log.h>
28 
29 #include "vrml2_base.h"
30 #include "vrml2_shape.h"
31 #include "plugins/3dapi/ifsg_all.h"
32 #include "vrml2_faceset.h"
33 
34 
36 {
37  appearance = NULL;
38  geometry = NULL;
40  return;
41 }
42 
43 
45 {
46  appearance = NULL;
47  geometry = NULL;
49  m_Parent = aParent;
50 
51  if( NULL != m_Parent )
52  m_Parent->AddChildNode( this );
53 
54  return;
55 }
56 
57 
59 {
60  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 2 )
61  do {
62  std::ostringstream ostr;
63  ostr << " * [INFO] Destroying Shape with " << m_Children.size();
64  ostr << " children, " << m_Refs.size() << " references and ";
65  ostr << m_BackPointers.size() << " backpointers";
66  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
67  } while( 0 );
68  #endif
69 
70  return;
71 }
72 
73 
75 {
76  // this node is dangling unless it has a parent of type:
77  // WRL2_TRANSFORM
78  // WRL2_SWITCH
79 
80  if( NULL == m_Parent
82  && m_Parent->GetNodeType() != WRL2_SWITCH ) )
83  return true;
84 
85  return false;
86 }
87 
88 
90 {
91  if( NULL == aNode )
92  {
93  #ifdef DEBUG_VRML2
94  do {
95  std::ostringstream ostr;
96  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
97  ostr << " * [BUG] NULL passed for aNode";
98  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
99  } while( 0 );
100  #endif
101 
102  return false;
103  }
104 
105  WRL2NODES type = aNode->GetNodeType();
106 
107  if( !checkNodeType( type ) )
108  {
109  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
110  do {
111  std::ostringstream ostr;
112  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
113  ostr << " * [INFO] bad file format; unexpected child node '";
114  ostr << aNode->GetNodeTypeName( type ) << "'";
115  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
116  } while( 0 );
117  #endif
118 
119  return false;
120  }
121 
122  if( WRL2_APPEARANCE == type )
123  {
124  if( NULL != appearance )
125  {
126  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
127  do {
128  std::ostringstream ostr;
129  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
130  ostr << " * [INFO] bad file format; multiple appearance nodes";
131  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
132  } while( 0 );
133  #endif
134 
135  return false;
136  }
137 
138  appearance = aNode;
139  return WRL2NODE::AddRefNode( aNode );
140  }
141 
142  if( NULL != geometry )
143  {
144  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
145  do {
146  std::ostringstream ostr;
147  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
148  ostr << " * [INFO] bad file format; multiple geometry nodes";
149  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
150  } while( 0 );
151  #endif
152 
153  return false;
154  }
155 
156  geometry = aNode;
157  return WRL2NODE::AddRefNode( aNode );
158 }
159 
160 
162 {
163  if( NULL == aNode )
164  {
165  #ifdef DEBUG_VRML2
166  do {
167  std::ostringstream ostr;
168  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
169  ostr << " * [BUG] NULL passed for aNode";
170  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
171  } while( 0 );
172  #endif
173 
174  return false;
175  }
176 
177  WRL2NODES type = aNode->GetNodeType();
178 
179  if( !checkNodeType( type ) )
180  {
181  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
182  do {
183  std::ostringstream ostr;
184  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
185  ostr << " * [INFO] bad file format; unexpected child node '";
186  ostr << aNode->GetNodeTypeName( type ) << "'";
187  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
188  } while( 0 );
189  #endif
190 
191  return false;
192  }
193 
194  if( WRL2_APPEARANCE == type )
195  {
196  if( NULL != appearance )
197  {
198  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
199  do {
200  std::ostringstream ostr;
201  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
202  ostr << " * [INFO] bad file format; multiple appearance nodes";
203  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
204  } while( 0 );
205  #endif
206 
207  return false;
208  }
209 
210  appearance = aNode;
211  return WRL2NODE::AddChildNode( aNode );
212  }
213 
214  if( NULL != geometry )
215  {
216  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
217  do {
218  std::ostringstream ostr;
219  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
220  ostr << " * [INFO] bad file format; multiple geometry nodes";
221  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
222  } while( 0 );
223  #endif
224 
225  return false;
226  }
227 
228  geometry = aNode;
229  return WRL2NODE::AddChildNode( aNode );
230 }
231 
232 
234 {
235  switch( aType )
236  {
237  case WRL2_APPEARANCE:
238  case WRL2_BOX:
239  case WRL2_CONE:
240  case WRL2_CYLINDER:
241  case WRL2_ELEVATIONGRID:
242  case WRL2_EXTRUSION:
243  case WRL2_INDEXEDFACESET:
244  case WRL2_INDEXEDLINESET:
245  case WRL2_POINTSET:
246  case WRL2_SPHERE:
247  case WRL2_TEXT:
248  break;
249 
250  default:
251  return false;
252  break;
253  }
254 
255  return true;
256 }
257 
258 
259 bool WRL2SHAPE::Read( WRLPROC& proc, WRL2BASE* aTopNode )
260 {
261  if( NULL == aTopNode )
262  {
263  #ifdef DEBUG_VRML2
264  do {
265  std::ostringstream ostr;
266  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
267  ostr << " * [BUG] aTopNode is NULL";
268  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
269  } while( 0 );
270  #endif
271 
272  return false;
273  }
274 
275  size_t line, column;
276  proc.GetFilePosData( line, column );
277 
278  char tok = proc.Peek();
279 
280  if( proc.eof() )
281  {
282  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
283  do {
284  std::ostringstream ostr;
285  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
286  ostr << " * [INFO] bad file format; unexpected eof at line ";
287  ostr << line << ", column " << column;
288  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
289  } while( 0 );
290  #endif
291 
292  return false;
293  }
294 
295  if( '{' != tok )
296  {
297  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
298  do {
299  std::ostringstream ostr;
300  ostr << proc.GetError() << "\n";
301  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
302  ostr << " * [INFO] bad file format; expecting '{' but got '" << tok;
303  ostr << "' at line " << line << ", column " << column;
304  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
305  } while( 0 );
306  #endif
307 
308  return false;
309  }
310 
311  proc.Pop();
312  std::string glob;
313 
314  while( true )
315  {
316  if( proc.Peek() == '}' )
317  {
318  proc.Pop();
319  break;
320  }
321 
322  if( !proc.ReadName( glob ) )
323  {
324  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
325  do {
326  std::ostringstream ostr;
327  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
328  ostr << proc.GetError();
329  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
330  } while( 0 );
331  #endif
332 
333  return false;
334  }
335 
336  // expecting one of:
337  // appearance
338  // geometry
339 
340  proc.GetFilePosData( line, column );
341 
342  if( !glob.compare( "appearance" ) )
343  {
344  if( !aTopNode->ReadNode( proc, this, NULL ) )
345  {
346  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
347  do {
348  std::ostringstream ostr;
349  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
350  ostr << " * [INFO] could not read appearance information";
351  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
352  } while( 0 );
353  #endif
354 
355  return false;
356  }
357  }
358  else if( !glob.compare( "geometry" ) )
359  {
360  if( !aTopNode->ReadNode( proc, this, NULL ) )
361  {
362  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
363  do {
364  std::ostringstream ostr;
365  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
366  ostr << " * [INFO] could not read geometry information";
367  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
368  } while( 0 );
369  #endif
370 
371  return false;
372  }
373  }
374  else
375  {
376  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 1 )
377  do {
378  std::ostringstream ostr;
379  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
380  ostr << " * [INFO] bad Shape at line " << line << ", column ";
381  ostr << column << "\n";
382  ostr << " * [INFO] file: '" << proc.GetFileName() << "'";
383  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
384  } while( 0 );
385  #endif
386 
387  return false;
388  }
389  } // while( true ) -- reading contents of Shape{}
390 
391  return true;
392 }
393 
394 
396 {
397  if( NULL == geometry )
398  return NULL;
399 
400  WRL2NODES geomType = geometry->GetNodeType();
401 
402  switch( geomType )
403  {
404  case WRL2_INDEXEDLINESET:
405  case WRL2_POINTSET:
406  case WRL2_TEXT:
407  return NULL;
408  break;
409 
410  default:
411  break;
412  }
413 
414  #if defined( DEBUG_VRML2 ) && ( DEBUG_VRML2 > 2 )
415  do {
416  std::ostringstream ostr;
417  ostr << " * [INFO] Translating Shape with " << m_Children.size();
418  ostr << " children, " << m_Refs.size() << " references and ";
419  ostr << m_BackPointers.size() << " backpointers";
420  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
421  } while( 0 );
422  #endif
423 
424  bool vcolors = false;
425 
427  vcolors = ((WRL2FACESET*)geometry)->HasColors();
428 
429  // if there is no appearance, make use of the per vertex colors if available
430  if( NULL == appearance )
431  {
433  return NULL;
434 
435  if( !vcolors )
436  return NULL;
437  }
438 
439  S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent );
440 
441  if( NULL != aParent && ptype != S3D::SGTYPE_TRANSFORM )
442  {
443  #ifdef DEBUG_VRML2
444  do {
445  std::ostringstream ostr;
446  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
447  ostr << " * [BUG] Shape does not have a Transform parent (parent ID: ";
448  ostr << ptype << ")";
449  wxLogTrace( MASK_VRML, "%s\n", ostr.str().c_str() );
450  } while( 0 );
451  #endif
452 
453  return NULL;
454  }
455 
456  if( m_sgNode )
457  {
458  if( NULL != aParent )
459  {
461  && !S3D::AddSGNodeChild( aParent, m_sgNode ) )
462  {
463  return NULL;
464  }
465  else if( aParent != S3D::GetSGNodeParent( m_sgNode )
466  && !S3D::AddSGNodeRef( aParent, m_sgNode ) )
467  {
468  return NULL;
469  }
470  }
471 
472  return m_sgNode;
473  }
474 
475  IFSG_SHAPE shNode( aParent );
476 
477  SGNODE* pShape = shNode.GetRawPtr();
478  SGNODE* pGeom = geometry->TranslateToSG( pShape );
479 
480  if( NULL == pGeom )
481  {
482  // this can happen if a VRML file contains
483  // empty point or index sets
484  shNode.Destroy();
485  return NULL;
486  }
487 
488  SGNODE* pApp = NULL;
489 
490  if( NULL != appearance )
491  pApp = appearance->TranslateToSG( pShape );
492 
493  if( NULL != appearance && NULL == pApp )
494  {
495  IFSG_FACESET tmp( false );
496  tmp.Attach( pGeom );
497  tmp.Destroy();
498  shNode.Destroy();
499  return NULL;
500  }
501 
502  m_sgNode = shNode.GetRawPtr();
503 
504  return m_sgNode;
505 }
506 
507 
509 {
510  if( NULL == aNode )
511  return;
512 
513  if( aNode == appearance )
514  appearance = NULL;
515  else if( aNode == geometry )
516  geometry = NULL;
517 
518  WRL2NODE::unlinkChildNode( aNode );
519  return;
520 }
521 
522 
523 void WRL2SHAPE::unlinkRefNode( const WRL2NODE* aNode )
524 {
525  if( NULL == aNode )
526  return;
527 
528  if( aNode == appearance )
529  appearance = NULL;
530  else if( aNode == geometry )
531  geometry = NULL;
532 
533  WRL2NODE::unlinkRefNode( aNode );
534  return;
535 }
virtual SGNODE * TranslateToSG(SGNODE *aParent)=0
Function TranslateToSG produces a representation of the data using the intermediate scenegraph struct...
void Pop(void)
Definition: wrlproc.cpp:2007
WRL2NODE represents the base class of all VRML2 nodes.
Definition: vrml2_node.h:58
SGNODE * TranslateToSG(SGNODE *aParent) override
Function TranslateToSG produces a representation of the data using the intermediate scenegraph struct...
std::list< WRL2NODE * > m_Children
Definition: vrml2_node.h:66
bool GetFilePosData(size_t &line, size_t &column)
Definition: wrlproc.cpp:1951
bool Attach(SGNODE *aNode) override
Function Attach associates a given SGNODE* with this wrapper.
#define MASK_VRML
Definition: wrltypes.h:37
std::list< WRL2NODE * > m_Refs
Definition: vrml2_node.h:67
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:636
WRL2NODES m_Type
Definition: vrml2_node.h:62
SGNODE represents the base class of all Scene Graph nodes.
Definition: sg_node.h:76
collects header files for all SG* wrappers and the API
SGNODE * GetRawPtr(void) noexcept
Function GetRawPtr() returns the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:66
SGLIB_API bool AddSGNodeRef(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:645
bool ReadNode(WRLPROC &proc, WRL2NODE *aParent, WRL2NODE **aNode)
Definition: vrml2_base.cpp:371
#define NULL
bool AddChildNode(WRL2NODE *aNode) override
bool Read(WRLPROC &proc, WRL2BASE *aTopNode) override
void unlinkChildNode(const WRL2NODE *aNode) override
Function unlinkChild removes references to an owned child; it is invoked by the child upon destructio...
WRL2NODE * m_Parent
Definition: vrml2_node.h:61
SGLIB_API bool AddSGNodeChild(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:654
SGNODE * m_sgNode
Definition: vrml2_node.h:70
std::list< WRL2NODE * > m_BackPointers
Definition: vrml2_node.h:65
WRL2FACESET.
Definition: vrml2_faceset.h:42
WRL2NODE * geometry
Definition: vrml2_shape.h:44
WRL2NODES GetNodeType(void) const
Function GetNodeType returns the type of this node instance.
Definition: vrml2_node.cpp:212
char Peek(void)
Definition: wrlproc.cpp:1979
std::string GetFileName(void)
Definition: wrlproc.cpp:1967
WRL2BASE represents the top node of a VRML2 model.
Definition: vrml2_base.h:59
WRL2NODE * appearance
Definition: vrml2_shape.h:43
const char * GetNodeTypeName(WRL2NODES aNodeType) const
Definition: vrml2_node.cpp:295
SGTYPES
Definition: sg_types.h:34
void unlinkRefNode(const WRL2NODE *aNode) override
Function unlinkRef removes pointers to a referenced node; it is invoked by the referenced node upon d...
SGLIB_API S3D::SGTYPES GetSGNodeType(SGNODE *aNode)
Definition: ifsg_api.cpp:627
bool isDangling(void) override
Function isDangling returns true if the object does not have a parent which is a logical container fo...
Definition: vrml2_shape.cpp:74
virtual bool AddChildNode(WRL2NODE *aNode)
Definition: vrml2_node.cpp:377
bool ReadName(std::string &aName)
Definition: wrlproc.cpp:280
IFSG_FACESET is the wrapper for the SGFACESET class.
Definition: ifsg_faceset.h:40
virtual void unlinkRefNode(const WRL2NODE *aNode)
Function unlinkRef removes pointers to a referenced node; it is invoked by the referenced node upon d...
Definition: vrml2_node.cpp:484
WRL2NODES
Definition: wrltypes.h:121
virtual ~WRL2SHAPE()
Definition: vrml2_shape.cpp:58
std::string GetError(void)
Definition: wrlproc.cpp:1945
virtual void unlinkChildNode(const WRL2NODE *aNode)
Function unlinkChild removes references to an owned child; it is invoked by the child upon destructio...
Definition: vrml2_node.cpp:464
bool checkNodeType(WRL2NODES aType)
Function checkNodeType returns true if the node type is an appearance or geometry class.
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
Definition: ifsg_node.cpp:54
virtual bool AddRefNode(WRL2NODE *aNode)
Definition: vrml2_node.cpp:416
bool eof(void)
Definition: wrlproc.cpp:1939
bool AddRefNode(WRL2NODE *aNode) override
Definition: vrml2_shape.cpp:89
IFSG_SHAPE is the wrapper for the SGSHAPE class.
Definition: ifsg_shape.h:40