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 <cirilo.bernardo@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 
25 #include <iostream>
26 #include <sstream>
27 #include <wx/log.h>
28 
29 #include "3d_cache/sg/sg_faceset.h"
30 #include "3d_cache/sg/sg_colors.h"
31 #include "3d_cache/sg/sg_coords.h"
32 #include "3d_cache/sg/sg_normals.h"
34 #include "3d_cache/sg/sg_helpers.h"
35 
36 SGFACESET::SGFACESET( SGNODE* aParent ) : SGNODE( aParent )
37 {
39  m_Colors = NULL;
40  m_Coords = NULL;
41  m_CoordIndices = NULL;
42  m_Normals = NULL;
43  m_RColors = NULL;
44  m_RCoords = NULL;
45  m_RNormals = NULL;
46  valid = false;
47  validated = false;
48 
49  if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
50  {
51  m_Parent = NULL;
52 
53 #ifdef DEBUG
54  std::ostringstream ostr;
55  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
56  ostr << " * [BUG] inappropriate parent to SGFACESET (type ";
57  ostr << aParent->GetNodeType() << ")";
58  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
59 #endif
60  }
61  else if( NULL != aParent && S3D::SGTYPE_SHAPE == aParent->GetNodeType() )
62  {
63  m_Parent->AddChildNode( this );
64  }
65 
66  return;
67 }
68 
69 
71 {
72  // drop references
73  if( m_RColors )
74  {
75  m_RColors->delNodeRef( this );
76  m_RColors = NULL;
77  }
78 
79  if( m_RCoords )
80  {
81  m_RCoords->delNodeRef( this );
82  m_RCoords = NULL;
83  }
84 
85  if( m_RNormals )
86  {
87  m_RNormals->delNodeRef( this );
88  m_RNormals = NULL;
89  }
90 
91  // delete owned objects
92  if( m_Colors )
93  {
94  m_Colors->SetParent( NULL, false );
95  delete m_Colors;
96  m_Colors = NULL;
97  }
98 
99  if( m_Coords )
100  {
101  m_Coords->SetParent( NULL, false );
102  delete m_Coords;
103  m_Coords = NULL;
104  }
105 
106  if( m_Normals )
107  {
108  m_Normals->SetParent( NULL, false );
109  delete m_Normals;
110  m_Normals = NULL;
111  }
112 
113  if( m_CoordIndices )
114  {
115  m_CoordIndices->SetParent( NULL, false );
116  delete m_CoordIndices;
117  m_CoordIndices = NULL;
118  }
119 
120  return;
121 }
122 
123 
124 bool SGFACESET::SetParent( SGNODE* aParent, bool notify )
125 {
126  if( NULL != m_Parent )
127  {
128  if( aParent == m_Parent )
129  return true;
130 
131  // handle the change in parents
132  if( notify )
133  m_Parent->unlinkChildNode( this );
134 
135  m_Parent = NULL;
136 
137  if( NULL == aParent )
138  return true;
139  }
140 
141  // only a SGSHAPE may be parent to a SGFACESET
142  if( NULL != aParent && S3D::SGTYPE_SHAPE != aParent->GetNodeType() )
143  return false;
144 
145  m_Parent = aParent;
146 
147  if( m_Parent )
148  m_Parent->AddChildNode( this );
149 
150  return true;
151 }
152 
153 
154 SGNODE* SGFACESET::FindNode(const char *aNodeName, const SGNODE *aCaller)
155 {
156  if( NULL == aNodeName || 0 == aNodeName[0] )
157  return NULL;
158 
159  if( !m_Name.compare( aNodeName ) )
160  return this;
161 
162  SGNODE* np = NULL;
163 
164  if( m_Colors )
165  {
166  np = m_Colors->FindNode( aNodeName, this );
167 
168  if( np )
169  return np;
170  }
171 
172  if( m_Coords )
173  {
174  np = m_Coords->FindNode( aNodeName, this );
175 
176  if( np )
177  return np;
178  }
179 
180  if( m_CoordIndices )
181  {
182  np = m_CoordIndices->FindNode( aNodeName, this );
183 
184  if( np )
185  return np;
186  }
187 
188  if( m_Normals )
189  {
190  np = m_Normals->FindNode( aNodeName, this );
191 
192  if( np )
193  return np;
194  }
195 
196  // query the parent if appropriate
197  if( aCaller == m_Parent || NULL == m_Parent )
198  return NULL;
199 
200  return m_Parent->FindNode( aNodeName, this );
201 }
202 
203 
204 void SGFACESET::unlinkNode( const SGNODE* aNode, bool isChild )
205 {
206  if( NULL == aNode )
207  return;
208 
209  valid = false;
210  validated = false;
211 
212  if( isChild )
213  {
214  if( aNode == m_Colors )
215  {
216  m_Colors = NULL;
217  return;
218  }
219 
220  if( aNode == m_Coords )
221  {
222  m_Coords = NULL;
223  return;
224  }
225 
226  if( aNode == m_Normals )
227  {
228  m_Normals = NULL;
229  return;
230  }
231 
232  if( aNode == m_CoordIndices )
233  {
234  m_CoordIndices = NULL;
235  return;
236  }
237  }
238  else
239  {
240  if( aNode == m_RColors )
241  {
242  delNodeRef( this );
243  m_RColors = NULL;
244  return;
245  }
246 
247  if( aNode == m_RCoords )
248  {
249  delNodeRef( this );
250  m_RCoords = NULL;
251  return;
252  }
253 
254  if( aNode == m_RNormals )
255  {
256  delNodeRef( this );
257  m_RNormals = NULL;
258  return;
259  }
260  }
261 
262  #ifdef DEBUG
263  do {
264  std::ostringstream ostr;
265  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
266  ostr << " * [BUG] unlinkNode() did not find its target";
267  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
268  } while( 0 );
269  #endif
270 
271  return;
272 }
273 
274 
275 void SGFACESET::unlinkChildNode( const SGNODE* aNode )
276 {
277  unlinkNode( aNode, true );
278  return;
279 }
280 
281 
282 void SGFACESET::unlinkRefNode( const SGNODE* aNode )
283 {
284  unlinkNode( aNode, false );
285  return;
286 }
287 
288 
289 
290 bool SGFACESET::addNode( SGNODE* aNode, bool isChild )
291 {
292  if( NULL == aNode )
293  {
294  #ifdef DEBUG
295  std::ostringstream ostr;
296  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
297  ostr << " * [BUG] NULL pointer passed for aNode";
298  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
299  #endif
300 
301  return false;
302  }
303 
304  valid = false;
305  validated = false;
306 
307  if( S3D::SGTYPE_COLORS == aNode->GetNodeType() )
308  {
309  if( m_Colors || m_RColors )
310  {
311  if( aNode != m_Colors && aNode != m_RColors )
312  {
313  #ifdef DEBUG
314  std::ostringstream ostr;
315  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
316  ostr << " * [BUG] assigning multiple Colors nodes";
317  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
318  #endif
319 
320  return false;
321  }
322 
323  return true;
324  }
325 
326  if( isChild )
327  {
328  m_Colors = (SGCOLORS*)aNode;
329  m_Colors->SetParent( this );
330  }
331  else
332  {
333  m_RColors = (SGCOLORS*)aNode;
334  m_RColors->addNodeRef( this );
335  }
336 
337  return true;
338  }
339 
340  if( S3D::SGTYPE_COORDS == aNode->GetNodeType() )
341  {
342  if( m_Coords || m_RCoords )
343  {
344  if( aNode != m_Coords && aNode != m_RCoords )
345  {
346  #ifdef DEBUG
347  std::ostringstream ostr;
348  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
349  ostr << " * [BUG] assigning multiple Coords nodes";
350  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
351  #endif
352 
353  return false;
354  }
355 
356  return true;
357  }
358 
359  if( isChild )
360  {
361  m_Coords = (SGCOORDS*)aNode;
362  m_Coords->SetParent( this );
363  }
364  else
365  {
366  m_RCoords = (SGCOORDS*)aNode;
367  m_RCoords->addNodeRef( this );
368  }
369 
370  return true;
371  }
372 
373  if( S3D::SGTYPE_NORMALS == aNode->GetNodeType() )
374  {
375  if( m_Normals || m_RNormals )
376  {
377  if( aNode != m_Normals && aNode != m_RNormals )
378  {
379  #ifdef DEBUG
380  std::ostringstream ostr;
381  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
382  ostr << " * [BUG] assigning multiple Normals nodes";
383  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
384  #endif
385 
386  return false;
387  }
388 
389  return true;
390  }
391 
392  if( isChild )
393  {
394  m_Normals = (SGNORMALS*)aNode;
395  m_Normals->SetParent( this );
396  }
397  else
398  {
399  m_RNormals = (SGNORMALS*)aNode;
400  m_RNormals->addNodeRef( this );
401  }
402 
403  return true;
404  }
405 
406  if( S3D::SGTYPE_COORDINDEX == aNode->GetNodeType() )
407  {
408  if( m_CoordIndices )
409  {
410  if( aNode != m_CoordIndices )
411  {
412  #ifdef DEBUG
413  std::ostringstream ostr;
414  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
415  ostr << " * [BUG] assigning multiple CoordIndex nodes";
416  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
417  #endif
418 
419  return false;
420  }
421 
422  return true;
423  }
424 
425  m_CoordIndices = (SGCOORDINDEX*)aNode;
426  m_CoordIndices->SetParent( this );
427 
428  return true;
429  }
430 
431  #ifdef DEBUG
432  do {
433  std::ostringstream ostr;
434  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
435  ostr << " * [BUG] object '" << aNode->GetName();
436  ostr << "' (type " << aNode->GetNodeType();
437  ostr << ") is not a valid type for this object (" << aNode->GetNodeType() << ")";
438  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
439  } while( 0 );
440  #endif
441 
442  return false;
443 }
444 
445 
447 {
448  return addNode( aNode, false );
449 }
450 
451 
453 {
454  return addNode( aNode, true );
455 }
456 
457 
459 {
460  m_written = false;
461 
462  // rename this node
463  m_Name.clear();
464  GetName();
465 
466  // rename all Colors and Indices
467  if( m_Colors )
469 
470  // rename all Coordinates and Indices
471  if( m_Coords )
473 
474  if( m_CoordIndices )
476 
477  // rename all Normals and Indices
478  if( m_Normals )
480 
481  return;
482 }
483 
484 
485 bool SGFACESET::WriteVRML( std::ostream& aFile, bool aReuseFlag )
486 {
487  if( ( NULL == m_Coords && NULL == m_RCoords )
488  || ( NULL == m_CoordIndices ) )
489  {
490  return false;
491  }
492 
493  if( aReuseFlag )
494  {
495  if( !m_written )
496  {
497  aFile << " geometry DEF " << GetName() << " IndexedFaceSet {\n";
498  m_written = true;
499  }
500  else
501  {
502  aFile << "USE " << GetName() << "\n";
503  return true;
504  }
505  }
506  else
507  {
508  aFile << " geometry IndexedFaceSet {\n";
509  }
510 
511  if( m_Coords )
512  m_Coords->WriteVRML( aFile, aReuseFlag );
513 
514  if( m_RCoords )
515  m_RCoords->WriteVRML( aFile, aReuseFlag );
516 
517  if( m_CoordIndices )
518  m_CoordIndices->WriteVRML( aFile, aReuseFlag );
519 
520  if( m_Normals || m_RNormals )
521  aFile << " normalPerVertex TRUE\n";
522 
523  if( m_Normals )
524  m_Normals->WriteVRML( aFile, aReuseFlag );
525 
526  if( m_RNormals )
527  m_RNormals->WriteVRML( aFile, aReuseFlag );
528 
529  if( m_Colors )
530  m_Colors->WriteVRML( aFile, aReuseFlag );
531 
532  if( m_RColors )
533  m_RColors->WriteVRML( aFile, aReuseFlag );
534 
535  aFile << "}\n";
536 
537  return true;
538 }
539 
540 
541 bool SGFACESET::WriteCache( std::ostream& aFile, SGNODE* parentNode )
542 {
543  if( NULL == parentNode )
544  {
545  if( NULL == m_Parent )
546  {
547  #ifdef DEBUG
548  std::ostringstream ostr;
549  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
550  ostr << " * [BUG] corrupt data; m_aParent is NULL";
551  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
552  #endif
553 
554  return false;
555  }
556 
557  SGNODE* np = m_Parent;
558 
559  while( NULL != np->GetParent() )
560  np = np->GetParent();
561 
562  if( np->WriteCache( aFile, NULL ) )
563  {
564  m_written = true;
565  return true;
566  }
567 
568  return false;
569  }
570 
571  if( parentNode != m_Parent )
572  {
573  #ifdef DEBUG
574  std::ostringstream ostr;
575  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
576  ostr << " * [BUG] corrupt data; parentNode != m_aParent";
577  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
578  #endif
579 
580  return false;
581  }
582 
583  if( !aFile.good() )
584  {
585  #ifdef DEBUG
586  std::ostringstream ostr;
587  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
588  ostr << " * [INFO] bad stream";
589  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
590  #endif
591 
592  return false;
593  }
594 
595  // check if any references are unwritten and swap parents if so
596  if( NULL != m_RCoords && !m_RCoords->isWritten() )
597  m_RCoords->SwapParent( this );
598 
599  if( NULL != m_RNormals && !m_RNormals->isWritten() )
600  m_RNormals->SwapParent( this );
601 
602  if( NULL != m_RColors && !m_RColors->isWritten() )
603  m_RColors->SwapParent( this );
604 
605  aFile << "[" << GetName() << "]";
606  #define NITEMS 7
607  bool items[NITEMS];
608  int i;
609 
610  for( i = 0; i < NITEMS; ++i )
611  items[i] = 0;
612 
613  i = 0;
614  if( NULL != m_Coords )
615  items[i] = true;
616 
617  ++i;
618  if( NULL != m_RCoords )
619  items[i] = true;
620 
621  ++i;
622  if( NULL != m_CoordIndices )
623  items[i] = true;
624 
625  ++i;
626  if( NULL != m_Normals )
627  items[i] = true;
628 
629  ++i;
630  if( NULL != m_RNormals )
631  items[i] = true;
632 
633  ++i;
634  if( NULL != m_Colors )
635  items[i] = true;
636 
637  ++i;
638  if( NULL != m_RColors )
639  items[i] = true;
640 
641  for( int jj = 0; jj < NITEMS; ++jj )
642  aFile.write( (char*)&items[jj], sizeof(bool) );
643 
644  if( items[0] )
645  m_Coords->WriteCache( aFile, this );
646 
647  if( items[1] )
648  aFile << "[" << m_RCoords->GetName() << "]";
649 
650  if( items[2] )
651  m_CoordIndices->WriteCache( aFile, this );
652 
653  if( items[3] )
654  m_Normals->WriteCache( aFile, this );
655 
656  if( items[4] )
657  aFile << "[" << m_RNormals->GetName() << "]";
658 
659  if( items[5] )
660  m_Colors->WriteCache( aFile, this );
661 
662  if( items[6] )
663  aFile << "[" << m_RColors->GetName() << "]";
664 
665  if( aFile.fail() )
666  return false;
667 
668  m_written = true;
669  return true;
670 }
671 
672 
673 bool SGFACESET::ReadCache( std::istream& aFile, SGNODE* parentNode )
674 {
676  || m_Colors || m_RColors
677  || m_Normals || m_RNormals )
678  {
679  #ifdef DEBUG
680  std::ostringstream ostr;
681  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
682  ostr << " * [BUG] non-empty node";
683  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
684  #endif
685 
686  return false;
687  }
688 
689  #define NITEMS 7
690  bool items[NITEMS];
691 
692  for( int i = 0; i < NITEMS; ++i )
693  aFile.read( (char*)&items[i], sizeof(bool) );
694 
695  if( ( items[0] && items[1] ) || ( items[3] && items[4] )
696  || ( items[5] && items[6] ) )
697  {
698  #ifdef DEBUG
699  std::ostringstream ostr;
700  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
701  ostr << " * [INFO] corrupt data; multiple item definitions at position ";
702  ostr << aFile.tellg();
703  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
704  #endif
705 
706  return false;
707  }
708 
709  std::string name;
710 
711  if( items[0] )
712  {
713  if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
714  {
715  #ifdef DEBUG
716  std::ostringstream ostr;
717  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
718  ostr << " * [INFO] corrupt data; bad child coords tag at position ";
719  ostr << aFile.tellg();
720  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
721  #endif
722 
723  return false;
724  }
725 
726  m_Coords = new SGCOORDS( this );
727  m_Coords->SetName( name.c_str() );
728 
729  if( !m_Coords->ReadCache( aFile, this ) )
730  {
731  #ifdef DEBUG
732  std::ostringstream ostr;
733  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
734  ostr << " * [INFO] corrupt data while reading coords '";
735  ostr << name << "'";
736  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
737  #endif
738 
739  return false;
740  }
741  }
742 
743  if( items[1] )
744  {
745  if( S3D::SGTYPE_COORDS != S3D::ReadTag( aFile, name ) )
746  {
747  #ifdef DEBUG
748  std::ostringstream ostr;
749  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
750  ostr << " * [INFO] corrupt data; bad ref coords tag at position ";
751  ostr << aFile.tellg();
752  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
753  #endif
754 
755  return false;
756  }
757 
758  SGNODE* np = FindNode( name.c_str(), this );
759 
760  if( !np )
761  {
762  #ifdef DEBUG
763  std::ostringstream ostr;
764  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
765  ostr << " * [INFO] corrupt data: cannot find ref coords '";
766  ostr << name << "'";
767  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
768  #endif
769 
770  return false;
771  }
772 
773  if( S3D::SGTYPE_COORDS != np->GetNodeType() )
774  {
775  #ifdef DEBUG
776  std::ostringstream ostr;
777  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
778  ostr << " * [INFO] corrupt data: type is not SGCOORDS '";
779  ostr << name << "'";
780  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
781  #endif
782 
783  return false;
784  }
785 
786  m_RCoords = (SGCOORDS*)np;
787  m_RCoords->addNodeRef( this );
788  }
789 
790  if( items[2] )
791  {
792  if( S3D::SGTYPE_COORDINDEX != S3D::ReadTag( aFile, name ) )
793  {
794  #ifdef DEBUG
795  std::ostringstream ostr;
796  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
797  ostr << " * [INFO] corrupt data; bad coord index tag at position ";
798  ostr << aFile.tellg();
799  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
800  #endif
801 
802  return false;
803  }
804 
805  m_CoordIndices = new SGCOORDINDEX( this );
806  m_CoordIndices->SetName( name.c_str() );
807 
808  if( !m_CoordIndices->ReadCache( aFile, this ) )
809  {
810  #ifdef DEBUG
811  std::ostringstream ostr;
812  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
813  ostr << " * [INFO] corrupt data while reading coord index '";
814  ostr << name << "'";
815  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
816  #endif
817 
818  return false;
819  }
820  }
821 
822  if( items[3] )
823  {
824  if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
825  {
826  #ifdef DEBUG
827  std::ostringstream ostr;
828  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
829  ostr << " * [INFO] corrupt data; bad child normals tag at position ";
830  ostr << aFile.tellg();
831  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
832  #endif
833 
834  return false;
835  }
836 
837  m_Normals = new SGNORMALS( this );
838  m_Normals->SetName( name.c_str() );
839 
840  if( !m_Normals->ReadCache( aFile, this ) )
841  {
842  #ifdef DEBUG
843  std::ostringstream ostr;
844  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
845  ostr << " * [INFO] corrupt data while reading normals '";
846  ostr << name << "'";
847  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
848  #endif
849 
850  return false;
851  }
852  }
853 
854  if( items[4] )
855  {
856  if( S3D::SGTYPE_NORMALS != S3D::ReadTag( aFile, name ) )
857  {
858  #ifdef DEBUG
859  std::ostringstream ostr;
860  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
861  ostr << " * [INFO] corrupt data; bad ref normals tag at position ";
862  ostr << aFile.tellg();
863  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
864  #endif
865 
866  return false;
867  }
868 
869  SGNODE* np = FindNode( name.c_str(), this );
870 
871  if( !np )
872  {
873  #ifdef DEBUG
874  std::ostringstream ostr;
875  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
876  ostr << " * [INFO] corrupt data: cannot find ref normals '";
877  ostr << name << "'";
878  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
879  #endif
880 
881  return false;
882  }
883 
884  if( S3D::SGTYPE_NORMALS != np->GetNodeType() )
885  {
886  #ifdef DEBUG
887  std::ostringstream ostr;
888  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
889  ostr << " * [INFO] corrupt data: type is not SGNORMALS '";
890  ostr << name << "'";
891  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
892  #endif
893 
894  return false;
895  }
896 
897  m_RNormals = (SGNORMALS*)np;
898  m_RNormals->addNodeRef( this );
899  }
900 
901  if( items[5] )
902  {
903  if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
904  {
905  #ifdef DEBUG
906  std::ostringstream ostr;
907  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
908  ostr << " * [INFO] corrupt data; bad child colors tag at position ";
909  ostr << aFile.tellg();
910  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
911  #endif
912 
913  return false;
914  }
915 
916  m_Colors = new SGCOLORS( this );
917  m_Colors->SetName( name.c_str() );
918 
919  if( !m_Colors->ReadCache( aFile, this ) )
920  {
921  #ifdef DEBUG
922  std::ostringstream ostr;
923  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
924  ostr << " * [INFO] corrupt data while reading colors '";
925  ostr << name << "'";
926  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
927  #endif
928 
929  return false;
930  }
931  }
932 
933  if( items[6] )
934  {
935  if( S3D::SGTYPE_COLORS != S3D::ReadTag( aFile, name ) )
936  {
937  #ifdef DEBUG
938  std::ostringstream ostr;
939  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
940  ostr << " * [INFO] corrupt data; bad ref colors tag at position ";
941  ostr << aFile.tellg();
942  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
943  #endif
944 
945  return false;
946  }
947 
948  SGNODE* np = FindNode( name.c_str(), this );
949 
950  if( !np )
951  {
952  #ifdef DEBUG
953  std::ostringstream ostr;
954  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
955  ostr << " * [INFO] corrupt data: cannot find ref colors '";
956  ostr << name << "'";
957  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
958  #endif
959 
960  return false;
961  }
962 
963  if( S3D::SGTYPE_COLORS != np->GetNodeType() )
964  {
965  #ifdef DEBUG
966  std::ostringstream ostr;
967  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
968  ostr << " * [INFO] corrupt data: type is not SGCOLORS '";
969  ostr << name << "'";
970  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
971  #endif
972 
973  return false;
974  }
975 
976  m_RColors = (SGCOLORS*)np;
977  m_RColors->addNodeRef( this );
978  }
979 
980  if( aFile.fail() )
981  return false;
982 
983  return true;
984 }
985 
986 
988 {
989  // verify the integrity of this object's data
990  if( validated )
991  return valid;
992 
993  // ensure we have at least coordinates and their normals
994  if( (NULL == m_Coords && NULL == m_RCoords)
995  || (NULL == m_Normals && NULL == m_RNormals)
996  || (NULL == m_CoordIndices) )
997  {
998 #ifdef DEBUG
999  std::ostringstream ostr;
1000  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1001  ostr << " * [INFO] bad model; no vertices, vertex indices, or normals";
1002  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
1003 #endif
1004  validated = true;
1005  valid = false;
1006  return false;
1007  }
1008 
1009  // check that there are >3 vertices
1010  SGCOORDS* coords = m_Coords;
1011 
1012  if( NULL == coords )
1013  coords = m_RCoords;
1014 
1015  size_t nCoords = 0;
1016  SGPOINT* lCoords = NULL;
1017  coords->GetCoordsList( nCoords, lCoords );
1018 
1019  if( nCoords < 3 )
1020  {
1021 #ifdef DEBUG
1022  std::ostringstream ostr;
1023  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1024  ostr << " * [INFO] bad model; fewer than 3 vertices";
1025  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
1026 #endif
1027  validated = true;
1028  valid = false;
1029  return false;
1030  }
1031 
1032  // check that nVertices is divisible by 3 (facets are triangles)
1033  size_t nCIdx = 0;
1034  int* lCIdx = NULL;
1035  m_CoordIndices->GetIndices( nCIdx, lCIdx );
1036 
1037  if( nCIdx < 3 || ( nCIdx % 3 > 0 ) )
1038  {
1039 #ifdef DEBUG
1040  std::ostringstream ostr;
1041  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1042  ostr << " * [INFO] bad model; no vertex indices or not multiple of 3";
1043  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
1044 #endif
1045  validated = true;
1046  valid = false;
1047  return false;
1048  }
1049 
1050  // check that vertex[n] >= 0 and < nVertices
1051  for( size_t i = 0; i < nCIdx; ++i )
1052  {
1053  if( lCIdx[i] < 0 || lCIdx[i] >= (int)nCoords )
1054  {
1055 #ifdef DEBUG
1056  std::ostringstream ostr;
1057  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1058  ostr << " * [INFO] bad model; vertex index out of bounds";
1059  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
1060 #endif
1061  validated = true;
1062  valid = false;
1063  return false;
1064  }
1065  }
1066 
1067  // check that there are as many normals as vertices
1068  size_t nNorms = 0;
1069  SGVECTOR* lNorms = NULL;
1070  SGNORMALS* pNorms = m_Normals;
1071 
1072  if( NULL == pNorms )
1073  pNorms = m_RNormals;
1074 
1075  pNorms->GetNormalList( nNorms, lNorms );
1076 
1077  if( nNorms != nCoords )
1078  {
1079 #ifdef DEBUG
1080  std::ostringstream ostr;
1081  ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
1082  ostr << " * [INFO] bad model; number of normals (" << nNorms;
1083  ostr << ") does not match number of vertices (" << nCoords << ")";
1084  wxLogTrace( MASK_3D_SG, "%s\n", ostr.str().c_str() );
1085 #endif
1086  validated = true;
1087  valid = false;
1088  return false;
1089  }
1090 
1091  // if there are colors then ensure there are as many colors as vertices
1092  SGCOLORS* pColors = m_Colors;
1093 
1094  if( NULL == pColors )
1095  pColors = m_RColors;
1096 
1097  if( NULL != pColors )
1098  {
1099  // we must have at least as many colors as vertices
1100  size_t nColor = 0;
1101  SGCOLOR* pColor = NULL;
1102  pColors->GetColorList( nColor, pColor );
1103  }
1104 
1105  validated = true;
1106  valid = true;
1107  return true;
1108 }
1109 
1110 
1111 void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
1112 {
1113  if( m_CoordIndices )
1114  m_CoordIndices->GatherCoordIndices( aIndexList );
1115 
1116  return;
1117 }
1118 
1119 
1121 {
1122  SGCOORDS* coords = m_Coords;
1123 
1124  if( m_RCoords )
1125  coords = m_RCoords;
1126 
1127  if( NULL == coords || coords->coords.empty() )
1128  return false;
1129 
1130  if( m_Normals && !m_Normals->norms.empty( ) )
1131  return true;
1132 
1133  if( m_RNormals && !m_RNormals->norms.empty( ) )
1134  return true;
1135 
1136  return coords->CalcNormals( this, aPtr );
1137 }
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Function SetParent sets the parent SGNODE of this object.
Definition: sg_colors.cpp:63
defines a vertex coordinate set for a scenegraph object
void addNodeRef(SGNODE *aNode)
Function addNodeRef adds a pointer to a node which references, but does not own, this node...
Definition: sg_node.cpp:176
void ReNameNodes(void) override
Function ReNameNodes renames a node and all its child nodes in preparation for Write() operations...
Definition: sg_normals.cpp:201
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) override
Function FindNode searches the tree of linked nodes and returns a reference to the first node found w...
Definition: sg_normals.cpp:94
SGCOORDINDEX * m_CoordIndices
Definition: sg_faceset.h:55
void ReNameNodes(void) override
Function ReNameNodes renames a node and all its child nodes in preparation for Write() operations...
Definition: sg_coords.cpp:203
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Function WriteCache write's this node's data to a binary cache file; the data includes all data of ch...
Definition: sg_normals.cpp:267
bool CalcNormals(SGNODE **aPtr)
virtual ~SGFACESET()
Definition: sg_faceset.cpp:70
SGNODE * m_Parent
Definition: sg_node.h:83
Class SGCOORDINDEX is a class which maintains a coordinate index list.
Definition: sg_coordindex.h:44
SGFACESET(SGNODE *aParent)
Definition: sg_faceset.cpp:36
bool validated
Definition: sg_faceset.h:47
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Function SetParent sets the parent SGNODE of this object.
Definition: sg_index.cpp:57
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Function SetParent sets the parent SGNODE of this object.
Definition: sg_normals.cpp:64
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Function WriteVRML writes this node's data to a VRML file; this includes all data of child and refere...
Definition: sg_coords.cpp:213
bool GetColorList(size_t &aListSize, SGCOLOR *&aColorList)
Definition: sg_colors.cpp:157
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Function ReadCache Reads binary format data from a cache file.
Definition: sg_colors.cpp:337
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Function ReadCache Reads binary format data from a cache file.
Definition: sg_coords.cpp:344
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Function WriteVRML writes this node's data to a VRML file; this includes all data of child and refere...
Definition: sg_index.cpp:197
defines a set of vertex normals for a scene graph object
SGCOLORS * m_Colors
Definition: sg_faceset.h:53
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) override
Function FindNode searches the tree of linked nodes and returns a reference to the first node found w...
Definition: sg_coords.cpp:96
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Function WriteCache write's this node's data to a binary cache file; the data includes all data of ch...
Definition: sg_faceset.cpp:541
bool GetCoordsList(size_t &aListSize, SGPOINT *&aCoordsList)
Definition: sg_coords.cpp:160
Class SGNODE represents the base class of all Scene Graph nodes.
Definition: sg_node.h:76
S3D::SGTYPES GetNodeType(void) const
Function GetNodeType returns the type of this node instance.
Definition: sg_node.cpp:108
bool valid
Definition: sg_faceset.h:46
void delNodeRef(const SGNODE *aNode)
Function delNodeRef removes a pointer to a node which references, but does not own, this node.
Definition: sg_node.cpp:192
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Function ReadCache Reads binary format data from a cache file.
Definition: sg_normals.cpp:336
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Function WriteCache write's this node's data to a binary cache file; the data includes all data of ch...
Definition: sg_index.cpp:297
SGCOLORS * m_RColors
Definition: sg_faceset.h:59
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Function ReadCache Reads binary format data from a cache file.
Definition: sg_faceset.cpp:673
void ReNameNodes(void) override
Function ReNameNodes renames a node and all its child nodes in preparation for Write() operations...
Definition: sg_index.cpp:187
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Function WriteVRML writes this node's data to a VRML file; this includes all data of child and refere...
Definition: sg_normals.cpp:211
void unlinkNode(const SGNODE *aNode, bool isChild)
Definition: sg_faceset.cpp:204
void ReNameNodes(void) override
Function ReNameNodes renames a node and all its child nodes in preparation for Write() operations...
Definition: sg_faceset.cpp:458
void ReNameNodes(void) override
Function ReNameNodes renames a node and all its child nodes in preparation for Write() operations...
Definition: sg_colors.cpp:200
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) override
Function FindNode searches the tree of linked nodes and returns a reference to the first node found w...
Definition: sg_faceset.cpp:154
const char * GetName(void)
Definition: sg_node.cpp:150
SGCOORDS * m_RCoords
Definition: sg_faceset.h:60
bool m_written
Definition: sg_node.h:86
S3D::SGTYPES ReadTag(std::istream &aFile, std::string &aName)
Function ReadTag reads the text tag of a binary cache file which is the NodeTag and unique ID number ...
Definition: sg_helpers.cpp:208
SGNODE * GetParent(void) const
Function GetParent returns a pointer to the parent SGNODE of this object or NULL if the object has no...
Definition: sg_node.cpp:114
virtual void unlinkChildNode(const SGNODE *aNode)=0
Function unlinkChild removes references to an owned child; it is invoked by the child upon destructio...
defines an coordinate index set for a scenegraph object
bool GetIndices(size_t &nIndices, int *&aIndexList)
Function GetIndices retrieves the number of indices and a pointer to the list.
Definition: sg_index.cpp:151
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Function WriteVRML writes this node's data to a VRML file; this includes all data of child and refere...
Definition: sg_colors.cpp:210
bool SwapParent(SGNODE *aNewParent)
Function SwapParent swaps the ownership with the given parent.
Definition: sg_node.cpp:120
std::vector< SGVECTOR > norms
Definition: sg_normals.h:38
bool validate(void)
Definition: sg_faceset.cpp:987
bool AddChildNode(SGNODE *aNode) override
Definition: sg_faceset.cpp:452
defines an indexed face set for a scenegraph
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) override
Function FindNode searches the tree of linked nodes and returns a reference to the first node found w...
Definition: sg_index.cpp:87
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Function SetParent sets the parent SGNODE of this object.
Definition: sg_coords.cpp:66
SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller) override
Function FindNode searches the tree of linked nodes and returns a reference to the first node found w...
Definition: sg_colors.cpp:93
void GatherCoordIndices(std::vector< int > &aIndexList)
Function GatherCoordIndices adds all coordinate indices to the given list in preparation for a normal...
virtual SGNODE * FindNode(const char *aNodeName, const SGNODE *aCaller)=0
Function FindNode searches the tree of linked nodes and returns a reference to the first node found w...
void SetName(const char *aName)
Definition: sg_node.cpp:159
std::string m_Name
Definition: sg_node.h:85
bool AddRefNode(SGNODE *aNode) override
Definition: sg_faceset.cpp:446
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Function SetParent sets the parent SGNODE of this object.
Definition: sg_faceset.cpp:124
virtual bool WriteCache(std::ostream &aFile, SGNODE *parentNode)=0
Function WriteCache write's this node's data to a binary cache file; the data includes all data of ch...
bool addNode(SGNODE *aNode, bool isChild)
Definition: sg_faceset.cpp:290
S3D::SGTYPES m_SGtype
Definition: sg_node.h:84
SGCOORDS * m_Coords
Definition: sg_faceset.h:54
void unlinkChildNode(const SGNODE *aNode) override
Function unlinkChild removes references to an owned child; it is invoked by the child upon destructio...
Definition: sg_faceset.cpp:275
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Function WriteCache write's this node's data to a binary cache file; the data includes all data of ch...
Definition: sg_colors.cpp:268
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Function ReadCache Reads binary format data from a cache file.
Definition: sg_index.cpp:366
defines an RGB color set for a scenegraph object
void GatherCoordIndices(std::vector< int > &aIndexList)
Function GatherCoordIndices adds all internal coordinate indices to the given list in preparation for...
std::vector< SGPOINT > coords
Definition: sg_coords.h:40
bool CalcNormals(SGFACESET *callingNode, SGNODE **aPtr=NULL)
Function CalcNormals calculates normals for this coordinate list and sets the normals list in the par...
Definition: sg_coords.cpp:377
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Function WriteVRML writes this node's data to a VRML file; this includes all data of child and refere...
Definition: sg_faceset.cpp:485
virtual bool AddChildNode(SGNODE *aNode)=0
const char * name
void unlinkRefNode(const SGNODE *aNode) override
Function unlinkRef removes pointers to a referenced node; it is invoked by the referenced node upon d...
Definition: sg_faceset.cpp:282
SGNORMALS * m_Normals
Definition: sg_faceset.h:56
defines a number of macro functions to aid in repetitious code which is probably best expressed as a ...
#define NITEMS
SGNORMALS * m_RNormals
Definition: sg_faceset.h:61
bool GetNormalList(size_t &aListSize, SGVECTOR *&aNormalList)
Definition: sg_normals.cpp:158
bool isWritten(void)
Function IsWritten returns true if the object had already been written to a cache file or VRML file; ...
Definition: sg_node.h:130
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Function WriteCache write's this node's data to a binary cache file; the data includes all data of ch...
Definition: sg_coords.cpp:275