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 <[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 <iostream>
27 #include <sstream>
28 #include <wx/log.h>
29 
30 #include "vrml2_base.h"
31 #include "vrml2_shape.h"
32 #include "plugins/3dapi/ifsg_all.h"
33 #include "vrml2_faceset.h"
34 
35 
37 {
38  appearance = nullptr;
39  geometry = nullptr;
41 }
42 
43 
45 {
46  appearance = nullptr;
47  geometry = nullptr;
49  m_Parent = aParent;
50 
51  if( nullptr != m_Parent )
52  m_Parent->AddChildNode( this );
53 }
54 
55 
57 {
58  wxLogTrace( traceVrmlPlugin,
59  wxT( " * [INFO] Destroying Shape node with %zu children, %zu"
60  "references, and %zu back pointers." ),
61  m_Children.size(), m_Refs.size(), m_BackPointers.size() );
62 }
63 
64 
66 {
67  // this node is dangling unless it has a parent of type:
68  // WRL2_TRANSFORM
69  // WRL2_SWITCH
70 
71  if( nullptr == m_Parent
74  return true;
75 
76  return false;
77 }
78 
79 
81 {
82  wxCHECK_MSG( aNode, false, wxT( "Invalid node." ) );
83 
84  WRL2NODES type = aNode->GetNodeType();
85 
86  if( !checkNodeType( type ) )
87  {
88  wxLogTrace( traceVrmlPlugin,
89  wxT( "%s:%s:%d\n"
90  " * [INFO] bad file format; unexpected child node '%s'." ),
91  __FILE__, __FUNCTION__, __LINE__, aNode->GetNodeTypeName( type ) );
92 
93  return false;
94  }
95 
96  if( WRL2NODES::WRL2_APPEARANCE == type )
97  {
98  if( nullptr != appearance )
99  {
100  wxLogTrace( traceVrmlPlugin,
101  wxT( "%s:%s:%d\n"
102  " * [INFO] bad file format; multiple appearance nodes." ),
103  __FILE__, __FUNCTION__, __LINE__ );
104 
105  return false;
106  }
107 
108  appearance = aNode;
109  return WRL2NODE::AddRefNode( aNode );
110  }
111 
112  if( nullptr != geometry )
113  {
114  wxLogTrace( traceVrmlPlugin,
115  wxT( "%s:%s:%d\n"
116  " * [INFO] bad file format; multiple geometry nodes." ),
117  __FILE__, __FUNCTION__, __LINE__ );
118 
119  return false;
120  }
121 
122  geometry = aNode;
123  return WRL2NODE::AddRefNode( aNode );
124 }
125 
126 
128 {
129  wxCHECK_MSG( aNode, false, wxT( "Invalid node." ) );
130 
131  WRL2NODES type = aNode->GetNodeType();
132 
133  if( !checkNodeType( type ) )
134  {
135  wxLogTrace( traceVrmlPlugin,
136  wxT( "%s:%s:%d\n"
137  " * [INFO] bad file format; unexpected child node '%s'." ),
138  __FILE__, __FUNCTION__, __LINE__, aNode->GetNodeTypeName( type ) );
139 
140  return false;
141  }
142 
143  if( WRL2NODES::WRL2_APPEARANCE == type )
144  {
145  if( nullptr != appearance )
146  {
147  wxLogTrace( traceVrmlPlugin,
148  wxT( "%s:%s:%d\n"
149  " * [INFO] bad file format; multiple appearance nodes." ),
150  __FILE__, __FUNCTION__, __LINE__ );
151 
152  return false;
153  }
154 
155  appearance = aNode;
156  return WRL2NODE::AddChildNode( aNode );
157  }
158 
159  if( nullptr != geometry )
160  {
161  wxLogTrace( traceVrmlPlugin,
162  wxT( "%s:%s:%d\n"
163  " * [INFO] bad file format; multiple geometry nodes." ),
164  __FILE__, __FUNCTION__, __LINE__ );
165 
166  return false;
167  }
168 
169  geometry = aNode;
170  return WRL2NODE::AddChildNode( aNode );
171 }
172 
173 
175 {
176  switch( aType )
177  {
179  case WRL2NODES::WRL2_BOX:
189  break;
190 
191  default:
192  return false;
193  break;
194  }
195 
196  return true;
197 }
198 
199 
200 bool WRL2SHAPE::Read( WRLPROC& proc, WRL2BASE* aTopNode )
201 {
202  wxCHECK_MSG( aTopNode, false, wxT( "Invalid top node." ) );
203 
204  char tok = proc.Peek();
205 
206  if( proc.eof() )
207  {
208  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
209  " * [INFO] bad file format; unexpected eof %s." ),
210  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition() );
211 
212  return false;
213  }
214 
215  if( '{' != tok )
216  {
217  wxLogTrace( traceVrmlPlugin,
218  wxT( "%s:%s:%d\n"
219  " * [INFO] bad file format; expecting '{' but got '%s' %s." ),
220  __FILE__, __FUNCTION__, __LINE__, tok, proc.GetFilePosition() );
221 
222  return false;
223  }
224 
225  proc.Pop();
226  std::string glob;
227 
228  while( true )
229  {
230  if( proc.Peek() == '}' )
231  {
232  proc.Pop();
233  break;
234  }
235 
236  if( !proc.ReadName( glob ) )
237  {
238  wxLogTrace( traceVrmlPlugin, wxT( "%s:%s:%d\n"
239  "%s" ),
240  __FILE__, __FUNCTION__, __LINE__ , proc.GetError() );
241 
242  return false;
243  }
244 
245  // expecting one of:
246  // appearance
247  // geometry
248  if( !glob.compare( "appearance" ) )
249  {
250  if( !aTopNode->ReadNode( proc, this, nullptr ) )
251  {
252  wxLogTrace( traceVrmlPlugin,
253  wxT( "%s:%s:%d\n"
254  " * [INFO] could not read appearance node information." ),
255  __FILE__, __FUNCTION__, __LINE__ );
256 
257  return false;
258  }
259  }
260  else if( !glob.compare( "geometry" ) )
261  {
262  if( !aTopNode->ReadNode( proc, this, nullptr ) )
263  {
264  wxLogTrace( traceVrmlPlugin,
265  wxT( "%s:%s:%d\n"
266  " * [INFO] could not read geometry node information." ),
267  __FILE__, __FUNCTION__, __LINE__ );
268 
269  return false;
270  }
271  }
272  else
273  {
274  wxLogTrace( traceVrmlPlugin,
275  wxT( "%s:%s:%d\n"
276  " * [INFO] invalid Shape %s.\n"
277  " * [INFO] file: '%s'\n" ),
278  __FILE__, __FUNCTION__, __LINE__, proc.GetFilePosition(),
279  proc.GetFileName() );
280 
281  return false;
282  }
283  } // while( true ) -- reading contents of Shape{}
284 
285  return true;
286 }
287 
288 
290 {
291  if( nullptr == geometry )
292  return nullptr;
293 
294  WRL2NODES geomType = geometry->GetNodeType();
295 
296  switch( geomType )
297  {
301  return nullptr;
302  break;
303 
304  default:
305  break;
306  }
307 
308  wxLogTrace( traceVrmlPlugin,
309  wxT( " * [INFO] Translating Shape with %zu children, %zu references, and"
310  "%zu back pointers." ),
311  m_Children.size(), m_Refs.size(), m_BackPointers.size() );
312 
313  bool vcolors = false;
314 
316  vcolors = ((WRL2FACESET*)geometry)->HasColors();
317 
318  // if there is no appearance, make use of the per vertex colors if available
319  if( nullptr == appearance )
320  {
322  return nullptr;
323 
324  if( !vcolors )
325  return nullptr;
326  }
327 
328  S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent );
329 
330  wxCHECK_MSG( aParent && ( ptype == S3D::SGTYPE_TRANSFORM ), nullptr,
331  wxString::Format( wxT( "Shape does not have a Transform parent (parent "
332  "ID: %d)." ), ptype ) );
333 
334  if( m_sgNode )
335  {
336  if( nullptr != aParent )
337  {
338  if( nullptr == S3D::GetSGNodeParent( m_sgNode )
339  && !S3D::AddSGNodeChild( aParent, m_sgNode ) )
340  {
341  return nullptr;
342  }
343  else if( aParent != S3D::GetSGNodeParent( m_sgNode )
344  && !S3D::AddSGNodeRef( aParent, m_sgNode ) )
345  {
346  return nullptr;
347  }
348  }
349 
350  return m_sgNode;
351  }
352 
353  IFSG_SHAPE shNode( aParent );
354 
355  SGNODE* pShape = shNode.GetRawPtr();
356  SGNODE* pGeom = geometry->TranslateToSG( pShape );
357 
358  if( nullptr == pGeom )
359  {
360  // this can happen if a VRML file contains
361  // empty point or index sets
362  shNode.Destroy();
363  return nullptr;
364  }
365 
366  SGNODE* pApp = nullptr;
367 
368  if( nullptr != appearance )
369  pApp = appearance->TranslateToSG( pShape );
370 
371  if( nullptr != appearance && nullptr == pApp )
372  {
373  IFSG_FACESET tmp( false );
374  tmp.Attach( pGeom );
375  tmp.Destroy();
376  shNode.Destroy();
377  return nullptr;
378  }
379 
380  m_sgNode = shNode.GetRawPtr();
381 
382  return m_sgNode;
383 }
384 
385 
387 {
388  if( nullptr == aNode )
389  return;
390 
391  if( aNode == appearance )
392  appearance = nullptr;
393  else if( aNode == geometry )
394  geometry = nullptr;
395 
396  WRL2NODE::unlinkChildNode( aNode );
397 }
398 
399 
400 void WRL2SHAPE::unlinkRefNode( const WRL2NODE* aNode )
401 {
402  if( nullptr == aNode )
403  return;
404 
405  if( aNode == appearance )
406  appearance = nullptr;
407  else if( aNode == geometry )
408  geometry = nullptr;
409 
410  WRL2NODE::unlinkRefNode( aNode );
411 }
virtual SGNODE * TranslateToSG(SGNODE *aParent)=0
Produce a representation of the data using the intermediate scenegraph structures of the kicad_3dsg l...
void Pop(void)
Definition: wrlproc.cpp:2035
SGNODE * TranslateToSG(SGNODE *aParent) override
Produce a representation of the data using the intermediate scenegraph structures of the kicad_3dsg l...
std::list< WRL2NODE * > m_Children
Definition: vrml2_node.h:174
bool Attach(SGNODE *aNode) override
Function Attach associates a given SGNODE* with this wrapper.
std::list< WRL2NODE * > m_Refs
Definition: vrml2_node.h:175
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:492
WRL2NODES m_Type
Definition: vrml2_node.h:170
The base class of all Scene Graph nodes.
Definition: sg_node.h:74
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:65
SGLIB_API bool AddSGNodeRef(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:501
bool ReadNode(WRLPROC &proc, WRL2NODE *aParent, WRL2NODE **aNode)
Definition: vrml2_base.cpp:276
bool AddChildNode(WRL2NODE *aNode) override
bool Read(WRLPROC &proc, WRL2BASE *aTopNode) override
void unlinkChildNode(const WRL2NODE *aNode) override
Remove references to an owned child.
WRL2NODE * m_Parent
Definition: vrml2_node.h:169
SGLIB_API bool AddSGNodeChild(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:510
std::string GetFilePosition() const
Definition: wrlproc.cpp:1982
SGNODE * m_sgNode
Definition: vrml2_node.h:178
std::list< WRL2NODE * > m_BackPointers
Definition: vrml2_node.h:173
WRL2NODE * geometry
Definition: vrml2_shape.h:62
WRL2NODES GetNodeType(void) const
Definition: vrml2_node.cpp:204
char Peek(void)
Definition: wrlproc.cpp:2007
std::string GetFileName(void)
Definition: wrlproc.cpp:1995
The top node of a VRML2 model.
Definition: vrml2_base.h:59
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
WRL2NODE * appearance
Definition: vrml2_shape.h:61
const char * GetNodeTypeName(WRL2NODES aNodeType) const
Definition: vrml2_node.cpp:273
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
void unlinkRefNode(const WRL2NODE *aNode) override
Remove pointers to a referenced node.
SGLIB_API S3D::SGTYPES GetSGNodeType(SGNODE *aNode)
Definition: ifsg_api.cpp:483
bool isDangling(void) override
Determine whether an object should be moved to a different parent during the VRML to SG* translation.
Definition: vrml2_shape.cpp:65
virtual bool AddChildNode(WRL2NODE *aNode)
Definition: vrml2_node.cpp:356
bool ReadName(std::string &aName)
Definition: wrlproc.cpp:289
IFSG_FACESET is the wrapper for the SGFACESET class.
Definition: ifsg_faceset.h:40
virtual void unlinkRefNode(const WRL2NODE *aNode)
Remove pointers to a referenced node.
Definition: vrml2_node.cpp:425
WRL2NODES
Definition: wrltypes.h:124
virtual ~WRL2SHAPE()
Definition: vrml2_shape.cpp:56
std::string GetError(void)
Definition: wrlproc.cpp:1960
virtual void unlinkChildNode(const WRL2NODE *aNode)
Remove references to an owned child.
Definition: vrml2_node.cpp:407
bool checkNodeType(WRL2NODES aType)
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
Definition: ifsg_node.cpp:55
virtual bool AddRefNode(WRL2NODE *aNode)
Definition: vrml2_node.cpp:383
bool eof(void)
Definition: wrlproc.cpp:1954
bool AddRefNode(WRL2NODE *aNode) override
Definition: vrml2_shape.cpp:80
IFSG_SHAPE is the wrapper for the SGSHAPE class.
Definition: ifsg_shape.h:40