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 The 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}
Describe 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
The wrapper for SGCOORDINDEX.
bool NewNode(SGNODE *aParent) override
Create a new node to associate with this wrapper.
The wrapper for SGCOORDS.
Definition: ifsg_coords.h:40
bool NewNode(SGNODE *aParent) override
Create a new node to associate with this wrapper.
bool SetCoordsList(size_t aListSize, const SGPOINT *aCoordsList)
bool AddCoord(double aXValue, double aYValue, double aZValue)
The wrapper for the SGFACESET class.
Definition: ifsg_faceset.h:40
bool NewNode(SGNODE *aParent) override
Create a new node to associate with this wrapper.
bool AddIndex(int aIndex)
Add a single index to the list.
Definition: ifsg_index.cpp:57
bool SetIndices(size_t nIndices, int *aIndexList)
Set the number of indices and creates a copy of the given index data.
Definition: ifsg_index.cpp:47
SGNODE * GetParent(void) const
Return a pointer to the parent SGNODE of this object or NULL if the object has no parent (ie.
Definition: ifsg_node.cpp:79
SGNODE * GetRawPtr(void) noexcept
Return the raw internal SGNODE pointer.
Definition: ifsg_node.cpp:65
void Destroy(void)
Delete the object held by this wrapper.
Definition: ifsg_node.cpp:55
bool AddChildNode(SGNODE *aNode)
Add a node as a child owned by this node.
Definition: ifsg_node.cpp:148
bool AddRefNode(SGNODE *aNode)
Add a reference to an existing node which is not owned by (not a child of) this node.
Definition: ifsg_node.cpp:128
The wrapper for the SGNORMALS class.
Definition: ifsg_normals.h:40
bool NewNode(SGNODE *aParent) override
Create a new node to associate with this wrapper.
bool AddNormal(double aXValue, double aYValue, double aZValue)
The wrapper for the SGSHAPE class.
Definition: ifsg_shape.h:40
bool NewNode(SGNODE *aParent) override
Create a new node to associate with this wrapper.
Definition: ifsg_shape.cpp:121
The wrapper for the VRML compatible TRANSFORM block class SCENEGRAPH.
bool Attach(SGNODE *aNode) override
Associate 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)
Write 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)
Return the normal vector of a triangle described by vertices p1, p2, p3.
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)
bool CanRender(void)
#define PLUGIN_3D_IDF_MAJOR
#define PLUGIN_3D_IDF_PATCH
SCENEGRAPH * Load(char const *aFileName)
Read a model file and creates a generic display structure.
static char ext2[]
char const * GetFileFilter(int aIndex)
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)
Retrieve the version of the instantiated plugin for informational purposes.
#define PLUGIN_3D_IDF_REVNO
static char ext3[]
const char * GetKicadPluginName(void)
Return the name of the plugin instance, for example IDFv3.
static char ext1[]
int GetNExtensions(void)
int GetNFilters(void)
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]