KiCad PCB EDA Suite
Loading...
Searching...
No Matches
export_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) 2013 Cirilo Bernardo
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
22#include <list>
23#include <optional>
24#include <locale_io.h>
25#include <macros.h>
26#include <pcb_edit_frame.h>
27#include <board.h>
29#include <footprint.h>
31#include <io/idf/idf_parser.h>
32#include <pad.h>
33#include <pcb_shape.h>
34#include <build_version.h>
35#include <project_pcb.h>
36#include <reporter.h>
37#include "project.h"
38#include "3d_cache/3d_cache.h"
39#include "filename_resolver.h"
40#include "export_idf.h"
41
42
43#include <3d_math.h>
45#include <base_units.h> // to define pcbIUScale.FromMillimeter(x)
47
48
49// assumed default graphical line thickness: == 0.1mm
50#define LINE_WIDTH (pcbIUScale.mmToIU( 0.1 ))
51
52
54 REPORTER* aReporter ) :
55 m_board( aBoard ),
56 m_resolver( aResolver ),
57 m_settings( aSettings ),
58 m_reporter( aReporter )
59{
60 if( !m_settings )
61 {
62 m_defaultSettings = std::make_unique<JOB_EXPORT_PCB_IDF>();
64 }
65}
66
73static void idf_append_shape( PCB_SHAPE* aGraphic, double aScale, double aOffX, double aOffY,
74 std::list<IDF_SEGMENT*>& aLines )
75{
76 IDF_POINT sp, ep; // start and end points from KiCad item
77
78 switch( aGraphic->GetShape() )
79 {
81 {
82 if( aGraphic->GetStart() == aGraphic->GetEnd() )
83 break;
84
85 sp.x = aGraphic->GetStart().x * aScale + aOffX;
86 sp.y = -aGraphic->GetStart().y * aScale + aOffY;
87 ep.x = aGraphic->GetEnd().x * aScale + aOffX;
88 ep.y = -aGraphic->GetEnd().y * aScale + aOffY;
89 aLines.push_back( new IDF_SEGMENT( sp, ep ) );
90
91 break;
92 }
93
95 {
96 if( aGraphic->GetStart() == aGraphic->GetEnd() )
97 break;
98
99 // IDF Y is up-positive, so mirror KiCad's down-positive Y like the other shapes do
100 double top = -aGraphic->GetStart().y * aScale + aOffY;
101 double left = aGraphic->GetStart().x * aScale + aOffX;
102 double bottom = -aGraphic->GetEnd().y * aScale + aOffY;
103 double right = aGraphic->GetEnd().x * aScale + aOffX;
104
105 IDF_POINT corners[4];
106 corners[0] = IDF_POINT( left, top );
107 corners[1] = IDF_POINT( right, top );
108 corners[2] = IDF_POINT( right, bottom );
109 corners[3] = IDF_POINT( left, bottom );
110
111 aLines.push_back( new IDF_SEGMENT( corners[0], corners[1] ) );
112 aLines.push_back( new IDF_SEGMENT( corners[1], corners[2] ) );
113 aLines.push_back( new IDF_SEGMENT( corners[2], corners[3] ) );
114 aLines.push_back( new IDF_SEGMENT( corners[3], corners[0] ) );
115 break;
116 }
117
118 case SHAPE_T::ARC:
119 {
120 if( aGraphic->GetCenter() == aGraphic->GetStart() )
121 break;
122
123 sp.x = aGraphic->GetCenter().x * aScale + aOffX;
124 sp.y = -aGraphic->GetCenter().y * aScale + aOffY;
125 ep.x = aGraphic->GetStart().x * aScale + aOffX;
126 ep.y = -aGraphic->GetStart().y * aScale + aOffY;
127 aLines.push_back( new IDF_SEGMENT( sp, ep, -aGraphic->GetArcAngle().AsDegrees(), true ) );
128
129 break;
130 }
131
132 case SHAPE_T::CIRCLE:
133 {
134 if( aGraphic->GetRadius() == 0 )
135 break;
136
137 sp.x = aGraphic->GetCenter().x * aScale + aOffX;
138 sp.y = -aGraphic->GetCenter().y * aScale + aOffY;
139 ep.x = sp.x - aGraphic->GetRadius() * aScale;
140 ep.y = sp.y;
141
142 // Circles must always have an angle of +360 deg. to appease
143 // quirky MCAD implementations of IDF.
144 aLines.push_back( new IDF_SEGMENT( sp, ep, 360.0, true ) );
145
146 break;
147 }
148
149 case SHAPE_T::POLY:
150 {
151 if( !aGraphic->IsPolyShapeValid() )
152 break;
153
154 // Holes within an outline have no IDF representation; each outline is its own loop
155 const SHAPE_POLY_SET& polySet = aGraphic->GetPolyShape();
156
157 for( int ii = 0; ii < polySet.OutlineCount(); ++ii )
158 {
159 const SHAPE_LINE_CHAIN& chain = polySet.COutline( ii );
160
161 for( int jj = 0; jj < chain.PointCount(); ++jj )
162 {
163 const VECTOR2I& start = chain.CPoint( jj );
164 const VECTOR2I& end = chain.CPoint( ( jj + 1 ) % chain.PointCount() );
165
166 if( start == end )
167 continue;
168
169 sp.x = start.x * aScale + aOffX;
170 sp.y = -start.y * aScale + aOffY;
171 ep.x = end.x * aScale + aOffX;
172 ep.y = -end.y * aScale + aOffY;
173 aLines.push_back( new IDF_SEGMENT( sp, ep ) );
174 }
175 }
176
177 break;
178 }
179
180 case SHAPE_T::BEZIER:
181 {
183
184 const std::vector<VECTOR2I>& pts = aGraphic->GetBezierPoints();
185
186 for( size_t ii = 1; ii < pts.size(); ++ii )
187 {
188 if( pts[ii - 1] == pts[ii] )
189 continue;
190
191 sp.x = pts[ii - 1].x * aScale + aOffX;
192 sp.y = -pts[ii - 1].y * aScale + aOffY;
193 ep.x = pts[ii].x * aScale + aOffX;
194 ep.y = -pts[ii].y * aScale + aOffY;
195 aLines.push_back( new IDF_SEGMENT( sp, ep ) );
196 }
197
198 break;
199 }
200
201 default:
202 break;
203 }
204}
205
206
211static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard )
212{
213 double scale = aIDFBoard.GetUserScale();
214 std::list< IDF_SEGMENT* > lines; // IDF intermediate form of KiCad graphical item
215 IDF_OUTLINE* outline = nullptr; // graphical items forming an outline or cutout
216
217 // Footprint cutouts are emitted separately by idf_export_footprint(); like board cutouts they
218 // belong in the board outline section rather than the Other Outline section.
219
220 double offX, offY;
221 aIDFBoard.GetUserOffset( offX, offY );
222
223 // Retrieve segments and arcs from the board
224 for( BOARD_ITEM* item : aPcb->Drawings() )
225 {
226 if( item->Type() != PCB_SHAPE_T || item->GetLayer() != Edge_Cuts )
227 continue;
228
229 idf_append_shape( static_cast<PCB_SHAPE*>( item ), scale, offX, offY, lines );
230 }
231
232 // if there is no outline then use the bounding box
233 if( lines.empty() )
234 {
235 goto UseBoundingBox;
236 }
237
238 // get the board outline and write it out
239 // note: we do not use a try/catch block here since we intend
240 // to simply ignore unclosed loops and continue processing
241 // until we're out of segments to process
242 outline = new IDF_OUTLINE;
243 IDF3::GetOutline( lines, *outline );
244
245 if( outline->empty() )
246 goto UseBoundingBox;
247
248 aIDFBoard.AddBoardOutline( outline );
249 outline = nullptr;
250
251 // get all cutouts and write them out
252 while( !lines.empty() )
253 {
254 if( !outline )
255 outline = new IDF_OUTLINE;
256
257 IDF3::GetOutline( lines, *outline );
258
259 if( outline->empty() )
260 {
261 outline->Clear();
262 continue;
263 }
264
265 aIDFBoard.AddBoardOutline( outline );
266 outline = nullptr;
267 }
268
269 // an open loop on the final iteration leaves an allocated but empty outline behind
270 delete outline;
271
272 return;
273
274UseBoundingBox:
275
276 // clean up if necessary
277 while( !lines.empty() )
278 {
279 delete lines.front();
280 lines.pop_front();
281 }
282
283 if( outline )
284 outline->Clear();
285 else
286 outline = new IDF_OUTLINE;
287
288 // Fetch a rectangular bounding box for the board; there is always some uncertainty in the
289 // board dimensions computed via ComputeBoundingBox() since this depends on the individual
290 // footprint entities.
291 BOX2I bbbox = aPcb->GetBoardEdgesBoundingBox();
292
293 // convert to mm and compensate for an assumed LINE_WIDTH line thickness
294 double x = ( bbbox.GetOrigin().x + LINE_WIDTH / 2 ) * scale + offX;
295 double y = ( bbbox.GetOrigin().y + LINE_WIDTH / 2 ) * scale + offY;
296 double dx = ( bbbox.GetSize().x - LINE_WIDTH ) * scale;
297 double dy = ( bbbox.GetSize().y - LINE_WIDTH ) * scale;
298
299 double px[4], py[4];
300 px[0] = x;
301 py[0] = y;
302
303 px[1] = x;
304 py[1] = y + dy;
305
306 px[2] = x + dx;
307 py[2] = y + dy;
308
309 px[3] = x + dx;
310 py[3] = y;
311
312 IDF_POINT p1, p2;
313
314 p1.x = px[3];
315 p1.y = py[3];
316 p2.x = px[0];
317 p2.y = py[0];
318
319 outline->push( new IDF_SEGMENT( p1, p2 ) );
320
321 for( int i = 1; i < 4; ++i )
322 {
323 p1.x = px[i - 1];
324 p1.y = py[i - 1];
325 p2.x = px[i];
326 p2.y = py[i];
327
328 outline->push( new IDF_SEGMENT( p1, p2 ) );
329 }
330
331 aIDFBoard.AddBoardOutline( outline );
332}
333
334
336static std::optional<double> getModelHeight( const S3DMODEL& aModel, const VECTOR3D& aRotation, const VECTOR3D& aScale )
337{
338 if( !aModel.m_Meshes )
339 return std::nullopt;
340
341 const glm::mat4 modelMatrix = CalcModelMatrix( SFVEC3F( 0.0f, 0.0f, 0.0f ),
342 SFVEC3F( aRotation.x, aRotation.y, aRotation.z ),
343 SFVEC3F( aScale.x, aScale.y, aScale.z ) );
344 const SFVEC3F zRow( modelMatrix[0].z, modelMatrix[1].z, modelMatrix[2].z );
345
346 float ret = 0.0;
347
348 for( unsigned int meshIdx = 0; meshIdx < aModel.m_MeshesSize; ++meshIdx )
349 {
350 const SMESH& mesh = aModel.m_Meshes[meshIdx];
351
352 if( !mesh.m_Positions )
353 continue;
354
355 for( unsigned int vtx = 0; vtx < mesh.m_VertexSize; ++vtx )
356 {
357 const SFVEC3F& pos = mesh.m_Positions[vtx];
358 ret = std::max( ret, glm::dot( zRow, pos ) );
359 }
360 }
361
362 return ret;
363}
364
365
367{
368 wxString libraryName = aFootprint->GetFPID().GetLibNickname();
369 wxString footprintBasePath = wxEmptyString;
370
371 if( m_board->GetProject() )
372 {
373 std::optional<LIBRARY_TABLE_ROW*> fpRow =
374 PROJECT_PCB::FootprintLibAdapter( m_board->GetProject() )->GetRow( libraryName );
375
376 if( fpRow )
377 footprintBasePath = LIBRARY_MANAGER::GetFullURI( *fpRow, true );
378 }
379
380 double scale = aIDFBoard.GetUserScale();
381 double dx, dy;
382 aIDFBoard.GetUserOffset( dx, dy );
383
384 std::string refdes;
385 IDF3_COMPONENT* comp = nullptr;
386
387 auto sM = aFootprint->Models().begin();
388 auto eM = aFootprint->Models().end();
389 wxFileName idfFile;
390 wxString idfExt;
391
392 while( sM != eM )
393 {
394 if( !sM->m_Show )
395 {
396 ++sM;
397 continue;
398 }
399
400 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
401 embeddedFilesStack.push_back( aFootprint->GetEmbeddedFiles() );
402 embeddedFilesStack.push_back( m_board->GetEmbeddedFiles() );
403
404 idfFile.Assign( m_resolver->ResolvePath( sM->m_Filename, footprintBasePath, std::move( embeddedFilesStack ) ) );
405 idfExt = idfFile.GetExt();
406
407 if( idfExt.Cmp( wxT( "idf" ) ) && idfExt.Cmp( wxT( "IDF" ) ) )
408 {
409 ++sM;
410 continue;
411 }
412
413 if( refdes.empty() )
414 {
415 refdes = TO_UTF8( aFootprint->Reference().GetShownText( RESOLVED ) );
416
417 // NOREFDES cannot be used or else the software gets confused
418 // when writing out the placement data due to conflicting
419 // placement and layer specifications; to work around this we
420 // create a (hopefully) unique refdes for our exported part.
421 if( refdes.empty() || !refdes.compare( "~" ) )
422 refdes = aIDFBoard.GetNewRefDes();
423 }
424
425 IDF3_COMP_OUTLINE* outline = aIDFBoard.GetComponentOutline( idfFile.GetFullPath() );
426
427 if( !outline )
428 {
429 if( m_reporter )
430 {
431 m_reporter->Report( wxString::Format( "Error exporting footprint %s model %s",
432 aFootprint->GetReference(), idfFile.GetFullPath() ),
434 }
435
436 return false;
437 }
438
439 double rotz = aFootprint->GetOrientation().AsDegrees();
440 double locx = sM->m_Offset.x; // part offsets are in mm
441 double locy = sM->m_Offset.y;
442 double locz = sM->m_Offset.z;
443 double lrot = sM->m_Rotation.z;
444
445 bool top = ( aFootprint->GetLayer() == B_Cu ) ? false : true;
446
447 if( top )
448 {
449 locy = -locy;
450 RotatePoint( &locx, &locy, aFootprint->GetOrientation() );
451 locy = -locy;
452 }
453
454 if( !top )
455 {
456 lrot = -lrot;
457 RotatePoint( &locx, &locy, aFootprint->GetOrientation() );
458 locy = -locy;
459
460 rotz = 180.0 - rotz;
461
462 if( rotz >= 360.0 )
463 while( rotz >= 360.0 ) rotz -= 360.0;
464
465 if( rotz <= -360.0 )
466 while( rotz <= -360.0 ) rotz += 360.0;
467 }
468
469 if( comp == nullptr )
470 comp = aIDFBoard.FindComponent( refdes );
471
472 if( comp == nullptr )
473 {
474 comp = new IDF3_COMPONENT( &aIDFBoard );
475
476 comp->SetRefDes( refdes );
477
478 if( top )
479 {
480 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
481 -aFootprint->GetPosition().y * scale + dy,
483 }
484 else
485 {
486 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
487 -aFootprint->GetPosition().y * scale + dy,
489 }
490
491 comp->SetPlacement( IDF3::IDF_PLACEMENT::PS_ECAD );
492
493 aIDFBoard.AddComponent( comp );
494 }
495 else
496 {
497 double refX, refY, refA;
498 IDF3::IDF_LAYER side;
499
500 if( ! comp->GetPosition( refX, refY, refA, side ) )
501 {
502 // place the item
503 if( top )
504 {
505 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
506 -aFootprint->GetPosition().y * scale + dy,
508 }
509 else
510 {
511 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
512 -aFootprint->GetPosition().y * scale + dy,
514 }
515
516 comp->SetPlacement( IDF3::IDF_PLACEMENT::PS_ECAD );
517
518 }
519 else
520 {
521 // check that the retrieved component matches this one
522 refX = refX - ( aFootprint->GetPosition().x * scale + dx );
523 refY = refY - ( -aFootprint->GetPosition().y * scale + dy );
524 refA = refA - rotz;
525 refA *= refA;
526 refX *= refX;
527 refY *= refY;
528 refX += refY;
529
530 // conditions: same side, X,Y coordinates within 10 microns,
531 // angle within 0.01 degree
532 if( ( top && side == IDF3::IDF_LAYER::LYR_BOTTOM ) || ( !top && side == IDF3::IDF_LAYER::LYR_TOP )
533 || ( refA > 0.0001 ) || ( refX > 0.0001 ) )
534 {
535 if( m_reporter )
536 {
537 m_reporter->Report(
538 wxString::Format( "Error exporting footprint %s: duplicate reference designator",
539 aFootprint->GetReference() ),
541 }
542
543 return false;
544 }
545 }
546 }
547
548 // create the local data ...
549 IDF3_COMP_OUTLINE_DATA* data = new IDF3_COMP_OUTLINE_DATA( comp, outline );
550
551 data->SetOffsets( locx, locy, locz, lrot );
552 comp->AddOutlineData( data );
553 ++sM;
554 }
555
556 if( comp && m_reporter )
557 {
558 m_reporter->Report( wxString::Format( _( "Exported IDF model for footprint %s" ), aFootprint->GetReference() ),
560 }
561
562 return comp != nullptr;
563}
564
565
567 const EXTRUDED_3D_BODY& aBody ) const
568{
569 SHAPE_POLY_SET outline;
570
571 if( !GetExtrusionOutline( aFootprint, outline ) || outline.OutlineCount() < 1 )
572 {
573 if( m_reporter )
574 {
575 m_reporter->Report( wxString::Format( _( "Could not generate extruded body for %s" ),
576 aFootprint->GetReference() ),
578 }
579
580 return nullptr;
581 }
582
583 ApplyExtrusionTransform( outline, &aBody, VECTOR2D() );
584 outline.Move( -aFootprint->GetPosition() );
585 outline.Rotate( -aFootprint->GetOrientation() );
586 outline.Simplify();
587
588 double scale = m_settings->m_units == IDF_SETTINGS::UNITS::MILS ? pcbIUScale.MILS_PER_IU : pcbIUScale.MM_PER_IU;
589
590 SHAPE_LINE_CHAIN chain = outline.COutline( 0 );
591
592 if( chain.PointCount() < 3 )
593 {
594 if( m_reporter )
595 {
596 m_reporter->Report( wxString::Format( _( "Could not generate extruded body for %s" ),
597 aFootprint->GetReference() ),
599 }
600
601 return nullptr;
602 }
603
604 // Specify counter-clockwise: maybe not necessary for component outlines per the spec, but seems safe?
605 chain = chain.Reverse();
606
607 std::list<IDF_SEGMENT*> lines;
608
609 for( int ii = 0; ii < chain.PointCount(); ++ii )
610 {
611 VECTOR2I start = chain.CPoint( ii );
612 VECTOR2I end = chain.CPoint( ( ii + 1 ) % chain.PointCount() );
613
614 if( start == end )
615 continue;
616
617 IDF_POINT sp( start.x * scale, -start.y * scale );
618 IDF_POINT ep( end.x * scale, -end.y * scale );
619
620 lines.push_back( new IDF_SEGMENT( sp, ep ) );
621 }
622
623 auto cleanup =
624 [&lines]()
625 {
626 while( !lines.empty() )
627 {
628 delete lines.front();
629 lines.pop_front();
630 }
631 };
632
633 const PCB_FIELD* field = aFootprint->GetField( m_settings->m_partNumberField );
634
635 if( !field )
636 field = &aFootprint->Value();
637
638 IDF3_COMP_OUTLINE* libOutline = aIDFBoard.GetComponentOutline( aFootprint->GetFPID().Format(),
639 std::string( field->GetShownText( RESOLVED ) ) );
640
641 if( !libOutline )
642 {
643 if( m_reporter )
644 {
645 m_reporter->Report( wxString::Format( _( "Could not generate extruded body for %s" ),
646 aFootprint->GetReference() ),
648 }
649
650 cleanup();
651 return nullptr;
652 }
653
654 if( libOutline->OutlinesSize() == 0 )
655 {
656 IDF_OUTLINE* idfOutline = new IDF_OUTLINE;
657 IDF3::GetOutline( lines, *idfOutline );
658
659 if( idfOutline->empty() )
660 {
661 delete idfOutline;
662 cleanup();
663 return nullptr;
664 }
665
666 IDF3::COMP_TYPE compType =
667 ( aFootprint->GetAttributes() & FP_THROUGH_HOLE || aFootprint->GetAttributes() & FP_SMD )
670
671 libOutline->SetComponentClass( compType );
674
675 double height = std::max( 0.0, aBody.m_height * aBody.m_scale.z * scale );
676
677 libOutline->SetThickness( height );
678
679 if( !libOutline->AddOutline( idfOutline ) )
680 {
681 delete idfOutline;
682
683 if( m_reporter )
684 {
685 m_reporter->Report( wxString::Format( _( "Could not generate extruded body for %s" ),
686 aFootprint->GetReference() ),
688 }
689
690 cleanup();
691 return nullptr;
692 }
693 }
694 else
695 {
696 // The outline is shared with another footprint; reuse its geometry
697 }
698
699 return libOutline;
700}
701
702
704{
705 PROJECT* project = m_board->GetProject();
707 wxString libraryName = aFootprint->GetFPID().GetLibNickname();
708 wxString footprintBasePath = wxEmptyString;
709
710 if( !cache || !project )
711 return 0;
712
713 if( std::optional<LIBRARY_TABLE_ROW*> r = PROJECT_PCB::FootprintLibAdapter( project )->GetRow( libraryName ); r )
714 footprintBasePath = LIBRARY_MANAGER::GetFullURI( *r, true );
715
716 int height = 0;
717
718 for( const FP_3DMODEL& fpModel : aFootprint->Models() )
719 {
720 if( !fpModel.m_Show || fpModel.m_Filename.empty() )
721 continue;
722
723 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
724 embeddedFilesStack.push_back( aFootprint->GetEmbeddedFiles() );
725 embeddedFilesStack.push_back( m_board->GetEmbeddedFiles() );
726
727 wxString modelPath = m_resolver->ResolvePath( fpModel.m_Filename, footprintBasePath,
728 std::move( embeddedFilesStack ) );
729
730 if( modelPath.empty() )
731 continue;
732
733 const S3DMODEL* model = cache->GetModel( modelPath, footprintBasePath, {} );
734
735 if( !model )
736 continue;
737
738 height = std::max( height, pcbIUScale.mmToIU( getModelHeight( *model, fpModel.m_Rotation,
739 fpModel.m_Scale ).value_or( 0 ) ) );
740 }
741
742 return height;
743}
744
745
751void IDF_EXPORTER::exportFootprint( FOOTPRINT* aFootprint, IDF3_BOARD& aIDFBoard ) const
752{
753 wxCHECK( m_board && m_resolver && m_settings, /* void */ );
754
755 // Reference Designator
756 std::string crefdes = TO_UTF8( aFootprint->Reference().GetShownText( RESOLVED ) );
757
758 if( crefdes.empty() || !crefdes.compare( "~" ) )
759 {
760 std::string cvalue = TO_UTF8( aFootprint->Value().GetShownText( RESOLVED ) );
761
762 // if both the RefDes and Value are empty or set to '~' the board owns the part,
763 // otherwise associated parts of the footprint must be marked NOREFDES.
764 if( cvalue.empty() || !cvalue.compare( "~" ) )
765 crefdes = "BOARD";
766 else
767 crefdes = "NOREFDES";
768 }
769
770 // Export pads
771 double drill, x, y;
772 double scale = aIDFBoard.GetUserScale();
773 IDF3::KEY_PLATING kplate;
774 std::string pintype;
775 std::string tstr;
776
777 double dx, dy;
778
779 aIDFBoard.GetUserOffset( dx, dy );
780
781 // Footprint Edge_Cuts graphics are board cutouts. IDF has no per-component cutout, so they are
782 // appended to the board outline section where any loop after the first is treated as a cutout.
783 std::list<IDF_SEGMENT*> cutoutLines;
784
785 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
786 {
787 if( item->Type() != PCB_SHAPE_T || item->GetLayer() != Edge_Cuts )
788 continue;
789
790 idf_append_shape( static_cast<PCB_SHAPE*>( item ), scale, dx, dy, cutoutLines );
791 }
792
793 // GetOutline() consumes at least one segment per call, so this terminates even on open loops.
794 while( !cutoutLines.empty() )
795 {
796 IDF_OUTLINE* cutout = new IDF_OUTLINE;
797 IDF3::GetOutline( cutoutLines, *cutout );
798
799 if( cutout->empty() )
800 {
801 delete cutout;
802 continue;
803 }
804
805 // ownership transfers only on success
806 if( !aIDFBoard.AddBoardOutline( cutout ) )
807 delete cutout;
808 }
809
810 for( auto pad : aFootprint->Pads() )
811 {
812 drill = (double) pad->GetDrillSize().x * scale;
813 x = pad->GetPosition().x * scale + dx;
814 y = -pad->GetPosition().y * scale + dy;
815
816 // Export the hole on the edge layer
817 if( drill > 0.0 )
818 {
819 // plating
820 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
822 else
823 kplate = IDF3::KEY_PLATING::PTH;
824
825 // hole type
826 tstr = TO_UTF8( pad->GetNumber() );
827
828 if( tstr.empty() || !tstr.compare( "0" ) || !tstr.compare( "~" )
829 || ( kplate == IDF3::KEY_PLATING::NPTH )
830 || ( pad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG ) )
831 pintype = "MTG";
832 else
833 pintype = "PIN";
834
835 // fields:
836 // 1. hole dia. : float
837 // 2. X coord : float
838 // 3. Y coord : float
839 // 4. plating : PTH | NPTH
840 // 5. Assoc. part : BOARD | NOREFDES | PANEL | {"refdes"}
841 // 6. type : PIN | VIA | MTG | TOOL | { "other" }
842 // 7. owner : MCAD | ECAD | UNOWNED
843 if( ( pad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
844 && ( pad->GetDrillSize().x != pad->GetDrillSize().y ) )
845 {
846 // NOTE: IDF does not have direct support for slots;
847 // slots are implemented as a board cutout and we
848 // cannot represent plating or reference designators
849
850 double dlength = pad->GetDrillSize().y * scale;
851
852 // NOTE: The orientation of footprints and pads have
853 // the opposite sense due to KiCad drawing on a
854 // screen with a LH coordinate system
855 double angle = pad->GetOrientation().AsDegrees();
856
857 // NOTE: Since this code assumes the scenario where
858 // GetDrillSize().y is the length but idf_parser.cpp
859 // assumes a length along the X axis, the orientation
860 // must be shifted +90 deg when GetDrillSize().y is
861 // the major axis.
862
863 if( dlength < drill )
864 {
865 std::swap( drill, dlength );
866 }
867 else
868 {
869 angle += 90.0;
870 }
871
872 // NOTE: KiCad measures a slot's length from end to end
873 // rather than between the centers of the arcs
874 dlength -= drill;
875
876 aIDFBoard.AddSlot( drill, dlength, angle, x, y );
877 }
878 else
879 {
880 IDF_DRILL_DATA *dp = new IDF_DRILL_DATA( drill, x, y, kplate, crefdes,
881 pintype, IDF3::KEY_OWNER::ECAD );
882
883 if( !aIDFBoard.AddDrill( dp ) )
884 {
885 delete dp;
886
887 if( m_reporter )
888 {
889 m_reporter->Report( wxString::Format( "Error exporting footprint %s: %s",
890 aFootprint->GetReference(),
891 _( "could not add drill for pad" ) ),
893 }
894 }
895 }
896 }
897 }
898
899 if( ( !(aFootprint->GetAttributes() & (FP_THROUGH_HOLE|FP_SMD)) ) && !m_settings->m_includeUnspecified )
900 return;
901
902 if( aFootprint->GetDNPForVariant( m_board->GetCurrentVariant() ) && !m_settings->m_includeDNP )
903 return;
904
905 int standoffHeight = 0;
906
907 // add any valid models to the library item list
908 if( !exportFootprintIdfModels( aFootprint, aIDFBoard ) )
909 {
910 // No explicit models found: use the existing extruded body, or generate one
911 IDF3_COMP_OUTLINE* libOutline = nullptr;
912 EXTRUDED_3D_BODY generatedBody;
913 EXTRUDED_3D_BODY* body = nullptr;
914
915 if( EXTRUDED_3D_BODY* extruded = aFootprint->GetExtrudedBody() )
916 {
917 if( extruded->m_height <= 0 )
918 return;
919
920 standoffHeight = extruded->m_standoff;
921 body = extruded;
922 }
923
924 if( !body )
925 {
926 int height = getMaxModelHeight( aFootprint );
927
928 if( height == 0 )
929 return;
930
931 generatedBody.m_height = height;
932 body = &generatedBody;
933 }
934
935 libOutline = createOutlineFromExtrudedBody( aFootprint, aIDFBoard, *body );
936
937 if( libOutline )
938 {
939 std::string refdes = TO_UTF8( aFootprint->Reference().GetShownText( RESOLVED ) );
940
941 if( refdes.empty() || !refdes.compare( "~" ) )
942 refdes = aIDFBoard.GetNewRefDes();
943
944 IDF3_COMPONENT* comp = aIDFBoard.FindComponent( refdes );
945 double rotz = aFootprint->GetOrientation().AsDegrees();
946 bool top = ( aFootprint->GetLayer() != B_Cu );
947
948 if( comp == nullptr )
949 {
950 comp = new IDF3_COMPONENT( &aIDFBoard );
951 comp->SetRefDes( refdes );
952 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
953 -aFootprint->GetPosition().y * scale + dy,
955 comp->SetPlacement( IDF3::IDF_PLACEMENT::PS_ECAD );
956 aIDFBoard.AddComponent( comp );
957 }
958 else
959 {
960 double refX, refY, refA;
961 IDF3::IDF_LAYER side;
962
963 if( !comp->GetPosition( refX, refY, refA, side ) )
964 {
965 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
966 -aFootprint->GetPosition().y * scale + dy,
968 comp->SetPlacement( IDF3::IDF_PLACEMENT::PS_ECAD );
969 }
970 else
971 {
972 // check that the retrieved component matches this one
973 refX = refX - ( aFootprint->GetPosition().x * scale + dx );
974 refY = refY - ( -aFootprint->GetPosition().y * scale + dy );
975 refA = refA - rotz;
976 refA *= refA;
977 refX *= refX;
978 refY *= refY;
979 refX += refY;
980
981 // conditions: same side, X,Y coordinates within 10 microns,
982 // angle within 0.01 degree
983 if( ( top && side == IDF3::IDF_LAYER::LYR_BOTTOM ) || ( !top && side == IDF3::IDF_LAYER::LYR_TOP )
984 || ( refA > 0.0001 ) || ( refX > 0.0001 ) )
985 {
986 comp->GetPosition( refX, refY, refA, side );
987
988 if( m_reporter )
989 {
990 m_reporter->Report(
991 wxString::Format( "Error exporting footprint %s: duplicate reference designator",
992 aFootprint->GetReference() ),
994 }
995
996 return;
997 }
998 }
999 }
1000
1001 double unitScale = m_settings->m_units == IDF_SETTINGS::UNITS::MILS ? pcbIUScale.MILS_PER_IU
1002 : pcbIUScale.MM_PER_IU;
1003
1004 IDF3_COMP_OUTLINE_DATA* data = new IDF3_COMP_OUTLINE_DATA( comp, libOutline );
1005 data->SetOffsets( 0.0, 0.0, standoffHeight * unitScale, 0.0 );
1006 comp->AddOutlineData( data );
1007
1008 if( m_reporter )
1009 {
1010 m_reporter->Report( wxString::Format( _( "Exported extruded body for footprint %s" ),
1011 aFootprint->GetReference() ),
1013 }
1014 }
1015 }
1016}
1017
1018
1020{
1021 VECTOR2D origin;
1022 wxCHECK( m_settings && m_board, origin );
1023
1024 switch( m_settings->m_originMode )
1025 {
1026 default:
1028 {
1029 BOX2I bbox = m_board->GetBoardEdgesBoundingBox();
1030 origin = bbox.Centre() * pcbIUScale.MM_PER_IU;
1031 break;
1032 }
1033
1035 origin = m_board->GetDesignSettings().GetGridOrigin() * pcbIUScale.MM_PER_IU;
1036 break;
1037
1039 origin = m_board->GetDesignSettings().GetAuxOrigin() * pcbIUScale.MM_PER_IU;
1040 break;
1041
1043 {
1044 double scale = m_settings->m_units == IDF_SETTINGS::UNITS::MM ? pcbIUScale.MM_PER_IU : pcbIUScale.MILS_PER_IU;
1045 origin = m_settings->m_userOrigin *scale;
1046 break;
1047 }
1048 }
1049
1050 return origin;
1051}
1052
1053
1054bool IDF_EXPORTER::Export( const wxString& aFullFileName ) const
1055{
1056 wxCHECK( m_board, false );
1057 wxCHECK( m_resolver, false );
1058 wxCHECK( m_settings, false );
1059
1061
1062 // Switch the locale to standard C (needed to print floating point numbers)
1063 LOCALE_IO toggle;
1064
1065 bool ok = true;
1066 double scale = pcbIUScale.MM_PER_IU; // we must scale internal units to mm for IDF
1067 IDF3::IDF_UNIT idfUnit;
1068
1069 if( m_settings->m_units == IDF_SETTINGS::UNITS::MILS )
1070 {
1071 idfUnit = IDF3::IDF_UNIT::UNIT_THOU;
1072 idfBoard.SetUserPrecision( 1 );
1073 }
1074 else
1075 {
1076 idfUnit = IDF3::IDF_UNIT::UNIT_MM;
1077 idfBoard.SetUserPrecision( 5 );
1078 }
1079
1080 wxFileName brdName = m_board->GetFileName();
1081
1082 idfBoard.SetUserScale( scale );
1083 idfBoard.SetBoardThickness( m_board->GetDesignSettings().GetBoardThickness() * scale );
1084 idfBoard.SetBoardName( TO_UTF8( brdName.GetFullName() ) );
1085 idfBoard.SetBoardVersion( 0 );
1086 idfBoard.SetLibraryVersion( 0 );
1087
1088 std::ostringstream ostr;
1089 ostr << "KiCad " << TO_UTF8( GetBuildVersion() );
1090 idfBoard.SetIDFSource( ostr.str() );
1091
1092 try
1093 {
1094 // set up the board reference point
1095 VECTOR2D origin = getOrigin();
1096 idfBoard.SetUserOffset( -origin.x, origin.y );
1097
1098 if( m_reporter )
1099 m_reporter->Report( _( "Exporting board shape" ), RPT_SEVERITY_INFO );
1100
1101 // Export the board outline
1102 idf_export_outline( m_board, idfBoard );
1103
1104 // Output the drill holes and footprint (library) data.
1105 for( FOOTPRINT* footprint : m_board->Footprints() )
1106 exportFootprint( footprint, idfBoard );
1107
1108 if( !idfBoard.WriteFile( aFullFileName, idfUnit, m_reporter ) )
1109 ok = false;
1110 }
1111 catch( const IO_ERROR& ioe )
1112 {
1113 if( m_reporter && !idfBoard.GetError().empty() )
1114 m_reporter->Report( ioe.What(), RPT_SEVERITY_ERROR );
1115
1116 ok = false;
1117 }
1118 catch( const std::exception& e )
1119 {
1120 if( m_reporter && !idfBoard.GetError().empty() )
1121 m_reporter->Report( From_UTF8( e.what() ), RPT_SEVERITY_ERROR );
1122
1123 ok = false;
1124 }
1125
1126 if( ok )
1127 {
1128 wxFileName brdname( aFullFileName );
1129 wxFileName libname( aFullFileName );
1130
1131 brdname.SetExt( FILEEXT::IdfV3BoardFileExtension );
1132 libname.SetExt( FILEEXT::IdfV3LibraryFileExtension );
1133
1134 m_settings->AddOutput( brdname.GetFullPath() );
1135 m_settings->AddOutput( libname.GetFullPath() );
1136
1137 if( m_reporter )
1138 {
1139 m_reporter->Report( wxString::Format( _( "Wrote IDF board file to %s" ), brdname.GetFullPath() ),
1141 m_reporter->Report( wxString::Format( _( "Wrote IDF library file to %s" ), libname.GetFullPath() ),
1143 }
1144 }
1145
1146 return ok;
1147}
glm::mat4 CalcModelMatrix(const SFVEC3F &aOffset, const SFVEC3F &aRotation, const SFVEC3F &aScale)
Build the model-to-footprint transform used by rendering and picking.
Definition 3d_math.cpp:34
Defines math related functions.
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
bool GetExtrusionOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aOutline, PCB_LAYER_ID aLayerOverride)
Get the extrusion outline polygon for a footprint in board coordinates.
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
wxString GetBuildVersion()
Get the full KiCad version string.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
bool AddOutline(IDF_OUTLINE *aOutline)
Add the specified outline to this object.
virtual bool SetThickness(double aThickness)
Set the thickness or height of the outline (mm).
size_t OutlinesSize(void)
virtual bool SetUnit(IDF3::IDF_UNIT aUnit)
Function SetUnit sets the native unit of the outline; except for component outlines this must be the ...
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:410
const BOX2I GetBoardEdgesBoundingBox() const
Return the board bounding box calculated using exclusively the board edges (graphics on Edge....
Definition board.h:1288
const DRAWINGS & Drawings() const
Definition board.h:466
constexpr Vec Centre() const
Definition box2.h:94
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr const SizeVec & GetSize() const
Definition box2.h:203
double AsDegrees() const
Definition eda_angle.h:115
EDA_ANGLE GetArcAngle() const
SHAPE_POLY_SET & GetPolyShape()
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:175
void RebuildBezierToSegmentsPointsList(int aMaxError)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition eda_shape.h:491
bool IsPolyShapeValid() const
VECTOR3D m_scale
Definition footprint.h:125
Provide an extensible class to resolve 3D model paths.
EDA_ANGLE GetOrientation() const
Definition footprint.h:439
const EXTRUDED_3D_BODY * GetExtrudedBody() const
Definition footprint.h:429
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:947
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
std::deque< PAD * > & Pads()
Definition footprint.h:405
int GetAttributes() const
Definition footprint.h:551
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:450
const LIB_ID & GetFPID() const
Definition footprint.h:474
PCB_FIELD & Reference()
Definition footprint.h:948
bool GetDNPForVariant(const wxString &aVariantName) const
Get the DNP status for a specific variant.
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:425
const wxString & GetReference() const
Definition footprint.h:909
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition footprint.h:1397
VECTOR2I GetPosition() const override
Definition footprint.h:436
DRAWINGS & GraphicalItems()
Definition footprint.h:408
void GetUserOffset(double &aXoff, double &aYoff)
bool WriteFile(const wxString &aFullFileName, IDF3::IDF_UNIT aUnits, REPORTER *aReporter=nullptr)
bool SetBoardThickness(double aBoardThickness)
bool SetLibraryVersion(int aVersion)
IDF3_COMP_OUTLINE * GetComponentOutline(const wxString &aFullFileName)
const std::string & GetNewRefDes(void)
double GetUserScale(void) const
Definition idf_parser.h:458
void SetUserOffset(double aXoff, double aYoff)
const std::string & GetError(void)
Definition idf_parser.h:580
void SetIDFSource(const std::string &aIDFSource)
Definition idf_parser.h:446
IDF3_COMPONENT * FindComponent(const std::string &aRefDes)
IDF_DRILL_DATA * AddDrill(IDF_DRILL_DATA *aDrilledHole)
bool AddComponent(IDF3_COMPONENT *aComponent)
bool SetUserScale(double aScaleFactor)
void SetBoardName(const std::string &aBoardName)
Definition idf_parser.h:436
bool SetUserPrecision(int aPrecision)
bool AddSlot(double aWidth, double aLength, double aOrientation, double aX, double aY)
bool SetBoardVersion(int aVersion)
bool AddBoardOutline(IDF_OUTLINE *aOutline)
bool SetOffsets(double aXoff, double aYoff, double aZoff, double aAngleOff)
Set the position and orientation of this outline item in relation to its parent.
A component's outline as stored in an IDF library file.
bool SetComponentClass(IDF3::COMP_TYPE aCompClass)
Set the type of component outline (.ELECTRICAL or .MECHANICAL).
A drilled hole.
Definition idf_common.h:312
JOB_EXPORT_PCB_IDF * m_settings
Definition export_idf.h:73
VECTOR2D getOrigin() const
IDF3_COMP_OUTLINE * createOutlineFromExtrudedBody(const FOOTPRINT *aFootprint, IDF3_BOARD &aIDFBoard, const EXTRUDED_3D_BODY &aBody) const
Generates an IDF component outline from a footprint extruded 3D body, if possible.
FILENAME_RESOLVER * m_resolver
Definition export_idf.h:72
bool Export(const wxString &aFullFileName) const
Generate IDFv3 compliant board (*.emn) and library (*.emp) files for aPcb.
void exportFootprint(FOOTPRINT *aFootprint, IDF3_BOARD &aIDFBoard) const
Exports the given footprint to an in-progress IDF file.
BOARD * m_board
Definition export_idf.h:71
int getMaxModelHeight(FOOTPRINT *aFootprint) const
Returns the largest extent in Z of the footprint's visible 3D models, in IU.
bool exportFootprintIdfModels(FOOTPRINT *aFootprint, IDF3_BOARD &aIDFBoard) const
Exports any explicit IDF models attached to a footprint to an in-progress IDF file.
IDF_EXPORTER(BOARD *aBoard, FILENAME_RESOLVER *aResolver, JOB_EXPORT_PCB_IDF *aSettings, REPORTER *aReporter=nullptr)
REPORTER * m_reporter
Definition export_idf.h:74
std::unique_ptr< JOB_EXPORT_PCB_IDF > m_defaultSettings
Definition export_idf.h:76
A segment and winding information for an IDF outline.
Definition idf_common.h:551
bool empty()
Definition idf_common.h:591
void Clear()
Clear the internal list of outline segments.
Definition idf_common.h:569
bool push(IDF_SEGMENT *item)
Add a segment to the internal segment list.
A point as used by the various IDF related classes.
Definition idf_common.h:426
double x
Definition idf_common.h:457
double y
Definition idf_common.h:458
A segment as used in IDFv3 outlines.
Definition idf_common.h:468
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
UTF8 Format() const
Definition lib_id.cpp:132
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
Return the string actually shown after processing of the base text.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:78
static S3D_CACHE * Get3DCacheManager(PROJECT *aProject, bool updateProjDir=false)
Return a pointer to an instance of the 3D cache manager.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
Container for project specific data.
Definition project.h:63
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
Cache for storing the 3D shapes.
Definition 3d_cache.h:53
S3DMODEL * GetModel(const wxString &aModelFileName, const wxString &aBasePath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
Definition 3d_cache.cpp:588
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int OutlineCount() const
Return the number of outlines in the set.
void Move(const VECTOR2I &aVector) override
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
@ RESOLVED
Definition common.h:95
#define _(s)
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
static void idf_export_outline(BOARD *aPcb, IDF3_BOARD &aIDFBoard)
Retrieve line segment information from the edge layer and compiles the data into a form which can be ...
#define LINE_WIDTH
static void idf_append_shape(PCB_SHAPE *aGraphic, double aScale, double aOffX, double aOffY, std::list< IDF_SEGMENT * > &aLines)
Convert a single Edge_Cuts graphic into IDF segments and append them to aLines.
static std::optional< double > getModelHeight(const S3DMODEL &aModel, const VECTOR3D &aRotation, const VECTOR3D &aScale)
Returns the largest board Z value, in mm, of the given model.
@ FP_SMD
Definition footprint.h:87
@ FP_THROUGH_HOLE
Definition footprint.h:86
static const std::string IdfV3LibraryFileExtension
static const std::string IdfV3BoardFileExtension
static wxString From_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition idf_helpers.h:44
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Cu
Definition layer_ids.h:61
This file contains miscellaneous commonly used macros and functions.
KEY_PLATING
The plating condition of a hole.
Definition idf_common.h:107
IDF_UNIT
The native unit of the board and of component outlines.
Definition idf_common.h:177
IDF_LAYER
The various IDF layer classes and groupings.
Definition idf_common.h:137
void GetOutline(std::list< IDF_SEGMENT * > &aLines, IDF_OUTLINE &aOutline)
Take contiguous elements from 'aLines' and stuffs them into 'aOutline'; elements put into the outline...
COMP_TYPE
Whether a component is a mechanical or electrical part.
Definition idf_common.h:167
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
const int scale
Store the a model based on meshes and materials.
Definition c3dmodel.h:111
unsigned int m_MeshesSize
Number of meshes in the array.
Definition c3dmodel.h:112
SMESH * m_Meshes
The meshes list of this model.
Definition c3dmodel.h:113
Per-vertex normal/color/texcoors structure.
Definition c3dmodel.h:77
unsigned int m_VertexSize
Number of vertex in the arrays.
Definition c3dmodel.h:78
SFVEC3F * m_Positions
Vertex position array.
Definition c3dmodel.h:79
KIBIS top(path, &reporter)
KIBIS_MODEL * model
KIBIS_COMPONENT * comp
const SHAPE_LINE_CHAIN chain
VECTOR2I end
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
VECTOR3< double > VECTOR3D
Definition vector3.h:230
glm::vec3 SFVEC3F
Definition xv3d_types.h:40