KiCad PCB EDA Suite
sg_faceset.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) 2015-2017 Cirilo Bernardo <[email protected]>
5  * Copyright (C) 2020 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 "3d_cache/sg/sg_faceset.h"
31 #include "3d_cache/sg/sg_colors.h"
32 #include "3d_cache/sg/sg_coords.h"
33 #include "3d_cache/sg/sg_normals.h"
35 #include "3d_cache/sg/sg_helpers.h"
36 
37 
38 SGFACESET::SGFACESET( SGNODE* aParent ) : SGNODE( aParent )
39 {
41  m_Colors = nullptr;
42  m_Coords = nullptr;
43  m_CoordIndices = nullptr;
44  m_Normals = nullptr;
45  m_RColors = nullptr;
46  m_RCoords = nullptr;
47  m_RNormals = nullptr;
48  valid = false;
49  validated = false;
50 
51  if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
52  {
53  m_Parent = nullptr;
54 
55  wxLogTrace( MASK_3D_SG,
56  wxT( "%s:%s:%d * [BUG] inappropriate parent to SGFACESET (type %s)" ),
57  __FILE__, __FUNCTION__, __LINE__,
58  aParent->GetNodeType() );
59  }
60  else if( nullptr != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
61  {
62  m_Parent->AddChildNode( this );
63  }
64 }
65 
66 
68 {
69  // drop references
70  if( m_RColors )
71  {
72  m_RColors->delNodeRef( this );
73  m_RColors = nullptr;
74  }
75 
76  if( m_RCoords )
77  {
78  m_RCoords->delNodeRef( this );
79  m_RCoords = nullptr;
80  }
81 
82  if( m_RNormals )
83  {
84  m_RNormals->delNodeRef( this );
85  m_RNormals = nullptr;
86  }
87 
88  // delete owned objects
89  if( m_Colors )
90  {
91  m_Colors->SetParent( nullptr, false );
92  delete m_Colors;
93  m_Colors = nullptr;
94  }
95 
96  if( m_Coords )
97  {
98  m_Coords->SetParent( nullptr, false );
99  delete m_Coords;
100  m_Coords = nullptr;
101  }
102 
103  if( m_Normals )
104  {
105  m_Normals->SetParent( nullptr, false );
106  delete m_Normals;
107  m_Normals = nullptr;
108  }
109 
110  if( m_CoordIndices )
111  {
112  m_CoordIndices->SetParent( nullptr, false );
113  delete m_CoordIndices;
114  m_CoordIndices = nullptr;
115  }
116 }
117 
118 
119 bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
120 {
121  if( nullptr != m_Parent )
122  {
123  if( aParent == m_Parent )
124  return true;
125 
126  // handle the change in parents
127  if( notify )
128  m_Parent->unlinkChildNode( this );
129 
130  m_Parent = nullptr;
131 
132  if( nullptr == aParent )
133  return true;
134  }
135 
136  // only a SGSHAPE may be parent to a SGFACESET
137  if( nullptr != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
138  return false;
139 
140  m_Parent = aParent;
141 
142  if( m_Parent )
143  m_Parent->AddChildNode( this );
144 
145  return true;
146 }
147 
148 
149 SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
150 {
151  if( nullptr == aNodeName || 0 == aNodeName[0] )
152  return nullptr;
153 
154  if( !m_Name.compare( aNodeName ) )
155  return this;
156 
157  SGNODE* np = nullptr;
158 
159  if( m_Colors )
160  {
161  np = m_Colors->FindNode( aNodeName, this );
162 
163  if( np )
164  return np;
165  }
166 
167  if( m_Coords )
168  {
169  np = m_Coords->FindNode( aNodeName, this );
170 
171  if( np )
172  return np;
173  }
174 
175  if( m_CoordIndices )
176  {
177  np = m_CoordIndices->FindNode( aNodeName, this );
178 
179  if( np )
180  return np;
181  }
182 
183  if( m_Normals )
184  {
185  np = m_Normals->FindNode( aNodeName, this );
186 
187  if( np )
188  return np;
189  }
190 
191  // query the parent if appropriate
192  if( aCaller == m_Parent || nullptr == m_Parent )
193  return nullptr;
194 
195  return m_Parent->FindNode( aNodeName, this );
196 }
197 
198 
199 void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
200 {
201  if( nullptr == aNode )
202  return;
203 
204  valid = false;
205  validated = false;
206 
207  if( isChild )
208  {
209  if( aNode == m_Colors )
210  {
211  m_Colors = nullptr;
212  return;
213  }
214 
215  if( aNode == m_Coords )
216  {
217  m_Coords = nullptr;
218  return;
219  }
220 
221  if( aNode == m_Normals )
222  {
223  m_Normals = nullptr;
224  return;
225  }
226 
227  if( aNode == m_CoordIndices )
228  {
229  m_CoordIndices = nullptr;
230  return;
231  }
232  }
233  else
234  {
235  if( aNode == m_RColors )
236  {
237  delNodeRef( this );
238  m_RColors = nullptr;
239  return;
240  }
241 
242  if( aNode == m_RCoords )
243  {
244  delNodeRef( this );
245  m_RCoords = nullptr;
246  return;
247  }
248 
249  if( aNode == m_RNormals )
250  {
251  delNodeRef( this );
252  m_RNormals = nullptr;
253  return;
254  }
255  }
256 
257  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] unlinkNode() did not find its target" ),
258  __FILE__, __FUNCTION__, __LINE__ );
259 }
260 
261 
262 void SGFACESET::unlinkChildNode( const SGNODE* aNode )
263 {
264  unlinkNode( aNode, true );
265 }
266 
267 
268 void SGFACESET::unlinkRefNode( const SGNODE* aNode )
269 {
270  unlinkNode( aNode, false );
271 }
272 
273 
274 
275 bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
276 {
277  wxCHECK( aNode, false );
278 
279  valid = false;
280  validated = false;
281 
282  if( S3D::SGTYPE_COLORS == aNode->GetNodeType() )
283  {
284  if( m_Colors || m_RColors )
285  {
286  if( aNode != m_Colors && aNode != m_RColors )
287  {
288  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
289  __FILE__, __FUNCTION__, __LINE__ );
290 
291  return false;
292  }
293 
294  return true;
295  }
296 
297  if( isChild )
298  {
299  m_Colors = (SGCOLORS*)aNode;
300  m_Colors->SetParent( this );
301  }
302  else
303  {
304  m_RColors = (SGCOLORS*)aNode;
305  m_RColors->addNodeRef( this );
306  }
307 
308  return true;
309  }
310 
311  if( S3D::SGTYPE_COORDS == aNode->GetNodeType() )
312  {
313  if( m_Coords || m_RCoords )
314  {
315  if( aNode != m_Coords && aNode != m_RCoords )
316  {
317  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Colors nodes" ),
318  __FILE__, __FUNCTION__, __LINE__ );
319 
320  return false;
321  }
322 
323  return true;
324  }
325 
326  if( isChild )
327  {
328  m_Coords = (SGCOORDS*)aNode;
329  m_Coords->SetParent( this );
330  }
331  else
332  {
333  m_RCoords = (SGCOORDS*)aNode;
334  m_RCoords->addNodeRef( this );
335  }
336 
337  return true;
338  }
339 
340  if( S3D::SGTYPE_NORMALS == aNode->GetNodeType() )
341  {
342  if( m_Normals || m_RNormals )
343  {
344  if( aNode != m_Normals && aNode != m_RNormals )
345  {
346  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] assigning multiple Normals nodes" ),
347  __FILE__, __FUNCTION__, __LINE__ );
348 
349  return false;
350  }
351 
352  return true;
353  }
354 
355  if( isChild )
356  {
357  m_Normals = (SGNORMALS*)aNode;
358  m_Normals->SetParent( this );
359  }
360  else
361  {
362  m_RNormals = (SGNORMALS*)aNode;
363  m_RNormals->addNodeRef( this );
364  }
365 
366  return true;
367  }
368 
369  if( S3D::SGTYPE_COORDINDEX == aNode->GetNodeType() )
370  {
371  if( m_CoordIndices )
372  {
373  if( aNode != m_CoordIndices )
374  {
375  wxLogTrace( MASK_3D_SG,
376  wxT( "%s:%s:%d * [BUG] assigning multiple CoordIndex nodes" ),
377  __FILE__, __FUNCTION__, __LINE__ );
378 
379  return false;
380  }
381 
382  return true;
383  }
384 
385  m_CoordIndices = (SGCOORDINDEX*)aNode;
386  m_CoordIndices->SetParent( this );
387 
388  return true;
389  }
390 
391  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] object type '%s' is not a valid type for "
392  "this object '%d'" ),
393  __FILE__, __FUNCTION__, __LINE__,
394  aNode->GetName(),
395  aNode->GetNodeType() );
396 
397  return false;
398 }
399 
400 
402 {
403  return addNode( aNode, false );
404 }
405 
406 
408 {
409  return addNode( aNode, true );
410 }
411 
412 
414 {
415  m_written = false;
416 
417  // rename this node
418  m_Name.clear();
419  GetName();
420 
421  // rename all Colors and Indices
422  if( m_Colors )
424 
425  // rename all Coordinates and Indices
426  if( m_Coords )
428 
429  if( m_CoordIndices )
431 
432  // rename all Normals and Indices
433  if( m_Normals )
435 }
436 
437 
438 bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
439 {
440  if( ( nullptr == m_Coords && nullptr == m_RCoords ) || ( nullptr == m_CoordIndices ) )
441  {
442  return false;
443  }
444 
445  if( aReuseFlag )
446  {
447  if( !m_written )
448  {
449  aFile << " geometry DEF " << GetName() << " IndexedFaceSet {\n";
450  m_written = true;
451  }
452  else
453  {
454  aFile << "USE " << GetName() << "\n";
455  return true;
456  }
457  }
458  else
459  {
460  aFile << " geometry IndexedFaceSet {\n";
461  }
462 
463  if( m_Coords )
464  m_Coords->WriteVRML( aFile, aReuseFlag );
465 
466  if( m_RCoords )
467  m_RCoords->WriteVRML( aFile, aReuseFlag );
468 
469  if( m_CoordIndices )
470  m_CoordIndices->WriteVRML( aFile, aReuseFlag );
471 
472  if( m_Normals || m_RNormals )
473  aFile << " normalPerVertex TRUE\n";
474 
475  if( m_Normals )
476  m_Normals->WriteVRML( aFile, aReuseFlag );
477 
478  if( m_RNormals )
479  m_RNormals->WriteVRML( aFile, aReuseFlag );
480 
481  if( m_Colors )
482  m_Colors->WriteVRML( aFile, aReuseFlag );
483 
484  if( m_RColors )
485  m_RColors->WriteVRML( aFile, aReuseFlag );
486 
487  aFile << "}\n";
488 
489  return true;
490 }
491 
492 
493 bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
494 {
495  if( nullptr == parentNode )
496  {
497  wxCHECK( m_Parent, false );
498 
499  SGNODE* np = m_Parent;
500 
501  while( nullptr != np->GetParent() )
502  np = np->GetParent();
503 
504  if( np->WriteCache( aFile, nullptr ) )
505  {
506  m_written = true;
507  return true;
508  }
509 
510  return false;
511  }
512 
513  wxCHECK( parentNode == m_Parent, false );
514 
515  if( !aFile.good() )
516  {
517  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad stream" ),
518  __FILE__, __FUNCTION__, __LINE__ );
519 
520  return false;
521  }
522 
523  // check if any references are unwritten and swap parents if so
524  if( nullptr != m_RCoords && !m_RCoords->isWritten() )
525  m_RCoords->SwapParent( this );
526 
527  if( nullptr != m_RNormals && !m_RNormals->isWritten() )
528  m_RNormals->SwapParent( this );
529 
530  if( nullptr != m_RColors && !m_RColors->isWritten() )
531  m_RColors->SwapParent( this );
532 
533  aFile << "[" << GetName() << "]";
534  #define NITEMS 7
535  bool items[NITEMS];
536  int i;
537 
538  for( i = 0; i < NITEMS; ++i )
539  items[i] = 0;
540 
541  i = 0;
542  if( nullptr != m_Coords )
543  items[i] = true;
544 
545  ++i;
546  if( nullptr != m_RCoords )
547  items[i] = true;
548 
549  ++i;
550  if( nullptr != m_CoordIndices )
551  items[i] = true;
552 
553  ++i;
554  if( nullptr != m_Normals )
555  items[i] = true;
556 
557  ++i;
558  if( nullptr != m_RNormals )
559  items[i] = true;
560 
561  ++i;
562  if( nullptr != m_Colors )
563  items[i] = true;
564 
565  ++i;
566  if( nullptr != m_RColors )
567  items[i] = true;
568 
569  for( int jj = 0; jj < NITEMS; ++jj )
570  aFile.write( (char*) &items[jj], sizeof( bool ) );
571 
572  if( items[0] )
573  m_Coords->WriteCache( aFile, this );
574 
575  if( items[1] )
576  aFile << "[" << m_RCoords->GetName() << "]";
577 
578  if( items[2] )
579  m_CoordIndices->WriteCache( aFile, this );
580 
581  if( items[3] )
582  m_Normals->WriteCache( aFile, this );
583 
584  if( items[4] )
585  aFile << "[" << m_RNormals->GetName() << "]";
586 
587  if( items[5] )
588  m_Colors->WriteCache( aFile, this );
589 
590  if( items[6] )
591  aFile << "[" << m_RColors->GetName() << "]";
592 
593  if( aFile.fail() )
594  return false;
595 
596  m_written = true;
597  return true;
598 }
599 
600 
601 bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
602 {
604  || m_RNormals )
605  {
606  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [BUG] non-empty node" ),
607  __FILE__, __FUNCTION__, __LINE__ );
608 
609  return false;
610  }
611 
612  #define NITEMS 7
613  bool items[NITEMS];
614 
615  for( int i = 0; i < NITEMS; ++i )
616  aFile.read( (char*) &items[i], sizeof( bool ) );
617 
618  if( ( items[0] && items[1] ) || ( items[3] && items[4] ) || ( items[5] && items[6] ) )
619  {
620  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; multiple item definitions "
621  "at position %d" ),
622  __FILE__, __FUNCTION__, __LINE__,
623  static_cast<int>( aFile.tellg() ) );
624 
625  return false;
626  }
627 
628  std::string name;
629 
630  if( items[0] )
631  {
632  if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
633  {
634  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child coords tag at "
635  "position %d" ),
636  __FILE__, __FUNCTION__, __LINE__,
637  static_cast<int>( aFile.tellg() ) );
638 
639  return false;
640  }
641 
642  m_Coords = new SGCOORDS( this );
643  m_Coords->SetName( name.c_str() );
644 
645  if( !m_Coords->ReadCache( aFile, this ) )
646  {
647  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; corrupt data while "
648  "reading coords '%s'" ),
649  __FILE__, __FUNCTION__, __LINE__,
650  name );
651 
652  return false;
653  }
654  }
655 
656  if( items[1] )
657  {
658  if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
659  {
660  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref coords tag at "
661  "position %d" ),
662  __FILE__, __FUNCTION__, __LINE__,
663  static_cast<int>( aFile.tellg() ) );
664 
665  return false;
666  }
667 
668  SGNODE* np = FindNode( name.c_str(), this );
669 
670  if( !np )
671  {
672  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; cannot find ref "
673  "coords '%s'" ),
674  __FILE__, __FUNCTION__, __LINE__,
675  name );
676 
677  return false;
678  }
679 
680  if( S3D::SGTYPE_COORDS != np->GetNodeType() )
681  {
682  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; type is not SGCOORDS "
683  "'%s'" ),
684  __FILE__, __FUNCTION__, __LINE__,
685  name );
686 
687  return false;
688  }
689 
690  m_RCoords = (SGCOORDS*)np;
691  m_RCoords->addNodeRef( this );
692  }
693 
694  if( items[2] )
695  {
696  if( S3D::SGTYPE_COORDINDEX != S3D::ReadTag( aFile, name ) )
697  {
698  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad coord index tag at "
699  "position %d" ),
700  __FILE__, __FUNCTION__, __LINE__,
701  static_cast<int>( aFile.tellg() ) );
702 
703  return false;
704  }
705 
706  m_CoordIndices = new SGCOORDINDEX( this );
707  m_CoordIndices->SetName( name.c_str() );
708 
709  if( !m_CoordIndices->ReadCache( aFile, this ) )
710  {
711  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading coord "
712  "index '%s'" ),
713  __FILE__, __FUNCTION__, __LINE__,
714  name );
715 
716  return false;
717  }
718  }
719 
720  if( items[3] )
721  {
722  if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
723  {
724  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child normals tag "
725  "at position %d" ),
726  __FILE__, __FUNCTION__, __LINE__,
727  static_cast<int>( aFile.tellg() ) );
728 
729  return false;
730  }
731 
732  m_Normals = new SGNORMALS( this );
733  m_Normals->SetName( name.c_str() );
734 
735  if( !m_Normals->ReadCache( aFile, this ) )
736  {
737  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading normals "
738  "'%s'" ),
739  __FILE__, __FUNCTION__, __LINE__,
740  name );
741 
742  return false;
743  }
744  }
745 
746  if( items[4] )
747  {
748  if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
749  {
750  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref normals tag at "
751  "position %d" ),
752  __FILE__, __FUNCTION__, __LINE__,
753  static_cast<int>( aFile.tellg() ) );
754 
755  return false;
756  }
757 
758  SGNODE* np = FindNode( name.c_str(), this );
759 
760  if( !np )
761  {
762  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: cannot find ref normals "
763  "'%s'" ),
764  __FILE__, __FUNCTION__, __LINE__,
765  name );
766 
767  return false;
768  }
769 
770  if( S3D::SGTYPE_NORMALS != np->GetNodeType() )
771  {
772  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt: type is not SGNORMALS '%s'" ),
773  __FILE__, __FUNCTION__, __LINE__,
774  name );
775 
776  return false;
777  }
778 
779  m_RNormals = (SGNORMALS*)np;
780  m_RNormals->addNodeRef( this );
781  }
782 
783  if( items[5] )
784  {
785  if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
786  {
787  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad child colors tag "
788  "at position %d" ),
789  __FILE__, __FUNCTION__, __LINE__,
790  static_cast<int>( aFile.tellg() ) );
791 
792  return false;
793  }
794 
795  m_Colors = new SGCOLORS( this );
796  m_Colors->SetName( name.c_str() );
797 
798  if( !m_Colors->ReadCache( aFile, this ) )
799  {
800  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data while reading colors "
801  "'%s'" ),
802  __FILE__, __FUNCTION__, __LINE__,
803  name );
804 
805  return false;
806  }
807  }
808 
809  if( items[6] )
810  {
811  if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
812  {
813  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data; bad ref colors tag at "
814  "position %d" ),
815  __FILE__, __FUNCTION__, __LINE__,
816  static_cast<int>( aFile.tellg() ) );
817 
818  return false;
819  }
820 
821  SGNODE* np = FindNode( name.c_str(), this );
822 
823  if( !np )
824  {
825  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: cannot find ref colors "
826  "'%s'" ),
827  __FILE__, __FUNCTION__, __LINE__,
828  name );
829 
830  return false;
831  }
832 
833  if( S3D::SGTYPE_COLORS != np->GetNodeType() )
834  {
835  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] corrupt data: type is not SGCOLORS "
836  "'%s'" ),
837  __FILE__, __FUNCTION__, __LINE__,
838  name );
839 
840  return false;
841  }
842 
843  m_RColors = (SGCOLORS*)np;
844  m_RColors->addNodeRef( this );
845  }
846 
847  if( aFile.fail() )
848  return false;
849 
850  return true;
851 }
852 
853 
855 {
856  // verify the integrity of this object's data
857  if( validated )
858  return valid;
859 
860  // ensure we have at least coordinates and their normals
861  if( ( nullptr == m_Coords && nullptr == m_RCoords )
862  || ( nullptr == m_Normals && nullptr == m_RNormals )
863  || ( nullptr == m_CoordIndices ) )
864  {
865  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertices, vertex indices, "
866  "or normals" ),
867  __FILE__, __FUNCTION__, __LINE__ );
868 
869  validated = true;
870  valid = false;
871  return false;
872  }
873 
874  // check that there are >3 vertices
875  SGCOORDS* coords = m_Coords;
876 
877  if( nullptr == coords )
878  coords = m_RCoords;
879 
880  size_t nCoords = 0;
881  SGPOINT* lCoords = nullptr;
882  coords->GetCoordsList( nCoords, lCoords );
883 
884  if( nCoords < 3 )
885  {
886  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; fewer than 3 vertices" ),
887  __FILE__, __FUNCTION__, __LINE__ );
888 
889  validated = true;
890  valid = false;
891  return false;
892  }
893 
894  // check that nVertices is divisible by 3 (facets are triangles)
895  size_t nCIdx = 0;
896  int* lCIdx = nullptr;
897  m_CoordIndices->GetIndices( nCIdx, lCIdx );
898 
899  if( nCIdx < 3 || ( nCIdx % 3 > 0 ) )
900  {
901  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; no vertex indices or not "
902  "multiple of 3" ),
903  __FILE__, __FUNCTION__, __LINE__ );
904 
905  validated = true;
906  valid = false;
907  return false;
908  }
909 
910  // check that vertex[n] >= 0 and < nVertices
911  for( size_t i = 0; i < nCIdx; ++i )
912  {
913  if( lCIdx[i] < 0 || lCIdx[i] >= (int)nCoords )
914  {
915  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; vertex index out of "
916  "bounds" ),
917  __FILE__, __FUNCTION__, __LINE__ );
918 
919  validated = true;
920  valid = false;
921  return false;
922  }
923  }
924 
925  // check that there are as many normals as vertices
926  size_t nNorms = 0;
927  SGVECTOR* lNorms = nullptr;
928  SGNORMALS* pNorms = m_Normals;
929 
930  if( nullptr == pNorms )
931  pNorms = m_RNormals;
932 
933  pNorms->GetNormalList( nNorms, lNorms );
934 
935  if( nNorms != nCoords )
936  {
937  wxLogTrace( MASK_3D_SG, wxT( "%s:%s:%d * [INFO] bad model; number of normals (%ul) does "
938  "not match number of vertices (%ul)" ),
939  __FILE__, __FUNCTION__, __LINE__,
940  static_cast<unsigned long>( nNorms ),
941  static_cast<unsigned long>( nCoords ) );
942 
943  validated = true;
944  valid = false;
945  return false;
946  }
947 
948  // if there are colors then ensure there are as many colors as vertices
949  SGCOLORS* pColors = m_Colors;
950 
951  if( nullptr == pColors )
952  pColors = m_RColors;
953 
954  if( nullptr != pColors )
955  {
956  // we must have at least as many colors as vertices
957  size_t nColor = 0;
958  SGCOLOR* pColor = nullptr;
959  pColors->GetColorList( nColor, pColor );
960  }
961 
962  validated = true;
963  valid = true;
964  return true;
965 }
966 
967 
968 void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
969 {
970  if( m_CoordIndices )
971  m_CoordIndices->GatherCoordIndices( aIndexList );
972 }
973 
974 
976 {
977  SGCOORDS* coords = m_Coords;
978 
979  if( m_RCoords )
980  coords = m_RCoords;
981 
982  if( nullptr == coords || coords->coords.empty() )
983  return false;
984 
985  if( m_Normals && !m_Normals->norms.empty( ) )
986  return true;
987 
988  if( m_RNormals && !m_RNormals->norms.empty( ) )
989  return true;
990 
991  return coords->CalcNormals( this, aPtr );
992 }
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_colors.cpp:58
Define an RGB color set for a scenegraph object.
Definition: sg_colors.h:38
void addNodeRef(SGNODE *aNode)
Add a pointer to a node which references this node, but does not own.
Definition: sg_node.cpp:170
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_normals.cpp:168
SGCOORDINDEX * m_CoordIndices
Definition: sg_faceset.h:81
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_coords.cpp:169
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_normals.cpp:234
bool CalcNormals(SGNODE **aPtr)
Definition: sg_faceset.cpp:975
virtual ~SGFACESET()
Definition: sg_faceset.cpp:67
SGNODE * m_Parent
Pointer to parent node; may be NULL for top level transform.
Definition: sg_node.h:227
An object to maintain a coordinate index list.
Definition: sg_coordindex.h:42
SGFACESET(SGNODE *aParent)
Definition: sg_faceset.cpp:38
bool validated
Definition: sg_faceset.h:91
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_index.cpp:52
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_normals.cpp:59
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_coords.cpp:179
bool GetColorList(size_t &aListSize, SGCOLOR *&aColorList)
Definition: sg_colors.cpp:128
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override
Search the tree of linked nodes and return a reference to the first node found with the given name.
Definition: sg_coords.cpp:90
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_colors.cpp:284
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_coords.cpp:286
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_index.cpp:171
SGCOLORS * m_Colors
Definition: sg_faceset.h:79
Define a vertex coordinate set for a scenegraph object.
Definition: sg_coords.h:40
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_faceset.cpp:493
bool GetCoordsList(size_t &aListSize, SGPOINT *&aCoordsList)
Definition: sg_coords.cpp:130
The base class of all Scene Graph nodes.
Definition: sg_node.h:74
bool valid
Definition: sg_faceset.h:90
void delNodeRef(const SGNODE *aNode)
Remove a pointer to a node which references this node, but does not own.
Definition: sg_node.cpp:185
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_normals.cpp:279
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_index.cpp:262
SGCOLORS * m_RColors
Definition: sg_faceset.h:85
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_faceset.cpp:601
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_index.cpp:161
Define a set of vertex normals for a scene graph object.
Definition: sg_normals.h:38
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_normals.cpp:178
void unlinkNode(const SGNODE *aNode, bool isChild)
Definition: sg_faceset.cpp:199
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_faceset.cpp:413
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_colors.cpp:171
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) override
Search the tree of linked nodes and return a reference to the first node found with the given name.
Definition: sg_faceset.cpp:149
bool CalcNormals(SGFACESET *callingNode, SGNODE **aPtr=nullptr)
Calculate normals for this coordinate list and sets the normals list in the parent SGFACESET.
Definition: sg_coords.cpp:309
const char * GetName(void)
Definition: sg_node.cpp:146
SGCOORDS * m_RCoords
Definition: sg_faceset.h:86
bool m_written
Set to true when the object has been written after a ReNameNodes().
Definition: sg_node.h:230
S3D::SGTYPES ReadTag(std::istream &aFile, std::string &aName)
Read the text tag of a binary cache file which is the NodeTag and unique ID number combined.
Definition: sg_helpers.cpp:195
virtual void unlinkChildNode(const SGNODE *aNode)=0
Remove references to an owned child.
bool GetIndices(size_t &nIndices, int *&aIndexList)
Retrieve the number of indices and a pointer to the list.
Definition: sg_index.cpp:126
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_colors.cpp:181
bool SwapParent(SGNODE *aNewParent)
Swap the ownership with the given parent.
Definition: sg_node.cpp:116
std::vector< SGVECTOR > norms
Definition: sg_normals.h:64
bool validate(void)
Definition: sg_faceset.cpp:854
bool AddChildNode(SGNODE *aNode) override
Definition: sg_faceset.cpp:407
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_coords.cpp:60
void GatherCoordIndices(std::vector< int > &aIndexList)
Add all coordinate indices to the given list in preparation for a normals calculation.
virtual SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller)=0
Search the tree of linked nodes and return a reference to the first node found with the given name.
SGNODE * GetParent(void) const noexcept
Returns a pointer to the parent SGNODE of this object or NULL if the object has no parent (ie.
Definition: sg_node.cpp:110
void SetName(const char *aName)
Definition: sg_node.cpp:155
std::string m_Name
name to use for referencing the entity by name.
Definition: sg_node.h:229
bool AddRefNode(SGNODE *aNode) override
Definition: sg_faceset.cpp:401
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_faceset.cpp:119
virtual bool WriteCache(std::ostream &aFile, SGNODE *parentNode)=0
Write this node's data to a binary cache file.
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override
Search the tree of linked nodes and return a reference to the first node found with the given name.
Definition: sg_colors.cpp:88
bool addNode(SGNODE *aNode, bool isChild)
Definition: sg_faceset.cpp:275
S3D::SGTYPES m_SGtype
Type of Scene Graph node.
Definition: sg_node.h:228
SGCOORDS * m_Coords
Definition: sg_faceset.h:80
void unlinkChildNode(const SGNODE *aNode) override
Remove references to an owned child.
Definition: sg_faceset.cpp:262
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_colors.cpp:239
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_index.cpp:307
const char * name
Definition: DXF_plotter.cpp:56
void GatherCoordIndices(std::vector< int > &aIndexList)
Add all internal coordinate indices to the given list in preparation for a normals calculation.
Definition: sg_faceset.cpp:968
std::vector< SGPOINT > coords
Definition: sg_coords.h:72
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_faceset.cpp:438
bool isWritten(void) noexcept
Return true if the object had already been written to a cache file or VRML file.
Definition: sg_node.h:220
virtual bool AddChildNode(SGNODE *aNode)=0
void unlinkRefNode(const SGNODE *aNode) override
Remove pointers to a referenced node.
Definition: sg_faceset.cpp:268
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override
Search the tree of linked nodes and return a reference to the first node found with the given name.
Definition: sg_index.cpp:82
SGNORMALS * m_Normals
Definition: sg_faceset.h:82
Define a number of macros to aid in repetitious code which is probably best expressed as a preprocess...
#define NITEMS
SGNORMALS * m_RNormals
Definition: sg_faceset.h:87
bool GetNormalList(size_t &aListSize, SGVECTOR *&aNormalList)
Definition: sg_normals.cpp:129
S3D::SGTYPES GetNodeType(void) const noexcept
Return the type of this node instance.
Definition: sg_node.cpp:104
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) noexcept override
Search the tree of linked nodes and return a reference to the first node found with the given name.
Definition: sg_normals.cpp:89
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_coords.cpp:241