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 <locale_io.h>
24#include <macros.h>
25#include <pcb_edit_frame.h>
26#include <board.h>
28#include <footprint.h>
30#include <idf_parser.h>
31#include <pad.h>
32#include <pcb_shape.h>
33#include <build_version.h>
34#include <project_pcb.h>
35#include <wx/msgdlg.h>
36#include "project.h"
37#include "3d_cache/3d_cache.h"
38#include "filename_resolver.h"
39#include "export_idf.h"
40
41
42#include <base_units.h> // to define pcbIUScale.FromMillimeter(x)
43
44
45// assumed default graphical line thickness: == 0.1mm
46#define LINE_WIDTH (pcbIUScale.mmToIU( 0.1 ))
47
48
50
51
58static void idf_append_shape( PCB_SHAPE* aGraphic, double aScale, double aOffX, double aOffY,
59 std::list<IDF_SEGMENT*>& aLines )
60{
61 IDF_POINT sp, ep; // start and end points from KiCad item
62
63 switch( aGraphic->GetShape() )
64 {
66 {
67 if( aGraphic->GetStart() == aGraphic->GetEnd() )
68 break;
69
70 sp.x = aGraphic->GetStart().x * aScale + aOffX;
71 sp.y = -aGraphic->GetStart().y * aScale + aOffY;
72 ep.x = aGraphic->GetEnd().x * aScale + aOffX;
73 ep.y = -aGraphic->GetEnd().y * aScale + aOffY;
74 aLines.push_back( new IDF_SEGMENT( sp, ep ) );
75
76 break;
77 }
78
80 {
81 if( aGraphic->GetStart() == aGraphic->GetEnd() )
82 break;
83
84 // IDF Y is up-positive, so mirror KiCad's down-positive Y like the other shapes do
85 double top = -aGraphic->GetStart().y * aScale + aOffY;
86 double left = aGraphic->GetStart().x * aScale + aOffX;
87 double bottom = -aGraphic->GetEnd().y * aScale + aOffY;
88 double right = aGraphic->GetEnd().x * aScale + aOffX;
89
90 IDF_POINT corners[4];
91 corners[0] = IDF_POINT( left, top );
92 corners[1] = IDF_POINT( right, top );
93 corners[2] = IDF_POINT( right, bottom );
94 corners[3] = IDF_POINT( left, bottom );
95
96 aLines.push_back( new IDF_SEGMENT( corners[0], corners[1] ) );
97 aLines.push_back( new IDF_SEGMENT( corners[1], corners[2] ) );
98 aLines.push_back( new IDF_SEGMENT( corners[2], corners[3] ) );
99 aLines.push_back( new IDF_SEGMENT( corners[3], corners[0] ) );
100 break;
101 }
102
103 case SHAPE_T::ARC:
104 {
105 if( aGraphic->GetCenter() == aGraphic->GetStart() )
106 break;
107
108 sp.x = aGraphic->GetCenter().x * aScale + aOffX;
109 sp.y = -aGraphic->GetCenter().y * aScale + aOffY;
110 ep.x = aGraphic->GetStart().x * aScale + aOffX;
111 ep.y = -aGraphic->GetStart().y * aScale + aOffY;
112 aLines.push_back( new IDF_SEGMENT( sp, ep, -aGraphic->GetArcAngle().AsDegrees(), true ) );
113
114 break;
115 }
116
117 case SHAPE_T::CIRCLE:
118 {
119 if( aGraphic->GetRadius() == 0 )
120 break;
121
122 sp.x = aGraphic->GetCenter().x * aScale + aOffX;
123 sp.y = -aGraphic->GetCenter().y * aScale + aOffY;
124 ep.x = sp.x - aGraphic->GetRadius() * aScale;
125 ep.y = sp.y;
126
127 // Circles must always have an angle of +360 deg. to appease
128 // quirky MCAD implementations of IDF.
129 aLines.push_back( new IDF_SEGMENT( sp, ep, 360.0, true ) );
130
131 break;
132 }
133
134 case SHAPE_T::POLY:
135 {
136 if( !aGraphic->IsPolyShapeValid() )
137 break;
138
139 // Holes within an outline have no IDF representation; each outline is its own loop
140 const SHAPE_POLY_SET& polySet = aGraphic->GetPolyShape();
141
142 for( int ii = 0; ii < polySet.OutlineCount(); ++ii )
143 {
144 const SHAPE_LINE_CHAIN& chain = polySet.COutline( ii );
145
146 for( int jj = 0; jj < chain.PointCount(); ++jj )
147 {
148 const VECTOR2I& start = chain.CPoint( jj );
149 const VECTOR2I& end = chain.CPoint( ( jj + 1 ) % chain.PointCount() );
150
151 if( start == end )
152 continue;
153
154 sp.x = start.x * aScale + aOffX;
155 sp.y = -start.y * aScale + aOffY;
156 ep.x = end.x * aScale + aOffX;
157 ep.y = -end.y * aScale + aOffY;
158 aLines.push_back( new IDF_SEGMENT( sp, ep ) );
159 }
160 }
161
162 break;
163 }
164
165 case SHAPE_T::BEZIER:
166 {
168
169 const std::vector<VECTOR2I>& pts = aGraphic->GetBezierPoints();
170
171 for( size_t ii = 1; ii < pts.size(); ++ii )
172 {
173 if( pts[ii - 1] == pts[ii] )
174 continue;
175
176 sp.x = pts[ii - 1].x * aScale + aOffX;
177 sp.y = -pts[ii - 1].y * aScale + aOffY;
178 ep.x = pts[ii].x * aScale + aOffX;
179 ep.y = -pts[ii].y * aScale + aOffY;
180 aLines.push_back( new IDF_SEGMENT( sp, ep ) );
181 }
182
183 break;
184 }
185
186 default:
187 break;
188 }
189}
190
191
196static void idf_export_outline( BOARD* aPcb, IDF3_BOARD& aIDFBoard )
197{
198 double scale = aIDFBoard.GetUserScale();
199 std::list< IDF_SEGMENT* > lines; // IDF intermediate form of KiCad graphical item
200 IDF_OUTLINE* outline = nullptr; // graphical items forming an outline or cutout
201
202 // Footprint cutouts are emitted separately by idf_export_footprint(); like board cutouts they
203 // belong in the board outline section rather than the Other Outline section.
204
205 double offX, offY;
206 aIDFBoard.GetUserOffset( offX, offY );
207
208 // Retrieve segments and arcs from the board
209 for( BOARD_ITEM* item : aPcb->Drawings() )
210 {
211 if( item->Type() != PCB_SHAPE_T || item->GetLayer() != Edge_Cuts )
212 continue;
213
214 idf_append_shape( static_cast<PCB_SHAPE*>( item ), scale, offX, offY, lines );
215 }
216
217 // if there is no outline then use the bounding box
218 if( lines.empty() )
219 {
220 goto UseBoundingBox;
221 }
222
223 // get the board outline and write it out
224 // note: we do not use a try/catch block here since we intend
225 // to simply ignore unclosed loops and continue processing
226 // until we're out of segments to process
227 outline = new IDF_OUTLINE;
228 IDF3::GetOutline( lines, *outline );
229
230 if( outline->empty() )
231 goto UseBoundingBox;
232
233 aIDFBoard.AddBoardOutline( outline );
234 outline = nullptr;
235
236 // get all cutouts and write them out
237 while( !lines.empty() )
238 {
239 if( !outline )
240 outline = new IDF_OUTLINE;
241
242 IDF3::GetOutline( lines, *outline );
243
244 if( outline->empty() )
245 {
246 outline->Clear();
247 continue;
248 }
249
250 aIDFBoard.AddBoardOutline( outline );
251 outline = nullptr;
252 }
253
254 // an open loop on the final iteration leaves an allocated but empty outline behind
255 delete outline;
256
257 return;
258
259UseBoundingBox:
260
261 // clean up if necessary
262 while( !lines.empty() )
263 {
264 delete lines.front();
265 lines.pop_front();
266 }
267
268 if( outline )
269 outline->Clear();
270 else
271 outline = new IDF_OUTLINE;
272
273 // Fetch a rectangular bounding box for the board; there is always some uncertainty in the
274 // board dimensions computed via ComputeBoundingBox() since this depends on the individual
275 // footprint entities.
276 BOX2I bbbox = aPcb->GetBoardEdgesBoundingBox();
277
278 // convert to mm and compensate for an assumed LINE_WIDTH line thickness
279 double x = ( bbbox.GetOrigin().x + LINE_WIDTH / 2 ) * scale + offX;
280 double y = ( bbbox.GetOrigin().y + LINE_WIDTH / 2 ) * scale + offY;
281 double dx = ( bbbox.GetSize().x - LINE_WIDTH ) * scale;
282 double dy = ( bbbox.GetSize().y - LINE_WIDTH ) * scale;
283
284 double px[4], py[4];
285 px[0] = x;
286 py[0] = y;
287
288 px[1] = x;
289 py[1] = y + dy;
290
291 px[2] = x + dx;
292 py[2] = y + dy;
293
294 px[3] = x + dx;
295 py[3] = y;
296
297 IDF_POINT p1, p2;
298
299 p1.x = px[3];
300 p1.y = py[3];
301 p2.x = px[0];
302 p2.y = py[0];
303
304 outline->push( new IDF_SEGMENT( p1, p2 ) );
305
306 for( int i = 1; i < 4; ++i )
307 {
308 p1.x = px[i - 1];
309 p1.y = py[i - 1];
310 p2.x = px[i];
311 p2.y = py[i];
312
313 outline->push( new IDF_SEGMENT( p1, p2 ) );
314 }
315
316 aIDFBoard.AddBoardOutline( outline );
317}
318
319
325static void idf_export_footprint( BOARD* aPcb, FOOTPRINT* aFootprint, IDF3_BOARD& aIDFBoard,
326 bool aIncludeUnspecified, bool aIncludeDNP )
327{
328 // Reference Designator
329 std::string crefdes = TO_UTF8( aFootprint->Reference().GetShownText( false ) );
330
331 wxString libraryName = aFootprint->GetFPID().GetLibNickname();
332 wxString footprintBasePath = wxEmptyString;
333
334 if( aPcb->GetProject() )
335 {
336 std::optional<LIBRARY_TABLE_ROW*> fpRow =
337 PROJECT_PCB::FootprintLibAdapter( aPcb->GetProject() )->GetRow( libraryName );
338 if( fpRow )
339 footprintBasePath = LIBRARY_MANAGER::GetFullURI( *fpRow, true );
340 }
341
342 if( crefdes.empty() || !crefdes.compare( "~" ) )
343 {
344 std::string cvalue = TO_UTF8( aFootprint->Value().GetShownText( false ) );
345
346 // if both the RefDes and Value are empty or set to '~' the board owns the part,
347 // otherwise associated parts of the footprint must be marked NOREFDES.
348 if( cvalue.empty() || !cvalue.compare( "~" ) )
349 crefdes = "BOARD";
350 else
351 crefdes = "NOREFDES";
352 }
353
354 // Export pads
355 double drill, x, y;
356 double scale = aIDFBoard.GetUserScale();
357 IDF3::KEY_PLATING kplate;
358 std::string pintype;
359 std::string tstr;
360
361 double dx, dy;
362
363 aIDFBoard.GetUserOffset( dx, dy );
364
365 // Footprint Edge_Cuts graphics are board cutouts. IDF has no per-component cutout, so they are
366 // appended to the board outline section where any loop after the first is treated as a cutout.
367 std::list<IDF_SEGMENT*> cutoutLines;
368
369 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
370 {
371 if( item->Type() != PCB_SHAPE_T || item->GetLayer() != Edge_Cuts )
372 continue;
373
374 idf_append_shape( static_cast<PCB_SHAPE*>( item ), scale, dx, dy, cutoutLines );
375 }
376
377 // GetOutline() consumes at least one segment per call, so this terminates even on open loops.
378 while( !cutoutLines.empty() )
379 {
380 IDF_OUTLINE* cutout = new IDF_OUTLINE;
381 IDF3::GetOutline( cutoutLines, *cutout );
382
383 if( cutout->empty() )
384 {
385 delete cutout;
386 continue;
387 }
388
389 // ownership transfers only on success
390 if( !aIDFBoard.AddBoardOutline( cutout ) )
391 delete cutout;
392 }
393
394 for( auto pad : aFootprint->Pads() )
395 {
396 drill = (double) pad->GetDrillSize().x * scale;
397 x = pad->GetPosition().x * scale + dx;
398 y = -pad->GetPosition().y * scale + dy;
399
400 // Export the hole on the edge layer
401 if( drill > 0.0 )
402 {
403 // plating
404 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
405 kplate = IDF3::NPTH;
406 else
407 kplate = IDF3::PTH;
408
409 // hole type
410 tstr = TO_UTF8( pad->GetNumber() );
411
412 if( tstr.empty() || !tstr.compare( "0" ) || !tstr.compare( "~" )
413 || ( kplate == IDF3::NPTH )
414 || ( pad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG ) )
415 pintype = "MTG";
416 else
417 pintype = "PIN";
418
419 // fields:
420 // 1. hole dia. : float
421 // 2. X coord : float
422 // 3. Y coord : float
423 // 4. plating : PTH | NPTH
424 // 5. Assoc. part : BOARD | NOREFDES | PANEL | {"refdes"}
425 // 6. type : PIN | VIA | MTG | TOOL | { "other" }
426 // 7. owner : MCAD | ECAD | UNOWNED
427 if( ( pad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
428 && ( pad->GetDrillSize().x != pad->GetDrillSize().y ) )
429 {
430 // NOTE: IDF does not have direct support for slots;
431 // slots are implemented as a board cutout and we
432 // cannot represent plating or reference designators
433
434 double dlength = pad->GetDrillSize().y * scale;
435
436 // NOTE: The orientation of footprints and pads have
437 // the opposite sense due to KiCad drawing on a
438 // screen with a LH coordinate system
439 double angle = pad->GetOrientation().AsDegrees();
440
441 // NOTE: Since this code assumes the scenario where
442 // GetDrillSize().y is the length but idf_parser.cpp
443 // assumes a length along the X axis, the orientation
444 // must be shifted +90 deg when GetDrillSize().y is
445 // the major axis.
446
447 if( dlength < drill )
448 {
449 std::swap( drill, dlength );
450 }
451 else
452 {
453 angle += 90.0;
454 }
455
456 // NOTE: KiCad measures a slot's length from end to end
457 // rather than between the centers of the arcs
458 dlength -= drill;
459
460 aIDFBoard.AddSlot( drill, dlength, angle, x, y );
461 }
462 else
463 {
464 IDF_DRILL_DATA *dp = new IDF_DRILL_DATA( drill, x, y, kplate, crefdes,
465 pintype, IDF3::ECAD );
466
467 if( !aIDFBoard.AddDrill( dp ) )
468 {
469 delete dp;
470
471 std::ostringstream ostr;
472 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__;
473 ostr << "(): could not add drill";
474
475 throw std::runtime_error( ostr.str() );
476 }
477 }
478 }
479 }
480
481 if( ( !(aFootprint->GetAttributes() & (FP_THROUGH_HOLE|FP_SMD)) ) && !aIncludeUnspecified )
482 return;
483
484 if( aFootprint->GetDNPForVariant( aPcb ? aPcb->GetCurrentVariant() : wxString() )
485 && !aIncludeDNP )
486 return;
487
488 // add any valid models to the library item list
489 std::string refdes;
490
491 IDF3_COMPONENT* comp = nullptr;
492
493 auto sM = aFootprint->Models().begin();
494 auto eM = aFootprint->Models().end();
495 wxFileName idfFile;
496 wxString idfExt;
497
498 while( sM != eM )
499 {
500 if( !sM->m_Show )
501 {
502 ++sM;
503 continue;
504 }
505
506 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
507 embeddedFilesStack.push_back( aFootprint->GetEmbeddedFiles() );
508 embeddedFilesStack.push_back( aPcb->GetEmbeddedFiles() );
509
510 idfFile.Assign( resolver->ResolvePath( sM->m_Filename, footprintBasePath, std::move( embeddedFilesStack ) ) );
511 idfExt = idfFile.GetExt();
512
513 if( idfExt.Cmp( wxT( "idf" ) ) && idfExt.Cmp( wxT( "IDF" ) ) )
514 {
515 ++sM;
516 continue;
517 }
518
519 if( refdes.empty() )
520 {
521 refdes = TO_UTF8( aFootprint->Reference().GetShownText( false ) );
522
523 // NOREFDES cannot be used or else the software gets confused
524 // when writing out the placement data due to conflicting
525 // placement and layer specifications; to work around this we
526 // create a (hopefully) unique refdes for our exported part.
527 if( refdes.empty() || !refdes.compare( "~" ) )
528 refdes = aIDFBoard.GetNewRefDes();
529 }
530
531 IDF3_COMP_OUTLINE* outline;
532
533 outline = aIDFBoard.GetComponentOutline( idfFile.GetFullPath() );
534
535 if( !outline )
536 throw( std::runtime_error( aIDFBoard.GetError() ) );
537
538 double rotz = aFootprint->GetOrientation().AsDegrees();
539 double locx = sM->m_Offset.x; // part offsets are in mm
540 double locy = sM->m_Offset.y;
541 double locz = sM->m_Offset.z;
542 double lrot = sM->m_Rotation.z;
543
544 bool top = ( aFootprint->GetLayer() == B_Cu ) ? false : true;
545
546 if( top )
547 {
548 locy = -locy;
549 RotatePoint( &locx, &locy, aFootprint->GetOrientation() );
550 locy = -locy;
551 }
552
553 if( !top )
554 {
555 lrot = -lrot;
556 RotatePoint( &locx, &locy, aFootprint->GetOrientation() );
557 locy = -locy;
558
559 rotz = 180.0 - rotz;
560
561 if( rotz >= 360.0 )
562 while( rotz >= 360.0 ) rotz -= 360.0;
563
564 if( rotz <= -360.0 )
565 while( rotz <= -360.0 ) rotz += 360.0;
566 }
567
568 if( comp == nullptr )
569 comp = aIDFBoard.FindComponent( refdes );
570
571 if( comp == nullptr )
572 {
573 comp = new IDF3_COMPONENT( &aIDFBoard );
574
575 if( comp == nullptr )
576 throw( std::runtime_error( aIDFBoard.GetError() ) );
577
578 comp->SetRefDes( refdes );
579
580 if( top )
581 {
582 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
583 -aFootprint->GetPosition().y * scale + dy,
584 rotz, IDF3::LYR_TOP );
585 }
586 else
587 {
588 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
589 -aFootprint->GetPosition().y * scale + dy,
590 rotz, IDF3::LYR_BOTTOM );
591 }
592
593 comp->SetPlacement( IDF3::PS_ECAD );
594
595 aIDFBoard.AddComponent( comp );
596 }
597 else
598 {
599 double refX, refY, refA;
600 IDF3::IDF_LAYER side;
601
602 if( ! comp->GetPosition( refX, refY, refA, side ) )
603 {
604 // place the item
605 if( top )
606 {
607 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
608 -aFootprint->GetPosition().y * scale + dy,
609 rotz, IDF3::LYR_TOP );
610 }
611 else
612 {
613 comp->SetPosition( aFootprint->GetPosition().x * scale + dx,
614 -aFootprint->GetPosition().y * scale + dy,
615 rotz, IDF3::LYR_BOTTOM );
616 }
617
618 comp->SetPlacement( IDF3::PS_ECAD );
619
620 }
621 else
622 {
623 // check that the retrieved component matches this one
624 refX = refX - ( aFootprint->GetPosition().x * scale + dx );
625 refY = refY - ( -aFootprint->GetPosition().y * scale + dy );
626 refA = refA - rotz;
627 refA *= refA;
628 refX *= refX;
629 refY *= refY;
630 refX += refY;
631
632 // conditions: same side, X,Y coordinates within 10 microns,
633 // angle within 0.01 degree
634 if( ( top && side == IDF3::LYR_BOTTOM ) || ( !top && side == IDF3::LYR_TOP )
635 || ( refA > 0.0001 ) || ( refX > 0.0001 ) )
636 {
637 comp->GetPosition( refX, refY, refA, side );
638
639 std::ostringstream ostr;
640 ostr << "* " << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
641 ostr << "* conflicting Reference Designator '" << refdes << "'\n";
642 ostr << "* X loc: " << ( aFootprint->GetPosition().x * scale + dx);
643 ostr << " vs. " << refX << "\n";
644 ostr << "* Y loc: " << ( -aFootprint->GetPosition().y * scale + dy);
645 ostr << " vs. " << refY << "\n";
646 ostr << "* angle: " << rotz;
647 ostr << " vs. " << refA << "\n";
648
649 if( top )
650 ostr << "* TOP vs. ";
651 else
652 ostr << "* BOTTOM vs. ";
653
654 if( side == IDF3::LYR_TOP )
655 ostr << "TOP";
656 else
657 ostr << "BOTTOM";
658
659 throw( std::runtime_error( ostr.str() ) );
660 }
661 }
662 }
663
664 // create the local data ...
665 IDF3_COMP_OUTLINE_DATA* data = new IDF3_COMP_OUTLINE_DATA( comp, outline );
666
667 data->SetOffsets( locx, locy, locz, lrot );
668 comp->AddOutlineData( data );
669 ++sM;
670 }
671}
672
673
681bool ExportBoardToIDF3( BOARD* aPcb, const wxString& aFullFileName, bool aUseThou, double aXRef,
682 double aYRef, bool aIncludeUnspecified, bool aIncludeDNP,
683 FILENAME_RESOLVER* aResolver, wxString* aErrorMsg )
684{
685 // idf_export_footprint dereferences the resolver for every 3D model, so a null one
686 // must fail up front rather than crash mid-export
687 wxCHECK( aResolver, false );
688
689 IDF3_BOARD idfBoard( IDF3::CAD_ELEC );
690
691 // Switch the locale to standard C (needed to print floating point numbers)
692 LOCALE_IO toggle;
693
694 resolver = aResolver;
695
696 bool ok = true;
697 double scale = pcbIUScale.MM_PER_IU; // we must scale internal units to mm for IDF
698 IDF3::IDF_UNIT idfUnit;
699
700 if( aUseThou )
701 {
702 idfUnit = IDF3::UNIT_THOU;
703 idfBoard.SetUserPrecision( 1 );
704 }
705 else
706 {
707 idfUnit = IDF3::UNIT_MM;
708 idfBoard.SetUserPrecision( 5 );
709 }
710
711 wxFileName brdName = aPcb->GetFileName();
712
713 idfBoard.SetUserScale( scale );
714 idfBoard.SetBoardThickness( aPcb->GetDesignSettings().GetBoardThickness() * scale );
715 idfBoard.SetBoardName( TO_UTF8( brdName.GetFullName() ) );
716 idfBoard.SetBoardVersion( 0 );
717 idfBoard.SetLibraryVersion( 0 );
718
719 std::ostringstream ostr;
720 ostr << "KiCad " << TO_UTF8( GetBuildVersion() );
721 idfBoard.SetIDFSource( ostr.str() );
722
723 try
724 {
725 // set up the board reference point
726 idfBoard.SetUserOffset( -aXRef, aYRef );
727
728 // Export the board outline
729 idf_export_outline( aPcb, idfBoard );
730
731 // Output the drill holes and footprint (library) data.
732 for( FOOTPRINT* footprint : aPcb->Footprints() )
733 idf_export_footprint( aPcb, footprint, idfBoard, aIncludeUnspecified, aIncludeDNP );
734
735 if( !idfBoard.WriteFile( aFullFileName, idfUnit, false ) )
736 {
737 if( aErrorMsg )
738 *aErrorMsg = From_UTF8( idfBoard.GetError().c_str() );
739
740 ok = false;
741 }
742 }
743 catch( const IO_ERROR& ioe )
744 {
745 if( aErrorMsg )
746 *aErrorMsg = ioe.What();
747
748 ok = false;
749 }
750 catch( const std::exception& e )
751 {
752 if( aErrorMsg )
753 *aErrorMsg = From_UTF8( e.what() );
754
755 ok = false;
756 }
757
758 return ok;
759}
760
761
762bool PCB_EDIT_FRAME::Export_IDF3( BOARD* aPcb, const wxString& aFullFileName,
763 bool aUseThou, double aXRef, double aYRef,
764 bool aIncludeUnspecified, bool aIncludeDNP )
765{
767 wxString errorMsg;
768
769 bool ok = ExportBoardToIDF3( aPcb, aFullFileName, aUseThou, aXRef, aYRef, aIncludeUnspecified,
770 aIncludeDNP, res, &errorMsg );
771
772 if( !ok )
773 {
774 wxString msg;
775 msg << _( "IDF Export Failed:\n" ) << errorMsg;
776 wxMessageBox( msg );
777 }
778
779 return ok;
780}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
wxString GetBuildVersion()
Get the full KiCad version string.
int GetBoardThickness() const
The full thickness of the board including copper and masks.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3464
const BOX2I GetBoardEdgesBoundingBox() const
Return the board bounding box calculated using exclusively the board edges (graphics on Edge....
Definition board.h:1160
const FOOTPRINTS & Footprints() const
Definition board.h:421
const wxString & GetFileName() const
Definition board.h:410
wxString GetCurrentVariant() const
Definition board.h:469
PROJECT * GetProject() const
Definition board.h:658
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
const DRAWINGS & Drawings() const
Definition board.h:423
constexpr const Vec & GetOrigin() const
Definition box2.h:206
constexpr const SizeVec & GetSize() const
Definition box2.h:202
double AsDegrees() const
Definition eda_angle.h:116
EDA_ANGLE GetArcAngle() const
SHAPE_POLY_SET & GetPolyShape()
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:185
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:240
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition eda_shape.h:404
bool IsPolyShapeValid() const
Provide an extensible class to resolve 3D model paths.
EDA_ANGLE GetOrientation() const
Definition footprint.h:406
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:877
std::deque< PAD * > & Pads()
Definition footprint.h:375
int GetAttributes() const
Definition footprint.h:507
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:417
const LIB_ID & GetFPID() const
Definition footprint.h:441
PCB_FIELD & Reference()
Definition footprint.h:878
bool GetDNPForVariant(const wxString &aVariantName) const
Get the DNP status for a specific variant.
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:392
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition footprint.h:1305
VECTOR2I GetPosition() const override
Definition footprint.h:403
DRAWINGS & GraphicalItems()
Definition footprint.h:378
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...
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
bool Export_IDF3(BOARD *aPcb, const wxString &aFullFileName, bool aUseThou, double aXRef, double aYRef, bool aIncludeUnspecified, bool aIncludeDNP)
Create an IDF3 compliant BOARD (*.emn) and LIBRARY (*.emp) file.
wxString GetShownText(bool aAllowExtraText, 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)
FILENAME_RESOLVER * GetResolver() noexcept
Definition 3d_cache.cpp:541
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.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
#define _(s)
@ SEGMENT
Definition eda_shape.h:46
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:47
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 ...
bool ExportBoardToIDF3(BOARD *aPcb, const wxString &aFullFileName, bool aUseThou, double aXRef, double aYRef, bool aIncludeUnspecified, bool aIncludeDNP, FILENAME_RESOLVER *aResolver, wxString *aErrorMsg)
Generate IDFv3 compliant board (*.emn) and library (*.emp) files representing the user's PCB design.
#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 FILENAME_RESOLVER * resolver
static void idf_export_footprint(BOARD *aPcb, FOOTPRINT *aFootprint, IDF3_BOARD &aIDFBoard, bool aIncludeUnspecified, bool aIncludeDNP)
Retrieve information from all board footprints, adds drill holes to the DRILLED_HOLES or BOARD_OUTLIN...
@ FP_SMD
Definition footprint.h:84
@ FP_THROUGH_HOLE
Definition footprint.h:83
PROJECT & Prj()
Definition kicad.cpp:728
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Cu
Definition layer_ids.h:61
This file contains miscellaneous commonly used macros and functions.
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
const int scale
wxString From_UTF8(const char *cstring)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
KIBIS top(path, &reporter)
KIBIS_COMPONENT * comp
VECTOR3I res
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:225
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:81
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683