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
36
37
38SGFACESET::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
119bool 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
149SGNODE* 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
199void 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
263{
264 unlinkNode( aNode, true );
265}
266
267
269{
270 unlinkNode( aNode, false );
271}
272
273
274
275bool 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
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
438bool 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
493bool 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
601bool 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
968void 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}
const char * name
Definition: DXF_plotter.cpp:56
Define an RGB color set for a scenegraph object.
Definition: sg_colors.h:39
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_colors.cpp:284
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_colors.cpp:58
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_colors.cpp:181
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 GetColorList(size_t &aListSize, SGCOLOR *&aColorList)
Definition: sg_colors.cpp:128
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_colors.cpp:171
An object to maintain a coordinate index list.
Definition: sg_coordindex.h:43
void GatherCoordIndices(std::vector< int > &aIndexList)
Add all coordinate indices to the given list in preparation for a normals calculation.
Define a vertex coordinate set for a scenegraph object.
Definition: sg_coords.h:41
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_coords.cpp:241
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_coords.cpp:179
std::vector< SGPOINT > coords
Definition: sg_coords.h:72
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_coords.cpp:286
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
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_coords.cpp:60
bool GetCoordsList(size_t &aListSize, SGPOINT *&aCoordsList)
Definition: sg_coords.cpp:130
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_coords.cpp:169
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
bool validated
Definition: sg_faceset.h:91
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
void unlinkRefNode(const SGNODE *aNode) override
Remove pointers to a referenced node.
Definition: sg_faceset.cpp:268
SGCOORDS * m_RCoords
Definition: sg_faceset.h:86
SGCOORDINDEX * m_CoordIndices
Definition: sg_faceset.h:81
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 addNode(SGNODE *aNode, bool isChild)
Definition: sg_faceset.cpp:275
SGCOORDS * m_Coords
Definition: sg_faceset.h:80
bool CalcNormals(SGNODE **aPtr)
Definition: sg_faceset.cpp:975
SGFACESET(SGNODE *aParent)
Definition: sg_faceset.cpp:38
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_faceset.cpp:413
SGNORMALS * m_Normals
Definition: sg_faceset.h:82
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_faceset.cpp:119
void unlinkChildNode(const SGNODE *aNode) override
Remove references to an owned child.
Definition: sg_faceset.cpp:262
void unlinkNode(const SGNODE *aNode, bool isChild)
Definition: sg_faceset.cpp:199
SGCOLORS * m_RColors
Definition: sg_faceset.h:85
SGNORMALS * m_RNormals
Definition: sg_faceset.h:87
bool AddRefNode(SGNODE *aNode) override
Definition: sg_faceset.cpp:401
virtual ~SGFACESET()
Definition: sg_faceset.cpp:67
bool valid
Definition: sg_faceset.h:90
bool validate(void)
Definition: sg_faceset.cpp:854
SGCOLORS * m_Colors
Definition: sg_faceset.h:79
bool AddChildNode(SGNODE *aNode) override
Definition: sg_faceset.cpp:407
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_faceset.cpp:493
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_faceset.cpp:438
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_faceset.cpp:601
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_index.cpp:171
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_index.cpp:307
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
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_index.cpp:161
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_index.cpp:52
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_index.cpp:262
The base class of all Scene Graph nodes.
Definition: sg_node.h:75
void SetName(const char *aName)
Definition: sg_node.cpp:155
virtual bool WriteCache(std::ostream &aFile, SGNODE *parentNode)=0
Write this node's data to a binary cache file.
const char * GetName(void)
Definition: sg_node.cpp:146
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.
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
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
S3D::SGTYPES GetNodeType(void) const noexcept
Return the type of this node instance.
Definition: sg_node.cpp:104
virtual bool AddChildNode(SGNODE *aNode)=0
SGNODE * m_Parent
Pointer to parent node; may be NULL for top level transform.
Definition: sg_node.h:227
std::string m_Name
name to use for referencing the entity by name.
Definition: sg_node.h:229
void addNodeRef(SGNODE *aNode)
Add a pointer to a node which references this node, but does not own.
Definition: sg_node.cpp:170
virtual void unlinkChildNode(const SGNODE *aNode)=0
Remove references to an owned child.
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 m_written
Set to true when the object has been written after a ReNameNodes().
Definition: sg_node.h:230
S3D::SGTYPES m_SGtype
Type of Scene Graph node.
Definition: sg_node.h:228
bool SwapParent(SGNODE *aNewParent)
Swap the ownership with the given parent.
Definition: sg_node.cpp:116
Define a set of vertex normals for a scene graph object.
Definition: sg_normals.h:39
virtual bool SetParent(SGNODE *aParent, bool notify=true) override
Set the parent SGNODE of this object.
Definition: sg_normals.cpp:59
void ReNameNodes(void) override
Rename a node and all its child nodes in preparation for write operations.
Definition: sg_normals.cpp:168
bool WriteCache(std::ostream &aFile, SGNODE *parentNode) override
Write this node's data to a binary cache file.
Definition: sg_normals.cpp:234
bool GetNormalList(size_t &aListSize, SGVECTOR *&aNormalList)
Definition: sg_normals.cpp:129
bool WriteVRML(std::ostream &aFile, bool aReuseFlag) override
Writes this node's data to a VRML file.
Definition: sg_normals.cpp:178
bool ReadCache(std::istream &aFile, SGNODE *parentNode) override
Reads binary format data from a cache file.
Definition: sg_normals.cpp:279
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
std::vector< SGVECTOR > norms
Definition: sg_normals.h:64
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
@ SGTYPE_COLORS
Definition: sg_types.h:38
@ SGTYPE_SHAPE
Definition: sg_types.h:44
@ SGTYPE_FACESET
Definition: sg_types.h:40
@ SGTYPE_NORMALS
Definition: sg_types.h:43
@ SGTYPE_COORDS
Definition: sg_types.h:41
@ SGTYPE_COORDINDEX
Definition: sg_types.h:42
#define NITEMS
Define a number of macros to aid in repetitious code which is probably best expressed as a preprocess...