KiCad PCB EDA Suite
x3d_transform.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-2022 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/xml/xml.h>
29 #include <wx/log.h>
30 #include "x3d_ops.h"
31 #include "x3d_transform.h"
32 #include "plugins/3dapi/ifsg_all.h"
33 
34 
36 {
38  init();
39 }
40 
41 
43 {
45  init();
46 
47  if( nullptr != aParent )
48  {
49  X3DNODES ptype = aParent->GetNodeType();
50 
51  if( X3D_TRANSFORM == ptype || X3D_SWITCH == ptype )
52  m_Parent = aParent;
53  }
54 
55  if( nullptr != m_Parent )
56  m_Parent->AddChildNode( this );
57 }
58 
59 
61 {
62  wxLogTrace( traceVrmlPlugin,
63  wxT( " * [INFO] Destroying Transform with %zu children, %zu references, "
64  "and %zu back pointers." ),
65  m_Children.size(), m_Refs.size(), m_BackPointers.size() );
66 }
67 
68 
70 {
71  center.x = 0.0;
72  center.y = 0.0;
73  center.z = 0.0;
74 
75  scale.x = 1.0;
76  scale.y = 1.0;
77  scale.z = 1.0;
78 
80 
81  rotation.x = 0.0;
82  rotation.y = 0.0;
83  rotation.z = 1.0;
84 
86 
88  bboxSize = center;
89 }
90 
91 
92 void X3DTRANSFORM::readFields( wxXmlNode* aNode )
93 {
94  // DEF
95  // center
96  // scale
97  // translation
98  // rotation
99  // scaleOrientation
100  // bboxCenter (ignored)
101  // bboxSize (ignored)
102 
103  wxXmlAttribute* prop;
104 
105  // note: center/translation are multiplied by 2.54 to retain
106  // legacy behavior of 1 X3D unit = 0.1 inch; the SG*
107  // classes expect all units in mm.
108 
109  for( prop = aNode->GetAttributes(); prop != nullptr; prop = prop->GetNext() )
110  {
111  const wxString& pname = prop->GetName();
112 
113  if( pname == wxT( "DEF" ) )
114  {
115  m_Name = prop->GetValue();
116  m_Dict->AddName( m_Name, this );
117  }
118  else if( pname == wxT( "center" ) )
119  {
120  X3D::ParseSFVec3( prop->GetValue(), center );
121  center *= 2.54;
122  }
123  else if( pname == wxT( "scale" ) )
124  {
125  X3D::ParseSFVec3( prop->GetValue(), scale );
126  }
127  else if( pname == wxT( "translation" ) )
128  {
129  X3D::ParseSFVec3( prop->GetValue(), translation );
130  translation *= 2.54;
131  }
132  else if( pname == wxT( "rotation" ) )
133  {
134  X3D::ParseSFRotation( prop->GetValue(), rotation );
135  }
136  else if( pname == wxT( "scaleOrientation" ) )
137  {
138  X3D::ParseSFRotation( prop->GetValue(), scaleOrientation );
139  }
140  }
141 }
142 
143 
144 bool X3DTRANSFORM::Read( wxXmlNode* aNode, X3DNODE* aTopNode, X3D_DICT& aDict )
145 {
146  if( nullptr == aTopNode || nullptr == aNode )
147  return false;
148 
149  m_Dict = &aDict;
150  readFields( aNode );
151  bool ok = false;
152 
153  for( wxXmlNode* child = aNode->GetChildren(); child != nullptr; child = child->GetNext() )
154  {
155  wxString name = child->GetName();
156 
157  if( name == wxT( "Transform" ) || name == wxT( "Group" ) )
158  ok |= X3D::ReadTransform( child, this, aDict );
159  else if( name == wxT( "Switch" ) )
160  ok |= X3D::ReadSwitch( child, this, aDict );
161  else if( name == wxT( "Shape" ) )
162  ok |= X3D::ReadShape( child, this, aDict );
163 
164  }
165 
166  if( !ok )
167  return false;
168 
169  if( !SetParent( aTopNode ) )
170  return false;
171 
172  return true;
173 }
174 
175 
176 bool X3DTRANSFORM::SetParent( X3DNODE* aParent, bool doUnlink )
177 {
178  if( aParent == m_Parent )
179  return true;
180 
181  if( nullptr != aParent )
182  {
183  X3DNODES nt = aParent->GetNodeType();
184 
185  if( nt != X3D_SWITCH && nt != X3D_TRANSFORM )
186  return false;
187  }
188 
189  if( nullptr != m_Parent && doUnlink )
190  m_Parent->unlinkChildNode( this );
191 
192  m_Parent = aParent;
193 
194  if( nullptr != m_Parent )
195  m_Parent->AddChildNode( this );
196 
197  return true;
198 }
199 
200 
202 {
203  if( nullptr == aNode )
204  return false;
205 
206  X3DNODES tchild = aNode->GetNodeType();
207 
208  if( X3D_SWITCH != tchild && X3D_TRANSFORM != tchild && X3D_SHAPE != tchild )
209  return false;
210 
211  std::list< X3DNODE* >::iterator sC = m_Children.begin();
212  std::list< X3DNODE* >::iterator eC = m_Children.end();
213 
214  while( sC != eC )
215  {
216  if( *sC == aNode )
217  return false;
218 
219  ++sC;
220  }
221 
222  m_Children.push_back( aNode );
223 
224  if( aNode->GetParent() != this )
225  aNode->SetParent( this );
226 
227  return true;
228 }
229 
230 
232 {
233  if( nullptr == aNode )
234  return false;
235 
236  X3DNODES tchild = aNode->GetNodeType();
237 
238  if( X3D_SWITCH != tchild && X3D_TRANSFORM != tchild && X3D_SHAPE != tchild )
239  return false;
240 
241  std::list< X3DNODE* >::iterator sR = m_Refs.begin();
242  std::list< X3DNODE* >::iterator eR = m_Refs.end();
243 
244  while( sR != eR )
245  {
246  if( *sR == aNode )
247  return true;
248 
249  ++sR;
250  }
251 
252  m_Refs.push_back( aNode );
253  aNode->addNodeRef( this );
254 
255  return true;
256 }
257 
258 
260 {
261  wxLogTrace( traceVrmlPlugin,
262  wxT( " * [INFO] Translating Transform with %zu children, %zu references, "
263  "and %zu back pointers." ),
264  m_Children.size(), m_Refs.size(), m_BackPointers.size() );
265 
266  if( m_Children.empty() && m_Refs.empty() )
267  return nullptr;
268 
269  S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent );
270 
271  if( nullptr != aParent && ptype != S3D::SGTYPE_TRANSFORM )
272  {
273  wxLogTrace( traceVrmlPlugin,
274  wxT( " * [BUG] Transform does not have a Transform parent (parent ID: %d)" ),
275  ptype );
276 
277  return nullptr;
278  }
279 
280  if( m_sgNode )
281  {
282  if( nullptr != aParent )
283  {
284  if( nullptr == S3D::GetSGNodeParent( m_sgNode )
285  && !S3D::AddSGNodeChild( aParent, m_sgNode ) )
286  {
287  return nullptr;
288  }
289  else if( aParent != S3D::GetSGNodeParent( m_sgNode )
290  && !S3D::AddSGNodeRef( aParent, m_sgNode ) )
291  {
292  return nullptr;
293  }
294  }
295 
296  return m_sgNode;
297  }
298 
299  IFSG_TRANSFORM txNode( aParent );
300 
301  std::list< X3DNODE* >::iterator sC = m_Children.begin();
302  std::list< X3DNODE* >::iterator eC = m_Children.end();
303  X3DNODES type;
304 
305  // Include only the following in a Transform node:
306  // Shape
307  // Switch
308  // Transform
309  // Inline
310  bool test = false; // set to true if there are any subnodes for display
311 
312  for( int i = 0; i < 2; ++i )
313  {
314  while( sC != eC )
315  {
316  type = (*sC)->GetNodeType();
317 
318  switch( type )
319  {
320  case X3D_SHAPE:
321  case X3D_SWITCH:
322  case X3D_TRANSFORM:
323 
324  if( nullptr != (*sC)->TranslateToSG( txNode.GetRawPtr() ) )
325  test = true;
326 
327  break;
328 
329  default:
330  break;
331  }
332 
333  ++ sC;
334  }
335 
336  sC = m_Refs.begin();
337  eC = m_Refs.end();
338  }
339 
340  if( false == test )
341  {
342  txNode.Destroy();
343  return nullptr;
344  }
345 
346  txNode.SetScale( SGPOINT( scale.x, scale.y, scale.z ) );
347  txNode.SetCenter( SGPOINT( center.x, center.y, center.z ) );
351  txNode.SetRotation( SGVECTOR( rotation.x, rotation.y, rotation.z ), rotation.w );
352 
353  m_sgNode = txNode.GetRawPtr();
354 
355  return m_sgNode;
356 }
WRLVEC3F translation
Definition: x3d_transform.h:58
virtual bool SetParent(X3DNODE *aParent, bool doUnlink=true)=0
Set the parent X3DNODE of this object.
SGNODE * TranslateToSG(SGNODE *aParent) override
Produce a representation of the data using the intermediate scenegraph structures of the kicad_3dsg l...
std::list< X3DNODE * > m_BackPointers
Definition: x3d_base.h:163
bool AddChildNode(X3DNODE *aNode) override
X3DNODES m_Type
Definition: x3d_base.h:160
X3DNODE * GetParent(void) const
Return a pointer to the parent node of this object or NULL if the object has no parent (ie.
Definition: x3d_base.cpp:190
wxString m_Name
Definition: x3d_base.h:168
SGLIB_API SGNODE * GetSGNodeParent(SGNODE *aNode)
Definition: ifsg_api.cpp:494
bool Read(wxXmlNode *aNode, X3DNODE *aTopNode, X3D_DICT &aDict) override
void addNodeRef(X3DNODE *aNode)
Add a pointer to a node which references, but does not own, this node.
Definition: x3d_base.cpp:142
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
bool ReadTransform(wxXmlNode *aNode, X3DNODE *aParent, X3D_DICT &aDict)
Definition: x3d_ops.cpp:34
SGLIB_API bool AddSGNodeRef(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:503
std::list< X3DNODE * > m_Children
Definition: x3d_base.h:164
bool SetScaleOrientation(const SGVECTOR &aScaleAxis, double aAngle)
The base class of all X3D nodes.
Definition: x3d_base.h:74
WRLVEC3F bboxSize
Definition: x3d_transform.h:62
WRLVEC3F scale
Definition: x3d_transform.h:57
bool AddRefNode(X3DNODE *aNode) override
SGLIB_API bool AddSGNodeChild(SGNODE *aParent, SGNODE *aChild)
Definition: ifsg_api.cpp:512
bool SetRotation(const SGVECTOR &aRotationAxis, double aAngle)
void readFields(wxXmlNode *aNode)
virtual bool AddChildNode(X3DNODE *aNode)=0
X3DNODES GetNodeType(void) const
Return the type of this node instance.
Definition: x3d_base.cpp:184
virtual void unlinkChildNode(const X3DNODE *aNode)
Remove references to an owned child; it is invoked by the child upon destruction to ensure that the p...
Definition: x3d_base.cpp:102
const wxChar *const traceVrmlPlugin
Flag to enable VRML plugin trace output.
Definition: vrml.cpp:63
WRLROTATION scaleOrientation
Definition: x3d_transform.h:60
WRLROTATION rotation
Definition: x3d_transform.h:59
bool AddName(const wxString &aName, X3DNODE *aNode)
Definition: x3d_base.cpp:35
bool ParseSFRotation(const wxString &aSource, WRLROTATION &aResult)
Definition: x3d_ops.cpp:284
SGTYPES
Definition: sg_types.h:34
bool ReadShape(wxXmlNode *aNode, X3DNODE *aParent, X3D_DICT &aDict)
Definition: x3d_ops.cpp:79
virtual ~X3DTRANSFORM()
SGNODE * m_sgNode
Definition: x3d_base.h:169
SGLIB_API S3D::SGTYPES GetSGNodeType(SGNODE *aNode)
Definition: ifsg_api.cpp:485
X3DNODE * m_Parent
Definition: x3d_base.h:159
const char * name
Definition: DXF_plotter.cpp:56
bool SetCenter(const SGPOINT &aCenter) noexcept
IFSG_TRANSFORM is the wrapper for the VRML compatible TRANSFORM block class SCENEGRAPH.
bool ParseSFVec3(const wxString &aSource, WRLVEC3F &aResult)
Definition: x3d_ops.cpp:264
bool SetTranslation(const SGPOINT &aTranslation) noexcept
bool ReadSwitch(wxXmlNode *aNode, X3DNODE *aParent, X3D_DICT &aDict)
Definition: x3d_ops.cpp:72
bool SetScale(const SGPOINT &aScale) noexcept
WRLVEC3F bboxCenter
Definition: x3d_transform.h:61
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
Definition: ifsg_node.cpp:55
bool SetParent(X3DNODE *aParent, bool doUnlink=true) override
Set the parent X3DNODE of this object.
X3DNODES
Definition: x3d_base.h:59
X3D_DICT * m_Dict
Definition: x3d_base.h:161
WRLVEC3F center
Definition: x3d_transform.h:56
std::list< X3DNODE * > m_Refs
Definition: x3d_base.h:165