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 <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 
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 
42 {
44  init();
45 
46  if( nullptr != aParent )
47  {
48  X3DNODES ptype = aParent->GetNodeType();
49 
50  if( X3D_TRANSFORM == ptype || X3D_SWITCH == ptype )
51  m_Parent = aParent;
52  }
53 
54  if( nullptr != m_Parent )
55  m_Parent->AddChildNode( this );
56 }
57 
58 
60 {
61  wxLogTrace( traceVrmlPlugin,
62  wxT( " * [INFO] Destroying Transform with %zu children, %zu references, "
63  "and %zu back pointers." ),
64  m_Children.size(), m_Refs.size(), m_BackPointers.size() );
65 }
66 
67 
69 {
70  center.x = 0.0;
71  center.y = 0.0;
72  center.z = 0.0;
73 
74  scale.x = 1.0;
75  scale.y = 1.0;
76  scale.z = 1.0;
77 
79 
80  rotation.x = 0.0;
81  rotation.y = 0.0;
82  rotation.z = 1.0;
83 
85 
87  bboxSize = center;
88 }
89 
90 
91 void X3DTRANSFORM::readFields( wxXmlNode* aNode )
92 {
93  // DEF
94  // center
95  // scale
96  // translation
97  // rotation
98  // scaleOrientation
99  // bboxCenter (ignored)
100  // bboxSize (ignored)
101 
102  wxXmlAttribute* prop;
103 
104  // note: center/translation are multiplied by 2.54 to retain
105  // legacy behavior of 1 X3D unit = 0.1 inch; the SG*
106  // classes expect all units in mm.
107 
108  for( prop = aNode->GetAttributes(); prop != nullptr; prop = prop->GetNext() )
109  {
110  const wxString& pname = prop->GetName();
111 
112  if( pname == "DEF" )
113  {
114  m_Name = prop->GetValue();
115  m_Dict->AddName( m_Name, this );
116  }
117  else if( pname == "center" )
118  {
119  X3D::ParseSFVec3( prop->GetValue(), center );
120  center *= 2.54;
121  }
122  else if( pname == "scale" )
123  {
124  X3D::ParseSFVec3( prop->GetValue(), scale );
125  }
126  else if( pname == "translation" )
127  {
128  X3D::ParseSFVec3( prop->GetValue(), translation );
129  translation *= 2.54;
130  }
131  else if( pname == "rotation" )
132  {
133  X3D::ParseSFRotation( prop->GetValue(), rotation );
134  }
135  else if( pname == "scaleOrientation" )
136  {
137  X3D::ParseSFRotation( prop->GetValue(), scaleOrientation );
138  }
139  }
140 }
141 
142 
143 bool X3DTRANSFORM::Read( wxXmlNode* aNode, X3DNODE* aTopNode, X3D_DICT& aDict )
144 {
145  if( nullptr == aTopNode || nullptr == aNode )
146  return false;
147 
148  m_Dict = &aDict;
149  readFields( aNode );
150  bool ok = false;
151 
152  for( wxXmlNode* child = aNode->GetChildren(); child != nullptr; child = child->GetNext() )
153  {
154  wxString name = child->GetName();
155 
156  if( name == "Transform" || name == "Group" )
157  ok |= X3D::ReadTransform( child, this, aDict );
158  else if( name == "Switch" )
159  ok |= X3D::ReadSwitch( child, this, aDict );
160  else if( name == "Shape" )
161  ok |= X3D::ReadShape( child, this, aDict );
162 
163  }
164 
165  if( !ok )
166  return false;
167 
168  if( !SetParent( aTopNode ) )
169  return false;
170 
171  return true;
172 }
173 
174 
175 bool X3DTRANSFORM::SetParent( X3DNODE* aParent, bool doUnlink )
176 {
177  if( aParent == m_Parent )
178  return true;
179 
180  if( nullptr != aParent )
181  {
182  X3DNODES nt = aParent->GetNodeType();
183 
184  if( nt != X3D_SWITCH && nt != X3D_TRANSFORM )
185  return false;
186  }
187 
188  if( nullptr != m_Parent && doUnlink )
189  m_Parent->unlinkChildNode( this );
190 
191  m_Parent = aParent;
192 
193  if( nullptr != m_Parent )
194  m_Parent->AddChildNode( this );
195 
196  return true;
197 }
198 
199 
201 {
202  if( nullptr == aNode )
203  return false;
204 
205  X3DNODES tchild = aNode->GetNodeType();
206 
207  if( X3D_SWITCH != tchild && X3D_TRANSFORM != tchild && X3D_SHAPE != tchild )
208  return false;
209 
210  std::list< X3DNODE* >::iterator sC = m_Children.begin();
211  std::list< X3DNODE* >::iterator eC = m_Children.end();
212 
213  while( sC != eC )
214  {
215  if( *sC == aNode )
216  return false;
217 
218  ++sC;
219  }
220 
221  m_Children.push_back( aNode );
222 
223  if( aNode->GetParent() != this )
224  aNode->SetParent( this );
225 
226  return true;
227 }
228 
229 
231 {
232  if( nullptr == aNode )
233  return false;
234 
235  X3DNODES tchild = aNode->GetNodeType();
236 
237  if( X3D_SWITCH != tchild && X3D_TRANSFORM != tchild && X3D_SHAPE != tchild )
238  return false;
239 
240  std::list< X3DNODE* >::iterator sR = m_Refs.begin();
241  std::list< X3DNODE* >::iterator eR = m_Refs.end();
242 
243  while( sR != eR )
244  {
245  if( *sR == aNode )
246  return true;
247 
248  ++sR;
249  }
250 
251  m_Refs.push_back( aNode );
252  aNode->addNodeRef( this );
253 
254  return true;
255 }
256 
257 
259 {
260  wxLogTrace( traceVrmlPlugin,
261  wxT( " * [INFO] Translating Transform with %zu children, %zu references, "
262  "and %zu back pointers." ),
263  m_Children.size(), m_Refs.size(), m_BackPointers.size() );
264 
265  if( m_Children.empty() && m_Refs.empty() )
266  return nullptr;
267 
268  S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent );
269 
270  wxCHECK_MSG( aParent && ( ptype == S3D::SGTYPE_TRANSFORM ), nullptr,
271  wxString::Format( wxT( "Transform does not have a Transform parent "
272  "(parent ID: %d)" ), ptype ) );
273 
274  if( m_sgNode )
275  {
276  if( nullptr != aParent )
277  {
278  if( nullptr == S3D::GetSGNodeParent( m_sgNode )
279  && !S3D::AddSGNodeChild( aParent, m_sgNode ) )
280  {
281  return nullptr;
282  }
283  else if( aParent != S3D::GetSGNodeParent( m_sgNode )
284  && !S3D::AddSGNodeRef( aParent, m_sgNode ) )
285  {
286  return nullptr;
287  }
288  }
289 
290  return m_sgNode;
291  }
292 
293  IFSG_TRANSFORM txNode( aParent );
294 
295  std::list< X3DNODE* >::iterator sC = m_Children.begin();
296  std::list< X3DNODE* >::iterator eC = m_Children.end();
297  X3DNODES type;
298 
299  // Include only the following in a Transform node:
300  // Shape
301  // Switch
302  // Transform
303  // Inline
304  bool test = false; // set to true if there are any subnodes for display
305 
306  for( int i = 0; i < 2; ++i )
307  {
308  while( sC != eC )
309  {
310  type = (*sC)->GetNodeType();
311 
312  switch( type )
313  {
314  case X3D_SHAPE:
315  case X3D_SWITCH:
316  case X3D_TRANSFORM:
317 
318  if( nullptr != (*sC)->TranslateToSG( txNode.GetRawPtr() ) )
319  test = true;
320 
321  break;
322 
323  default:
324  break;
325  }
326 
327  ++ sC;
328  }
329 
330  sC = m_Refs.begin();
331  eC = m_Refs.end();
332  }
333 
334  if( false == test )
335  {
336  txNode.Destroy();
337  return nullptr;
338  }
339 
340  txNode.SetScale( SGPOINT( scale.x, scale.y, scale.z ) );
341  txNode.SetCenter( SGPOINT( center.x, center.y, center.z ) );
345  txNode.SetRotation( SGVECTOR( rotation.x, rotation.y, rotation.z ), rotation.w );
346 
347  m_sgNode = txNode.GetRawPtr();
348 
349  return m_sgNode;
350 }
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:492
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:501
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:510
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
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
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:483
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