You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

356 lines
8.6 KiB

  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-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. #include <iostream>
  25. #include <sstream>
  26. #include <wx/xml/xml.h>
  27. #include <wx/log.h>
  28. #include "x3d_ops.h"
  29. #include "x3d_transform.h"
  30. #include "plugins/3dapi/ifsg_all.h"
  31. X3DTRANSFORM::X3DTRANSFORM() : X3DNODE()
  32. {
  33. m_Type = X3D_TRANSFORM;
  34. init();
  35. }
  36. X3DTRANSFORM::X3DTRANSFORM( X3DNODE* aParent ) : X3DNODE()
  37. {
  38. m_Type = X3D_TRANSFORM;
  39. init();
  40. if( nullptr != aParent )
  41. {
  42. X3DNODES ptype = aParent->GetNodeType();
  43. if( X3D_TRANSFORM == ptype || X3D_SWITCH == ptype )
  44. m_Parent = aParent;
  45. }
  46. if( nullptr != m_Parent )
  47. m_Parent->AddChildNode( this );
  48. }
  49. X3DTRANSFORM::~X3DTRANSFORM()
  50. {
  51. wxLogTrace( traceVrmlPlugin,
  52. wxT( " * [INFO] Destroying Transform with %zu children, %zu references, "
  53. "and %zu back pointers." ),
  54. m_Children.size(), m_Refs.size(), m_BackPointers.size() );
  55. }
  56. void X3DTRANSFORM::init()
  57. {
  58. center.x = 0.0;
  59. center.y = 0.0;
  60. center.z = 0.0;
  61. scale.x = 1.0;
  62. scale.y = 1.0;
  63. scale.z = 1.0;
  64. translation = center;
  65. rotation.x = 0.0;
  66. rotation.y = 0.0;
  67. rotation.z = 1.0;
  68. scaleOrientation = rotation;
  69. bboxCenter = center;
  70. bboxSize = center;
  71. }
  72. void X3DTRANSFORM::readFields( wxXmlNode* aNode )
  73. {
  74. // DEF
  75. // center
  76. // scale
  77. // translation
  78. // rotation
  79. // scaleOrientation
  80. // bboxCenter (ignored)
  81. // bboxSize (ignored)
  82. wxXmlAttribute* prop;
  83. // note: center/translation are multiplied by 2.54 to retain
  84. // legacy behavior of 1 X3D unit = 0.1 inch; the SG*
  85. // classes expect all units in mm.
  86. for( prop = aNode->GetAttributes(); prop != nullptr; prop = prop->GetNext() )
  87. {
  88. const wxString& pname = prop->GetName();
  89. if( pname == "DEF" )
  90. {
  91. m_Name = prop->GetValue();
  92. m_Dict->AddName( m_Name, this );
  93. }
  94. else if( pname == "center" )
  95. {
  96. X3D::ParseSFVec3( prop->GetValue(), center );
  97. center *= 2.54;
  98. }
  99. else if( pname == "scale" )
  100. {
  101. X3D::ParseSFVec3( prop->GetValue(), scale );
  102. }
  103. else if( pname == "translation" )
  104. {
  105. X3D::ParseSFVec3( prop->GetValue(), translation );
  106. translation *= 2.54;
  107. }
  108. else if( pname == "rotation" )
  109. {
  110. X3D::ParseSFRotation( prop->GetValue(), rotation );
  111. }
  112. else if( pname == "scaleOrientation" )
  113. {
  114. X3D::ParseSFRotation( prop->GetValue(), scaleOrientation );
  115. }
  116. }
  117. }
  118. bool X3DTRANSFORM::Read( wxXmlNode* aNode, X3DNODE* aTopNode, X3D_DICT& aDict )
  119. {
  120. if( nullptr == aTopNode || nullptr == aNode )
  121. return false;
  122. m_Dict = &aDict;
  123. readFields( aNode );
  124. bool ok = false;
  125. for( wxXmlNode* child = aNode->GetChildren(); child != nullptr; child = child->GetNext() )
  126. {
  127. wxString name = child->GetName();
  128. if( name == "Transform" || name == "Group" )
  129. ok |= X3D::ReadTransform( child, this, aDict );
  130. else if( name == "Switch" )
  131. ok |= X3D::ReadSwitch( child, this, aDict );
  132. else if( name == "Shape" )
  133. ok |= X3D::ReadShape( child, this, aDict );
  134. }
  135. if( !ok )
  136. return false;
  137. if( !SetParent( aTopNode ) )
  138. return false;
  139. return true;
  140. }
  141. bool X3DTRANSFORM::SetParent( X3DNODE* aParent, bool doUnlink )
  142. {
  143. if( aParent == m_Parent )
  144. return true;
  145. if( nullptr != aParent )
  146. {
  147. X3DNODES nt = aParent->GetNodeType();
  148. if( nt != X3D_SWITCH && nt != X3D_TRANSFORM )
  149. return false;
  150. }
  151. if( nullptr != m_Parent && doUnlink )
  152. m_Parent->unlinkChildNode( this );
  153. m_Parent = aParent;
  154. if( nullptr != m_Parent )
  155. m_Parent->AddChildNode( this );
  156. return true;
  157. }
  158. bool X3DTRANSFORM::AddChildNode( X3DNODE* aNode )
  159. {
  160. if( nullptr == aNode )
  161. return false;
  162. X3DNODES tchild = aNode->GetNodeType();
  163. if( X3D_SWITCH != tchild && X3D_TRANSFORM != tchild && X3D_SHAPE != tchild )
  164. return false;
  165. std::list< X3DNODE* >::iterator sC = m_Children.begin();
  166. std::list< X3DNODE* >::iterator eC = m_Children.end();
  167. while( sC != eC )
  168. {
  169. if( *sC == aNode )
  170. return false;
  171. ++sC;
  172. }
  173. m_Children.push_back( aNode );
  174. if( aNode->GetParent() != this )
  175. aNode->SetParent( this );
  176. return true;
  177. }
  178. bool X3DTRANSFORM::AddRefNode( X3DNODE* aNode )
  179. {
  180. if( nullptr == aNode )
  181. return false;
  182. X3DNODES tchild = aNode->GetNodeType();
  183. if( X3D_SWITCH != tchild && X3D_TRANSFORM != tchild && X3D_SHAPE != tchild )
  184. return false;
  185. std::list< X3DNODE* >::iterator sR = m_Refs.begin();
  186. std::list< X3DNODE* >::iterator eR = m_Refs.end();
  187. while( sR != eR )
  188. {
  189. if( *sR == aNode )
  190. return true;
  191. ++sR;
  192. }
  193. m_Refs.push_back( aNode );
  194. aNode->addNodeRef( this );
  195. return true;
  196. }
  197. SGNODE* X3DTRANSFORM::TranslateToSG( SGNODE* aParent )
  198. {
  199. wxLogTrace( traceVrmlPlugin,
  200. wxT( " * [INFO] Translating Transform with %zu children, %zu references, "
  201. "and %zu back pointers." ),
  202. m_Children.size(), m_Refs.size(), m_BackPointers.size() );
  203. if( m_Children.empty() && m_Refs.empty() )
  204. return nullptr;
  205. S3D::SGTYPES ptype = S3D::GetSGNodeType( aParent );
  206. if( nullptr != aParent && ptype != S3D::SGTYPE_TRANSFORM )
  207. {
  208. wxLogTrace( traceVrmlPlugin,
  209. wxT( " * [BUG] Transform does not have a Transform parent (parent ID: %d)" ),
  210. ptype );
  211. return nullptr;
  212. }
  213. if( m_sgNode )
  214. {
  215. if( nullptr != aParent )
  216. {
  217. if( nullptr == S3D::GetSGNodeParent( m_sgNode )
  218. && !S3D::AddSGNodeChild( aParent, m_sgNode ) )
  219. {
  220. return nullptr;
  221. }
  222. else if( aParent != S3D::GetSGNodeParent( m_sgNode )
  223. && !S3D::AddSGNodeRef( aParent, m_sgNode ) )
  224. {
  225. return nullptr;
  226. }
  227. }
  228. return m_sgNode;
  229. }
  230. IFSG_TRANSFORM txNode( aParent );
  231. std::list< X3DNODE* >::iterator sC = m_Children.begin();
  232. std::list< X3DNODE* >::iterator eC = m_Children.end();
  233. X3DNODES type;
  234. // Include only the following in a Transform node:
  235. // Shape
  236. // Switch
  237. // Transform
  238. // Inline
  239. bool test = false; // set to true if there are any subnodes for display
  240. for( int i = 0; i < 2; ++i )
  241. {
  242. while( sC != eC )
  243. {
  244. type = (*sC)->GetNodeType();
  245. switch( type )
  246. {
  247. case X3D_SHAPE:
  248. case X3D_SWITCH:
  249. case X3D_TRANSFORM:
  250. if( nullptr != (*sC)->TranslateToSG( txNode.GetRawPtr() ) )
  251. test = true;
  252. break;
  253. default:
  254. break;
  255. }
  256. ++ sC;
  257. }
  258. sC = m_Refs.begin();
  259. eC = m_Refs.end();
  260. }
  261. if( false == test )
  262. {
  263. txNode.Destroy();
  264. return nullptr;
  265. }
  266. txNode.SetScale( SGPOINT( scale.x, scale.y, scale.z ) );
  267. txNode.SetCenter( SGPOINT( center.x, center.y, center.z ) );
  268. txNode.SetTranslation( SGPOINT( translation.x, translation.y, translation.z ) );
  269. txNode.SetScaleOrientation( SGVECTOR( scaleOrientation.x, scaleOrientation.y,
  270. scaleOrientation.z ), scaleOrientation.w );
  271. txNode.SetRotation( SGVECTOR( rotation.x, rotation.y, rotation.z ), rotation.w );
  272. m_sgNode = txNode.GetRawPtr();
  273. return m_sgNode;
  274. }