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