KiCad PCB EDA Suite
s3d_plugin_idf.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) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25// Note: the board's bottom side is at Z = 0
26
27#include <iostream>
28#include <sstream>
29#include <cmath>
30#include <string>
31#include <map>
32#include <wx/filename.h>
33#include <wx/log.h>
34#include <wx/string.h>
35
38#include "idf_parser.h"
39#include "vrml_layer.h"
40
41#define PLUGIN_3D_IDF_MAJOR 1
42#define PLUGIN_3D_IDF_MINOR 0
43#define PLUGIN_3D_IDF_PATCH 0
44#define PLUGIN_3D_IDF_REVNO 0
45
46// number of colors in the palette; cycles from 1..NCOLORS;
47// number 0 is special (the PCB board color)
48#define NCOLORS 6
49
55const wxChar* const traceIdfPlugin = wxT( "KICAD_IDF_PLUGIN" );
56
57
58// read and instantiate an IDF component outline
59static SCENEGRAPH* loadIDFOutline( const wxString& aFileName );
60
61
62// read and render an IDF board assembly
63static SCENEGRAPH* loadIDFBoard( const wxString& aFileName );
64
65
66// model a single extruded outline
67// idxColor = color index to use
68// aParent = parent SCENEGRAPH object, if any
69static SCENEGRAPH* addOutline( IDF3_COMP_OUTLINE* outline, int idxColor, SGNODE* aParent );
70
71
72// model the board extrusion
73static SCENEGRAPH* makeBoard( IDF3_BOARD& brd, SGNODE* aParent );
74
75
76// model all included components
77static bool makeComponents( IDF3_BOARD& brd, SGNODE* aParent );
78
79
80// model any .OTHER_OUTLINE items
81static bool makeOtherOutlines( IDF3_BOARD& brd, SGNODE* aParent );
82
83
84// convert the IDF outline to VRML intermediate data
85static bool getOutlineModel( VRML_LAYER& model, const std::list< IDF_OUTLINE* >* items );
86
87
88// convert IDF segment data to VRML segment data
89static bool addSegment( VRML_LAYER& model, IDF_SEGMENT* seg, int icont, int iseg );
90
91
92// convert the VRML intermediate data into SG* data
93static SCENEGRAPH* vrmlToSG( VRML_LAYER& vpcb, int idxColor, SGNODE* aParent, double top,
94 double bottom );
95
96
98{
99public:
101 {
102 setlocale( LC_NUMERIC, "C" );
103 }
104
106 {
107 setlocale( LC_NUMERIC, "" );
108 }
109};
110
111
112static SGNODE* getColor( IFSG_SHAPE& shape, int colorIdx )
113{
114 IFSG_APPEARANCE material( shape );
115
116 static int cidx = 1;
117 int idx;
118
119 if( colorIdx == -1 )
120 idx = cidx;
121 else
122 idx = colorIdx;
123
124 switch( idx )
125 {
126 case 0:
127 // green for PCB
128 material.SetSpecular( 0.13f, 0.81f, 0.22f );
129 material.SetDiffuse( 0.13f, 0.81f, 0.22f );
130
131 // default ambient intensity
132 material.SetShininess( 0.3f );
133 break;
134
135 case 1:
136 // magenta
137 material.SetSpecular( 0.8f, 0.0f, 0.8f );
138 material.SetDiffuse( 0.6f, 0.0f, 0.6f );
139
140 // default ambient intensity
141 material.SetShininess( 0.3f );
142 break;
143
144 case 2:
145 // red
146 material.SetSpecular( 0.69f, 0.14f, 0.14f );
147 material.SetDiffuse( 0.69f, 0.14f, 0.14f );
148
149 // default ambient intensity
150 material.SetShininess( 0.3f );
151 break;
152
153 case 3:
154 // orange
155 material.SetSpecular( 1.0f, 0.44f, 0.0f );
156 material.SetDiffuse( 1.0f, 0.44f, 0.0f );
157
158 // default ambient intensity
159 material.SetShininess( 0.3f );
160 break;
161
162 case 4:
163 // yellow
164 material.SetSpecular( 0.93f, 0.94f, 0.16f );
165 material.SetDiffuse( 0.93f, 0.94f, 0.16f );
166
167 // default ambient intensity
168 material.SetShininess( 0.3f );
169 break;
170
171 case 5:
172 // blue
173 material.SetSpecular( 0.1f, 0.11f, 0.88f );
174 material.SetDiffuse( 0.1f, 0.11f, 0.88f );
175
176 // default ambient intensity
177 material.SetShininess( 0.3f );
178 break;
179
180 default:
181 // violet
182 material.SetSpecular( 0.32f, 0.07f, 0.64f );
183 material.SetDiffuse( 0.32f, 0.07f, 0.64f );
184
185 // default ambient intensity
186 material.SetShininess( 0.3f );
187 break;
188 }
189
190 if( ( colorIdx == -1 ) && ( ++cidx > NCOLORS ) )
191 cidx = 1;
192
193 return material.GetRawPtr();
194}
195
196
197const char* GetKicadPluginName( void )
198{
199 return "PLUGIN_3D_IDF";
200}
201
202
203void GetPluginVersion( unsigned char* Major, unsigned char* Minor, unsigned char* Patch,
204 unsigned char* Revision )
205{
206 if( Major )
207 *Major = PLUGIN_3D_IDF_MAJOR;
208
209 if( Minor )
210 *Minor = PLUGIN_3D_IDF_MINOR;
211
212 if( Patch )
213 *Patch = PLUGIN_3D_IDF_PATCH;
214
215 if( Revision )
216 *Revision = PLUGIN_3D_IDF_REVNO;
217}
218
219
220// number of extensions supported
221#ifdef _WIN32
222 #define NEXTS 2
223#else
224 #define NEXTS 4
225#endif
226
227
228// number of filter sets supported
229#define NFILS 2
230
231
232static char ext0[] = "idf";
233static char ext1[] = "emn";
234
235
236#ifdef _WIN32
237 static char fil0[] = "IDF (*.idf)|*.idf";
238 static char fil1[] = "IDF BRD v2/v3 (*.emn)|*.emn";
239#else
240 static char ext2[] = "IDF";
241 static char ext3[] = "EMN";
242 static char fil0[] = "IDF (*.idf;*.IDF)|*.idf;*.IDF";
243 static char fil1[] = "IDF BRD (*.emn;*.EMN)|*.emn;*.EMN";
244#endif
245
246static struct FILE_DATA
247{
248 char const* extensions[NEXTS];
249 char const* filters[NFILS];
250
252 {
253 extensions[0] = ext0;
254 extensions[1] = ext1;
255 filters[0] = fil0;
256 filters[1] = fil1;
257
258#ifndef _WIN32
259 extensions[2] = ext2;
260 extensions[3] = ext3;
261#endif
262 }
263
265
266
267int GetNExtensions( void )
268{
269 return NEXTS;
270}
271
272
273char const* GetModelExtension( int aIndex )
274{
275 if( aIndex < 0 || aIndex >= NEXTS )
276 return nullptr;
277
278 return file_data.extensions[aIndex];
279}
280
281
282int GetNFilters( void )
283{
284 return NFILS;
285}
286
287
288char const* GetFileFilter( int aIndex )
289{
290 if( aIndex < 0 || aIndex >= NFILS )
291 return nullptr;
292
293 return file_data.filters[aIndex];
294}
295
296
297bool CanRender( void )
298{
299 // this plugin supports rendering of IDF component outlines
300 return true;
301}
302
303
304SCENEGRAPH* Load( char const* aFileName )
305{
306 if( nullptr == aFileName )
307 return nullptr;
308
309 wxFileName fname;
310 fname.Assign( wxString::FromUTF8Unchecked( aFileName ) );
311
312 wxString ext = fname.GetExt();
313
314 SCENEGRAPH* data = nullptr;
315
316 if( !ext.Cmp( wxT( "idf" ) ) || !ext.Cmp( wxT( "IDF" ) ) )
317 {
318 data = loadIDFOutline( fname.GetFullPath() );
319 }
320
321 if( !ext.Cmp( wxT( "emn" ) ) || !ext.Cmp( wxT( "EMN" ) ) )
322 {
323 data = loadIDFBoard( fname.GetFullPath() );
324 }
325
326 // DEBUG: WRITE OUT IDF FILE TO CONFIRM NORMALS
327#if defined( DEBUG_IDF ) && DEBUG_IDF > 3
328 if( data )
329 {
330 wxFileName fn( aFileName );
331 wxString output = wxT( "_idf-" );
332 output.append( fn.GetName() );
333 output.append( wxT( ".wrl" ) );
334 S3D::WriteVRML( output.ToUTF8(), true, (SGNODE*) ( data ), true, true );
335 }
336#endif
337
338 return data;
339}
340
341
342static bool getOutlineModel( VRML_LAYER& model, const std::list< IDF_OUTLINE* >* items )
343{
344 // empty outlines are not unusual so we fail quietly
345 if( items->size() < 1 )
346 return false;
347
348 int nvcont = 0;
349 int iseg = 0;
350
351 std::list< IDF_OUTLINE* >::const_iterator scont = items->begin();
352 std::list< IDF_OUTLINE* >::const_iterator econt = items->end();
353 std::list<IDF_SEGMENT*>::iterator sseg;
354 std::list<IDF_SEGMENT*>::iterator eseg;
355
356 IDF_SEGMENT lseg;
357
358 while( scont != econt )
359 {
360 nvcont = model.NewContour();
361
362 if( nvcont < 0 )
363 {
364 wxLogTrace( traceIdfPlugin, wxT( "%s:%s:%s\n"
365 "* [INFO] cannot create an outline" ),
366 __FILE__, __FUNCTION__, __LINE__ );
367
368 return false;
369 }
370
371 if( (*scont)->size() < 1 )
372 {
373 wxLogTrace( traceIdfPlugin, wxT( "%s:%s:%s\n "
374 "* [INFO] invalid contour: no vertices" ),
375 __FILE__, __FUNCTION__, __LINE__ );
376
377 return false;
378 }
379
380 sseg = (*scont)->begin();
381 eseg = (*scont)->end();
382
383 iseg = 0;
384
385 while( sseg != eseg )
386 {
387 lseg = **sseg;
388
389 if( !addSegment( model, &lseg, nvcont, iseg ) )
390 {
391 wxLogTrace( traceIdfPlugin, wxT( "%s:%s:%s\n"
392 "* [BUG] cannot add segment" ),
393 __FILE__, __FUNCTION__, __LINE__ );
394
395 return false;
396 }
397
398 ++iseg;
399 ++sseg;
400 }
401
402 ++scont;
403 }
404
405 return true;
406}
407
408
409static bool addSegment( VRML_LAYER& model, IDF_SEGMENT* seg, int icont, int iseg )
410{
411 // note: in all cases we must add all but the last point in the segment
412 // to avoid redundant points
413
414 if( seg->angle != 0.0 )
415 {
416 if( seg->IsCircle() )
417 {
418 if( iseg != 0 )
419 {
420 wxLogTrace( traceIdfPlugin,
421 wxT( "%s:%s:%s\n"
422 "* [INFO] adding a circle to an existing vertex list" ),
423 __FILE__, __FUNCTION__, __LINE__ );
424
425 return false;
426 }
427
428 return model.AppendCircle( seg->center.x, seg->center.y, seg->radius, icont );
429 }
430 else
431 {
432 return model.AppendArc( seg->center.x, seg->center.y, seg->radius,
433 seg->offsetAngle, seg->angle, icont );
434 }
435 }
436
437 if( !model.AddVertex( icont, seg->startPoint.x, seg->startPoint.y ) )
438 return false;
439
440 return true;
441}
442
443
444static SCENEGRAPH* vrmlToSG( VRML_LAYER& vpcb, int idxColor, SGNODE* aParent, double top,
445 double bottom )
446{
447 vpcb.Tesselate( nullptr );
448 std::vector< double > vertices;
449 std::vector< int > idxPlane;
450 std::vector< int > idxSide;
451
452 if( top < bottom )
453 {
454 double tmp = top;
455 top = bottom;
456 bottom = tmp;
457 }
458
459 if( !vpcb.Get3DTriangles( vertices, idxPlane, idxSide, top, bottom ) )
460 {
461 wxLogTrace( traceIdfPlugin, wxT( "%s:%s:%s\n"
462 "* [INFO] no vertex data" ),
463 __FILE__, __FUNCTION__, __LINE__ );
464
465 return nullptr;
466 }
467
468 if( ( idxPlane.size() % 3 ) || ( idxSide.size() % 3 ) )
469 {
470 wxLogTrace( traceIdfPlugin,
471 wxT( "%s:%s:%s\n"
472 "* [BUG] index lists are not a multiple of 3 (not a triangle list)" ),
473 __FILE__, __FUNCTION__, __LINE__ );
474
475 return nullptr;
476 }
477
478 std::vector< SGPOINT > vlist;
479 size_t nvert = vertices.size() / 3;
480 size_t j = 0;
481
482 for( size_t i = 0; i < nvert; ++i, j+= 3 )
483 vlist.emplace_back( vertices[j], vertices[j+1], vertices[j+2] );
484
485 // create the intermediate scenegraph
486 IFSG_TRANSFORM* tx0 = new IFSG_TRANSFORM( aParent ); // tx0 = Transform for this outline
487
488 // shape will hold (a) all vertices and (b) a local list of normals
489 IFSG_SHAPE* shape = new IFSG_SHAPE( *tx0 );
490
491 // this face shall represent the top and bottom planes
492 IFSG_FACESET* face = new IFSG_FACESET( *shape );
493
494 // coordinates for all faces
495 IFSG_COORDS* cp = new IFSG_COORDS( *face );
496 cp->SetCoordsList( nvert, &vlist[0] );
497
498 // coordinate indices for top and bottom planes only.
499 IFSG_COORDINDEX* coordIdx = new IFSG_COORDINDEX( *face );
500 coordIdx->SetIndices( idxPlane.size(), &idxPlane[0] );
501
502 // normals for the top and bottom planes.
503 IFSG_NORMALS* norms = new IFSG_NORMALS( *face );
504
505 // number of TOP (and bottom) vertices
506 j = nvert / 2;
507
508 // set the TOP normals
509 for( size_t i = 0; i < j; ++i )
510 norms->AddNormal( 0.0, 0.0, 1.0 );
511
512 // set the BOTTOM normals
513 for( size_t i = 0; i < j; ++i )
514 norms->AddNormal( 0.0, 0.0, -1.0 );
515
516 // assign a color from the palette
517 SGNODE* modelColor = getColor( *shape, idxColor );
518
519 // create a second shape describing the vertical walls of the IDF extrusion
520 // using per-vertex-per-face-normals
521 shape->NewNode( *tx0 );
522 shape->AddRefNode( modelColor ); // set the color to be the same as the top/bottom
523 face->NewNode( *shape );
524 cp->NewNode( *face ); // new vertex list
525 norms->NewNode( *face ); // new normals list
526 coordIdx->NewNode( *face ); // new index list
527
528 // populate the new per-face vertex list and its indices and normals
529 std::vector< int >::iterator sI = idxSide.begin();
530 std::vector< int >::iterator eI = idxSide.end();
531
532 size_t sidx = 0; // index to the new coord set
533 SGPOINT p1, p2, p3;
534 SGVECTOR vnorm;
535
536 while( sI != eI )
537 {
538 p1 = vlist[*sI];
539 cp->AddCoord( p1 );
540 ++sI;
541
542 p2 = vlist[*sI];
543 cp->AddCoord( p2 );
544 ++sI;
545
546 p3 = vlist[*sI];
547 cp->AddCoord( p3 );
548 ++sI;
549
550 vnorm.SetVector( S3D::CalcTriNorm( p1, p2, p3 ) );
551 norms->AddNormal( vnorm );
552 norms->AddNormal( vnorm );
553 norms->AddNormal( vnorm );
554
555 coordIdx->AddIndex( (int)sidx );
556 ++sidx;
557 coordIdx->AddIndex( (int)sidx );
558 ++sidx;
559 coordIdx->AddIndex( (int)sidx );
560 ++sidx;
561 }
562
563 SCENEGRAPH* data = (SCENEGRAPH*)tx0->GetRawPtr();
564
565 // delete the API wrappers
566 delete shape;
567 delete face;
568 delete coordIdx;
569 delete cp;
570 delete tx0;
571
572 return data;
573}
574
575
576static SCENEGRAPH* addOutline( IDF3_COMP_OUTLINE* outline, int idxColor, SGNODE* aParent )
577{
578 VRML_LAYER vpcb;
579
580 if( !getOutlineModel( vpcb, outline->GetOutlines() ) )
581 {
582 wxLogTrace( traceIdfPlugin, wxT( "%s:%s:%s\n"
583 "* [INFO] no valid outline data" ),
584 __FILE__, __FUNCTION__, __LINE__ );
585
586 return nullptr;
587 }
588
589 vpcb.EnsureWinding( 0, false );
590
591 double top = outline->GetThickness();
592 double bot = 0.0;
593
594 // note: some IDF entities permit negative heights
595 if( top < bot )
596 {
597 bot = top;
598 top = 0.0;
599 }
600
601 SCENEGRAPH* data = vrmlToSG( vpcb, idxColor, aParent, top, bot );
602
603 return data;
604}
605
606
607static SCENEGRAPH* loadIDFOutline( const wxString& aFileName )
608{
609 LOCALESWITCH switcher;
610 IDF3_BOARD brd( IDF3::CAD_ELEC );
611 IDF3_COMP_OUTLINE* outline = nullptr;
612
613 outline = brd.GetComponentOutline( aFileName );
614
615 if( nullptr == outline )
616 {
617 wxLogTrace( traceIdfPlugin, wxT( "%s:%s:%s\n"
618 "* [INFO] Failed to read IDF data:\n"
619 "%s\n"
620 "* [INFO] no outline for file '%s'" ),
621 __FILE__, __FUNCTION__, __LINE__,
622 brd.GetError(),
623 aFileName );
624
625 return nullptr;
626 }
627
628 SCENEGRAPH* data = addOutline( outline, -1, nullptr );
629
630 return data;
631}
632
633
634static SCENEGRAPH* loadIDFBoard( const wxString& aFileName )
635{
636 LOCALESWITCH switcher;
637 IDF3_BOARD brd( IDF3::CAD_ELEC );
638
639 // note: if the IDF model is defective no outline substitutes shall be made
640 if( !brd.ReadFile( aFileName, true ) )
641 {
642 wxLogTrace( traceIdfPlugin, wxT( "%s:%s:%s\n"
643 "* [INFO] Error '%s' occurred reading IDF file: %s" ),
644 __FILE__, __FUNCTION__, __LINE__,
645 brd.GetError(),
646 aFileName );
647
648 return nullptr;
649 }
650
651 IFSG_TRANSFORM tx0( true );
652 SGNODE* topNode = tx0.GetRawPtr();
653
654 bool noBoard = false;
655 bool noComp = false;
656 bool noOther = false;
657
658 if( nullptr == makeBoard( brd, topNode ) )
659 noBoard = true;
660
661 if( !makeComponents( brd, topNode ) )
662 noComp = true;
663
664 if( !makeOtherOutlines( brd, topNode ) )
665 noOther = true;
666
667 if( noBoard && noComp && noOther )
668 {
669 tx0.Destroy();
670 return nullptr;
671 }
672
673 return (SCENEGRAPH*) topNode;
674}
675
676
677static SCENEGRAPH* makeBoard( IDF3_BOARD& brd, SGNODE* aParent )
678{
679 if( nullptr == aParent )
680 return nullptr;
681
682 VRML_LAYER vpcb;
683
684 // check if no board outline
685 if( brd.GetBoardOutlinesSize() < 1 )
686 return nullptr;
687
688
689 if( !getOutlineModel( vpcb, brd.GetBoardOutline()->GetOutlines() ) )
690 return nullptr;
691
692 vpcb.EnsureWinding( 0, false );
693
694 int nvcont = vpcb.GetNContours() - 1;
695
696 while( nvcont > 0 )
697 vpcb.EnsureWinding( nvcont--, true );
698
699 // Add the drill holes
700 const std::list<IDF_DRILL_DATA*>* drills = &brd.GetBoardDrills();
701
702 std::list<IDF_DRILL_DATA*>::const_iterator sd = drills->begin();
703 std::list<IDF_DRILL_DATA*>::const_iterator ed = drills->end();
704
705 while( sd != ed )
706 {
707 vpcb.AddCircle( (*sd)->GetDrillXPos(), (*sd)->GetDrillYPos(),
708 (*sd)->GetDrillDia() / 2.0, true );
709 ++sd;
710 }
711
712 std::map< std::string, IDF3_COMPONENT* >*const comp = brd.GetComponents();
713 std::map< std::string, IDF3_COMPONENT* >::const_iterator sc = comp->begin();
714 std::map< std::string, IDF3_COMPONENT* >::const_iterator ec = comp->end();
715
716 while( sc != ec )
717 {
718 drills = sc->second->GetDrills();
719 sd = drills->begin();
720 ed = drills->end();
721
722 while( sd != ed )
723 {
724 vpcb.AddCircle( (*sd)->GetDrillXPos(), (*sd)->GetDrillYPos(),
725 (*sd)->GetDrillDia() / 2.0, true );
726 ++sd;
727 }
728
729 ++sc;
730 }
731
732 double top = brd.GetBoardThickness();
733
734 SCENEGRAPH* data = vrmlToSG( vpcb, 0, aParent, top, 0.0 );
735
736 return data;
737}
738
739
740static bool makeComponents( IDF3_BOARD& brd, SGNODE* aParent )
741{
742 if( nullptr == aParent )
743 return false;
744
745 int ncomponents = 0;
746
747 double brdTop = brd.GetBoardThickness();
748
749 // Add the component outlines
750 const std::map< std::string, IDF3_COMPONENT* >*const comp = brd.GetComponents();
751 std::map< std::string, IDF3_COMPONENT* >::const_iterator sc = comp->begin();
752 std::map< std::string, IDF3_COMPONENT* >::const_iterator ec = comp->end();
753
754 std::list< IDF3_COMP_OUTLINE_DATA* >::const_iterator so;
755 std::list< IDF3_COMP_OUTLINE_DATA* >::const_iterator eo;
756
757 double vX, vY, vA;
758 double tX, tY, tZ, tA;
759 bool bottom;
760 IDF3::IDF_LAYER lyr;
761
762 std::map< std::string, SGNODE* > dataMap; // map data by UID
763 std::map< std::string, SGNODE* >::iterator dataItem;
764 IDF3_COMP_OUTLINE* pout;
765
766 while( sc != ec )
767 {
768 sc->second->GetPosition( vX, vY, vA, lyr );
769
770 if( lyr == IDF3::LYR_BOTTOM )
771 bottom = true;
772 else
773 bottom = false;
774
775 so = sc->second->GetOutlinesData()->begin();
776 eo = sc->second->GetOutlinesData()->end();
777
778 while( so != eo )
779 {
780 if( std::abs( (*so)->GetOutline()->GetThickness() ) < 0.001 )
781 {
782 ++so;
783 continue;
784 }
785
786 (*so)->GetOffsets( tX, tY, tZ, tA );
787 tX += vX;
788 tY += vY;
789 tA += vA;
790
791 pout = (IDF3_COMP_OUTLINE*)((*so)->GetOutline());
792
793 if( nullptr == pout )
794 {
795 ++so;
796 continue;
797 }
798
799 dataItem = dataMap.find( pout->GetUID() );
800 SCENEGRAPH* sg = nullptr;
801
802 if( dataItem == dataMap.end() )
803 {
804 sg = addOutline( pout, -1, nullptr );
805
806 if( nullptr == sg )
807 {
808 ++so;
809 continue;
810 }
811
812 ++ncomponents;
813 dataMap.insert( std::pair< std::string, SGNODE* >( pout->GetUID(), (SGNODE*)sg ) );
814 }
815 else
816 {
817 sg = (SCENEGRAPH*) dataItem->second;
818 }
819
820 IFSG_TRANSFORM tx0( aParent );
821 IFSG_TRANSFORM txN( false );
822 txN.Attach( (SGNODE*)sg );
823
824 if( nullptr == txN.GetParent() )
825 tx0.AddChildNode( txN );
826 else
827 tx0.AddRefNode( txN );
828
829 if( bottom )
830 {
831 tx0.SetTranslation( SGPOINT( tX, tY, -tZ ) );
832 // for an item on the back of the board we have a compounded rotation,
833 // first a flip on the Y axis as per the IDF spec and then a rotation
834 // of -tA degrees on the Z axis. The resultant rotation axis is an
835 // XY vector equivalent to (0,1) rotated by -(tA/2) degrees
836 //
837 double ang = -tA * M_PI / 360.0;
838 double sinA = sin( ang );
839 double cosA = cos( ang );
840 tx0.SetRotation( SGVECTOR( -sinA, cosA , 0 ), M_PI );
841 }
842 else
843 {
844 tx0.SetTranslation( SGPOINT( tX, tY, tZ + brdTop ) );
845 tx0.SetRotation( SGVECTOR( 0, 0, 1 ), tA * M_PI / 180.0 );
846 }
847
848 ++so;
849 }
850
851 ++sc;
852 }
853
854 if( 0 == ncomponents )
855 return false;
856
857 return true;
858}
859
860
861static bool makeOtherOutlines( IDF3_BOARD& brd, SGNODE* aParent )
862{
863 if( nullptr == aParent )
864 return false;
865
866 VRML_LAYER vpcb;
867 int ncomponents = 0;
868
869 double brdTop = brd.GetBoardThickness();
870 double top, bot;
871
872 // Add the component outlines
873 const std::map< std::string, OTHER_OUTLINE* >*const comp = brd.GetOtherOutlines();
874 std::map< std::string, OTHER_OUTLINE* >::const_iterator sc = comp->begin();
875 std::map< std::string, OTHER_OUTLINE* >::const_iterator ec = comp->end();
876
877 int nvcont;
878
879 OTHER_OUTLINE* pout;
880
881 while( sc != ec )
882 {
883 pout = sc->second;
884
885 if( std::abs( pout->GetThickness() ) < 0.001 )
886 {
887 ++sc;
888 continue;
889 }
890
891 if( !getOutlineModel( vpcb, pout->GetOutlines() ) )
892 {
893 vpcb.Clear();
894 ++sc;
895 continue;
896 }
897
898 vpcb.EnsureWinding( 0, false );
899
900 nvcont = vpcb.GetNContours() - 1;
901
902 while( nvcont > 0 )
903 vpcb.EnsureWinding( nvcont--, true );
904
905 if( pout->GetSide() == IDF3::LYR_BOTTOM )
906 {
907 top = 0.0;
908 bot = -pout->GetThickness();
909 }
910 else
911 {
912 bot = brdTop;
913 top = bot + pout->GetThickness();
914 }
915
916 if( nullptr == vrmlToSG( vpcb, -1, aParent, top, bot ) )
917 {
918 vpcb.Clear();
919 ++sc;
920 continue;
921 }
922
923 ++ncomponents;
924
925 vpcb.Clear();
926 ++sc;
927 }
928
929 if( 0 == ncomponents )
930 return false;
931
932 return true;
933}
describes the runtime-loadable interface to support loading and parsing of 3D models.
bool SetDiffuse(float aRVal, float aGVal, float aBVal)
bool SetSpecular(float aRVal, float aGVal, float aBVal)
bool SetShininess(float aShininess) noexcept
IFSG_COORDINDEX is the wrapper for SGCOORDINDEX.
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
IFSG_COORDS is the wrapper for SGCOORDS.
Definition: ifsg_coords.h:41
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
bool SetCoordsList(size_t aListSize, const SGPOINT *aCoordsList)
bool AddCoord(double aXValue, double aYValue, double aZValue)
IFSG_FACESET is the wrapper for the SGFACESET class.
Definition: ifsg_faceset.h:41
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
bool AddIndex(int aIndex)
Function AddIndex adds a single index to the list.
Definition: ifsg_index.cpp:57
bool SetIndices(size_t nIndices, int *aIndexList)
Function SetIndices sets the number of indices and creates a copy of the given index data.
Definition: ifsg_index.cpp:47
SGNODE * GetParent(void) const
Function GetParent returns a pointer to the parent SGNODE of this object or NULL if the object has no...
Definition: ifsg_node.cpp:79
SGNODE * GetRawPtr(void) noexcept
Function GetRawPtr() returns the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:65
void Destroy(void)
Function Destroy deletes the object held by this wrapper.
Definition: ifsg_node.cpp:55
bool AddChildNode(SGNODE *aNode)
Function AddChildNode adds a node as a child owned by this node.
Definition: ifsg_node.cpp:148
bool AddRefNode(SGNODE *aNode)
Function AddRefNode adds a reference to an existing node which is not owned by (not a child of) this ...
Definition: ifsg_node.cpp:128
IFSG_NORMALS is the wrapper for the SGNORMALS class.
Definition: ifsg_normals.h:41
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
bool AddNormal(double aXValue, double aYValue, double aZValue)
IFSG_SHAPE is the wrapper for the SGSHAPE class.
Definition: ifsg_shape.h:41
bool NewNode(SGNODE *aParent) override
Function NewNode creates a new node to associate with this wrapper.
Definition: ifsg_shape.cpp:121
IFSG_TRANSFORM is the wrapper for the VRML compatible TRANSFORM block class SCENEGRAPH.
bool Attach(SGNODE *aNode) override
Function Attach associates a given SGNODE* with this wrapper.
bool SetTranslation(const SGPOINT &aTranslation) noexcept
bool SetRotation(const SGVECTOR &aRotationAxis, double aAngle)
Define the basic data set required to represent a 3D model.
Definition: scenegraph.h:45
The base class of all Scene Graph nodes.
Definition: sg_node.h:75
void SetVector(double aXVal, double aYVal, double aZVal)
Definition: sg_base.cpp:233
const wxChar *const traceIdfPlugin
Flag to enable IDF plugin trace output.
collects header files for all SG* wrappers and the API
SGLIB_API bool WriteVRML(const char *filename, bool overwrite, SGNODE *aTopNode, bool reuse, bool renameNodes)
Function WriteVRML writes out the given node and its subnodes to a VRML2 file.
Definition: ifsg_api.cpp:77
SGLIB_API SGVECTOR CalcTriNorm(const SGPOINT &p1, const SGPOINT &p2, const SGPOINT &p3)
Function CalcTriNorm returns the normal vector of a triangle described by vertices p1,...
Definition: ifsg_api.cpp:464
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
static bool addSegment(VRML_LAYER &model, IDF_SEGMENT *seg, int icont, int iseg)
static bool makeComponents(IDF3_BOARD &brd, SGNODE *aParent)
static bool getOutlineModel(VRML_LAYER &model, const std::list< IDF_OUTLINE * > *items)
static char fil0[]
static char fil1[]
#define NEXTS
static struct FILE_DATA file_data
char const * GetModelExtension(int aIndex)
Function GetModelExtension.
bool CanRender(void)
Function CanRender.
#define PLUGIN_3D_IDF_MAJOR
#define PLUGIN_3D_IDF_PATCH
SCENEGRAPH * Load(char const *aFileName)
reads a model file and creates a generic display structure
static char ext2[]
char const * GetFileFilter(int aIndex)
Function GetFileFilter.
static SCENEGRAPH * makeBoard(IDF3_BOARD &brd, SGNODE *aParent)
#define PLUGIN_3D_IDF_MINOR
#define NFILS
static char ext0[]
static SCENEGRAPH * loadIDFOutline(const wxString &aFileName)
void GetPluginVersion(unsigned char *Major, unsigned char *Minor, unsigned char *Patch, unsigned char *Revision)
Function GetPluginVersion retrieves the version of the instantiated plugin for informational purposes...
#define PLUGIN_3D_IDF_REVNO
static char ext3[]
const char * GetKicadPluginName(void)
Function GetKicadPluginName returns the name of the plugin instance; for example IDFv3.
static char ext1[]
int GetNExtensions(void)
Function GetNExtensions.
int GetNFilters(void)
Function GetNFilters.
static SCENEGRAPH * loadIDFBoard(const wxString &aFileName)
#define NCOLORS
static bool makeOtherOutlines(IDF3_BOARD &brd, SGNODE *aParent)
static SCENEGRAPH * addOutline(IDF3_COMP_OUTLINE *outline, int idxColor, SGNODE *aParent)
static SGNODE * getColor(IFSG_SHAPE &shape, int colorIdx)
static SCENEGRAPH * vrmlToSG(VRML_LAYER &vpcb, int idxColor, SGNODE *aParent, double top, double bottom)
char const * extensions[NEXTS]
char const * filters[NFILS]