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