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