KiCad PCB EDA Suite
Loading...
Searching...
No Matches
idf_parser.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) 2014-2017 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 <iostream>
23#include <iomanip>
24#include <sstream>
25#include <cmath>
26#include <cerrno>
27#include <algorithm>
28#include <utility>
29#include <wx/string.h>
30#include <wx/filename.h>
31
32#include <io/idf/idf_parser.h>
33#include <io/idf/idf_helpers.h>
34#include "streamwrapper.h"
35
36#include <reporter.h>
38
39using namespace std;
40using namespace IDF3;
41
42
43static bool MatchCompOutline( IDF3_COMP_OUTLINE* aOutlineA, IDF3_COMP_OUTLINE* aOutlineB )
44{
45 if( aOutlineA->GetComponentClass() != aOutlineB->GetComponentClass() )
46 return false;
47
48 if( aOutlineA->OutlinesSize() != aOutlineB->OutlinesSize() )
49 return false;
50
51 // are both outlines empty?
52 if( aOutlineA->OutlinesSize() == 0 )
53 return true;
54
55 IDF_OUTLINE* opA = aOutlineA->GetOutline( 0 );
56 IDF_OUTLINE* opB = aOutlineB->GetOutline( 0 );
57
58 if( opA->size() != opB->size() )
59 return false;
60
61 if( opA->size() == 0 )
62 return true;
63
64 std::list<IDF_SEGMENT*>::iterator olAs = opA->begin();
65 std::list<IDF_SEGMENT*>::iterator olAe = opA->end();
66 std::list<IDF_SEGMENT*>::iterator olBs = opB->begin();
67
68 while( olAs != olAe )
69 {
70 if( !(*olAs)->MatchesStart( (*olBs)->startPoint ) )
71 return false;
72
73 if( !(*olAs)->MatchesEnd( (*olBs)->endPoint ) )
74 return false;
75
76 ++olAs;
77 ++olBs;
78 }
79
80 return true;
81}
82
83
85{
86 parent = nullptr;
87 outline = nullptr;
88 xoff = 0.0;
89 yoff = 0.0;
90 zoff = 0.0;
91 aoff = 0.0;
92}
93
94
96 IDF3_COMP_OUTLINE* aOutline )
97{
98 parent = aParent;
99 outline = aOutline;
100 xoff = 0.0;
101 yoff = 0.0;
102 zoff = 0.0;
103 aoff = 0.0;
104
105 if( aOutline )
106 aOutline->incrementRef();
107}
108
109
111 IDF3_COMP_OUTLINE* aOutline,
112 double aXoff, double aYoff,
113 double aZoff, double aAngleOff )
114{
115 parent = aParent;
116 outline = aOutline;
117 xoff = aXoff;
118 yoff = aYoff;
119 zoff = aZoff;
120 aoff = aAngleOff;
121}
122
123
125{
126 if( outline )
127 outline->decrementRef();
128}
129
130
131#ifndef DISABLE_IDF_OWNERSHIP
132bool IDF3_COMP_OUTLINE_DATA::checkOwnership( int aSourceLine, const char* aSourceFunc )
133{
134 if( !parent )
135 {
136 ostringstream ostr;
137 ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
138 ostr << "* BUG: IDF3_COMP_OUTLINE_DATA::parent not set; cannot enforce ownership rules\n";
139 errormsg = ostr.str();
140
141 return false;
142 }
143
144 IDF3::IDF_PLACEMENT placement = parent->GetPlacement();
145 IDF3::CAD_TYPE parentCAD = parent->GetCadType();
146
147 if( placement == IDF_PLACEMENT::PS_PLACED || placement == IDF_PLACEMENT::PS_UNPLACED )
148 return true;
149
150 if( placement == IDF_PLACEMENT::PS_MCAD && parentCAD == CAD_TYPE::CAD_MECH )
151 return true;
152
153 if( placement == IDF_PLACEMENT::PS_ECAD && parentCAD == CAD_TYPE::CAD_ELEC )
154 return true;
155
156 do
157 {
158 ostringstream ostr;
159 ostr << "* " << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
160 ostr << "* ownership violation; CAD type is ";
161
162 if( parentCAD == CAD_TYPE::CAD_MECH )
163 ostr << "MCAD ";
164 else
165 ostr << "ECAD ";
166
167 ostr << "while outline owner is " << GetPlacementString( placement ) << "\n";
168 errormsg = ostr.str();
169
170 } while( 0 );
171
172 return false;
173}
174#endif
175
176
177bool IDF3_COMP_OUTLINE_DATA::SetOffsets( double aXoff, double aYoff,
178 double aZoff, double aAngleOff )
179{
180#ifndef DISABLE_IDF_OWNERSHIP
181 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
182 return false;
183#endif
184
185 xoff = aXoff;
186 yoff = aYoff;
187 zoff = aZoff;
188 aoff = aAngleOff;
189 return true;
190}
191
192
193void IDF3_COMP_OUTLINE_DATA::GetOffsets( double& aXoff, double& aYoff,
194 double& aZoff, double& aAngleOff )
195{
196 aXoff = xoff;
197 aYoff = yoff;
198 aZoff = zoff;
199 aAngleOff = aoff;
200}
201
202
204{
205 parent = aParent;
206}
207
208
210{
211#ifndef DISABLE_IDF_OWNERSHIP
212 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
213 return false;
214#endif
215
216 if( outline )
217 outline->decrementRef();
218
219 outline = aOutline;
220
221 if( outline )
222 outline->incrementRef();
223
224 return true;
225}
226
227
228bool IDF3_COMP_OUTLINE_DATA::readPlaceData( std::istream& aBoardFile, FILE_STATE& aBoardState, IDF3_BOARD* aBoard,
229 IDF_VERSION aIdfVersion, bool aNoSubstituteOutlines )
230{
231 if( !aBoard )
232 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
233 "\n* BUG: invoked with no reference to the parent IDF_BOARD" ) );
234
235 // clear out data possibly left over from previous use of the object
236 outline = nullptr;
237 parent = nullptr;
238
239 std::string iline; // the input line
240 bool isComment; // true if a line just read in is a comment line
241 std::streampos pos;
242 int idx = 0;
243 bool quoted = false;
244 std::string token;
245 std::string uid;
246 std::string refdes;
249
250 // RECORD 2: 'package name', 'part number', 'Refdes' (any, NOREFDES, BOARD)
251 while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() );
252
253 if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() )
254 {
255 ostringstream ostr;
256
257 ostr << "invalid IDF file\n";
258 ostr << "* violation: could not read PLACEMENT section\n";
259 ostr << "* file position: " << pos;
260
261 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
262 }
263
264 if( isComment )
265 {
266 ostringstream ostr;
267
268 ostr << "invalid IDF file\n";
269 ostr << "* violation: comment within PLACEMENT section\n";
270 ostr << "* line: '" << iline << "'\n";
271 ostr << "* file position: " << pos;
272
273 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
274 }
275
276 idx = 0;
277 GetIDFString( iline, token, quoted, idx );
278
279 if( !quoted && CompareToken( ".END_PLACEMENT", token ) )
280 {
281 aBoardState = FILE_STATE::FILE_PLACEMENT;
282 return false;
283 }
284
285 std::string ngeom = token;
286
287 if( !GetIDFString( iline, token, quoted, idx ) )
288 {
289 ostringstream ostr;
290
291 ostr << "invalid IDF file\n";
292 ostr << "* violation: no PART NAME in PLACEMENT RECORD2\n";
293 ostr << "* line: '" << iline << "'\n";
294 ostr << "* file position: " << pos;
295
296 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
297 }
298
299 std::string npart = token;
300 uid = ngeom + "_" + npart;
301
302 if( !GetIDFString( iline, token, quoted, idx ) )
303 {
304 ostringstream ostr;
305
306 ostr << "invalid IDF file\n";
307 ostr << "* violation: no REFDES in PLACEMENT RECORD2\n";
308 ostr << "* line: '" << iline << "'\n";
309 ostr << "* file position: " << pos;
310
311 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
312 }
313
314 if( CompareToken( "NOREFDES", token ) )
315 {
316 // according to the IDF3.0 specification, this is a
317 // mechanical component. The specification is defective
318 // since it is impossible to associate mechanical
319 // components with their holes unless the mechanical
320 // component is given a unique RefDes. This class of defect
321 // is one reason IDF does not work well in faithfully
322 // conveying information between ECAD and MCAD.
323 refdes = aBoard->GetNewRefDes();
324 }
325 else if( CompareToken( "BOARD", token ) )
326 {
327 ostringstream ostr;
328
329 ostr << "UNSUPPORTED FEATURE\n";
330 ostr << "* RefDes is 'BOARD', indicating this is a PANEL FILE (not supported)\n";
331 ostr << "* line: '" << iline << "'\n";
332 ostr << "* file position: " << pos;
333
334 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
335 }
336 else if( CompareToken( "PANEL", token ) )
337 {
338 ostringstream ostr;
339
340 ostr << "invalid IDF file\n";
341 ostr << "* violation: RefDes in PLACEMENT RECORD2 is 'PANEL'\n";
342 ostr << "* line: '" << iline << "'\n";
343 ostr << "* file position: " << pos;
344
345 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
346 }
347 else if( token.empty() )
348 {
349 ostringstream ostr;
350
351 ostr << "invalid IDF file\n";
352 ostr << "* violation: empty RefDes string in PLACEMENT RECORD2\n";
353 ostr << "* line: '" << iline << "'\n";
354 ostr << "* file position: " << pos;
355
356 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
357 }
358 else
359 {
360 // note: perversely, spaces can be a valid RefDes
361 refdes = token;
362 }
363
364 // V2: RECORD 3: X, Y, ROT, SIDE (top/bot), PLACEMENT (fixed, placed, unplaced)
365 // V3: RECORD 3: X, Y, Z, ROT, SIDE (top/bot), PLACEMENT (placed, unplaced, mcad, ecad)
366 while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() );
367
368 if( !aBoardFile.good() )
369 {
370 ostringstream ostr;
371
372 ostr << "invalid IDF file\n";
373 ostr << "* problems reading PLACEMENT SECTION, RECORD 3\n";
374 ostr << "* file position: " << pos;
375
376 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
377 }
378
379 if( isComment )
380 {
381 ostringstream ostr;
382
383 ostr << "invalid IDF file\n";
384 ostr << "* violation: comment within PLACEMENT section\n";
385 ostr << "* line: '" << iline << "'\n";
386 ostr << "* file position: " << pos;
387
388 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
389 }
390
391 idx = 0;
392 GetIDFString( iline, token, quoted, idx );
393
394 if( quoted )
395 {
396 ostringstream ostr;
397
398 ostr << "invalid IDF file\n";
399 ostr << "* violation: X value must not be in quotes (PLACEMENT RECORD 3)\n";
400 ostr << "* line: '" << iline << "'\n";
401 ostr << "* file position: " << pos;
402
403 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
404 }
405
406 istringstream istr;
407 istr.str( token );
408
409 istr >> xoff;
410 if( istr.fail() )
411 {
412 ostringstream ostr;
413
414 ostr << "invalid IDF file\n";
415 ostr << "* violation: X value is not numeric (PLACEMENT RECORD 3)\n";
416 ostr << "* line: '" << iline << "'\n";
417 ostr << "* file position: " << pos;
418
419 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
420 }
421
422 if( !GetIDFString( iline, token, quoted, idx ) )
423 {
424 ostringstream ostr;
425
426 ostr << "invalid IDF file\n";
427 ostr << "* violation: no Y value (PLACEMENT RECORD 3)\n";
428 ostr << "* line: '" << iline << "'\n";
429 ostr << "* file position: " << pos;
430
431 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
432 }
433
434 istr.clear();
435 istr.str( token );
436
437 istr >> yoff;
438 if( istr.fail() )
439 {
440 ostringstream ostr;
441
442 ostr << "invalid IDF file\n";
443 ostr << "* violation: Y value is not numeric (PLACEMENT RECORD 3)\n";
444 ostr << "* line: '" << iline << "'\n";
445 ostr << "* file position: " << pos;
446
447 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
448 }
449
450 if( aIdfVersion > IDF_VERSION::IDF_V2 )
451 {
452 if( !GetIDFString( iline, token, quoted, idx ) )
453 {
454 ostringstream ostr;
455
456 ostr << "invalid IDFv3 file\n";
457 ostr << "* violation: no Z value (PLACEMENT RECORD 3)\n";
458 ostr << "* line: '" << iline << "'\n";
459 ostr << "* file position: " << pos;
460
461 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
462 }
463
464 istr.clear();
465 istr.str( token );
466
467 istr >> zoff;
468 if( istr.fail() )
469 {
470 ostringstream ostr;
471
472 ostr << "invalid IDFv3 file\n";
473 ostr << "* violation: Z value is not numeric (PLACEMENT RECORD 3)\n";
474 ostr << "* line: '" << iline << "'\n";
475 ostr << "* file position: " << pos;
476
477 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
478 }
479 }
480
481 if( !GetIDFString( iline, token, quoted, idx ) )
482 {
483 ostringstream ostr;
484
485 ostr << "invalid IDF file\n";
486 ostr << "* violation: no rotation value (PLACEMENT RECORD 3)\n";
487 ostr << "* line: '" << iline << "'\n";
488 ostr << "* file position: " << pos;
489
490 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
491 }
492
493 istr.clear();
494 istr.str( token );
495
496 istr >> aoff;
497 if( istr.fail() )
498 {
499 ostringstream ostr;
500
501 ostr << "invalid IDF file\n";
502 ostr << "* violation: rotation value is not numeric (PLACEMENT RECORD 3)\n";
503 ostr << "* line: '" << iline << "'\n";
504 ostr << "* file position: " << pos;
505
506 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
507 }
508
509 if( !GetIDFString( iline, token, quoted, idx ) )
510 {
511 ostringstream ostr;
512
513 ostr << "invalid IDF file\n";
514 ostr << "* violation: no SIDE value (PLACEMENT RECORD 3)\n";
515 ostr << "* line: '" << iline << "'\n";
516 ostr << "* file position: " << pos;
517
518 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
519 }
520
521 if( CompareToken( "TOP", token ) )
522 {
524 }
525 else if( CompareToken( "BOTTOM", token ) )
526 {
528 }
529 else
530 {
531 ostringstream ostr;
532
533 ostr << "invalid IDF file\n";
534 ostr << "* violation: invalid SIDE value in PLACEMENT RECORD 3 ('";
535 ostr << token << "'); must be one of TOP/BOTTOM\n";
536 ostr << "* line: '" << iline << "'\n";
537 ostr << "* file position: " << pos;
538
539 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
540 }
541
542 if( !GetIDFString( iline, token, quoted, idx ) )
543 {
544 ostringstream ostr;
545
546 ostr << "invalid IDF file\n";
547 ostr << "* violation: no PLACEMENT value in PLACEMENT RECORD 3\n";
548 ostr << "* line: '" << iline << "'\n";
549 ostr << "* file position: " << pos;
550
551 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
552 }
553
554 if( CompareToken( "PLACED", token ) )
555 {
557 }
558 else if( CompareToken( "UNPLACED", token ) )
559 {
561 }
562 else if( aIdfVersion > IDF_VERSION::IDF_V2 && CompareToken( "MCAD", token ) )
563 {
565 }
566 else if( aIdfVersion > IDF_VERSION::IDF_V2 && CompareToken( "ECAD", token ) )
567 {
569 }
570 else if( aIdfVersion < IDF_VERSION::IDF_V3 && CompareToken( "FIXED", token ) )
571 {
572 if( aBoard->GetCadType() == CAD_TYPE::CAD_ELEC )
574 else
576 }
577 else
578 {
579 ostringstream ostr;
580
581 ostr << "invalid IDF file\n";
582 ostr << "* violation: invalid PLACEMENT value ('";
583 ostr << token << "') in PLACEMENT RECORD 3\n";
584 ostr << "* line: '" << iline << "'\n";
585 ostr << "* file position: " << pos;
586
587 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
588 }
589
590 outline = aBoard->GetComponentOutline( uid );
591
592 if( outline == nullptr && !aNoSubstituteOutlines )
593 {
594 ERROR_IDF << "MISSING OUTLINE\n";
595 cerr << "* GeomName( " << ngeom << " ), PartName( " << npart << " )\n";
596 cerr << "* Substituting default outline.\n";
597 outline = aBoard->GetInvalidOutline( ngeom, npart );
598
599 if( outline == nullptr )
600 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
601 "\n* missing outline: cannot create default" ) );
602 }
603
604 if( aBoard->GetUnit() == IDF3::IDF_UNIT::UNIT_THOU )
605 {
609 }
610
611 parent = aBoard->FindComponent( refdes );
612
613 if( parent == nullptr )
614 {
615 IDF3_COMPONENT* cp;
616
617 try
618 {
619 cp = new IDF3_COMPONENT( aBoard );
620 }
621 catch( std::bad_alloc& )
622 {
623 outline = nullptr;
624
625 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
626 "cannot create component object" ) );
627 }
628
629 cp->SetRefDes( refdes );
630 cp->SetPosition( xoff, yoff, aoff, side );
631 cp->SetPlacement( placement );
632
633 xoff = 0;
634 yoff = 0;
635 aoff = 0;
636
637 aBoard->AddComponent( cp );
638
639 parent = cp;
640 }
641 else
642 {
643 double tX, tY, tA;
645
646 if( parent->GetPosition( tX, tY, tA, tL ) )
647 {
648 if( side != tL )
649 {
650 outline = nullptr;
651 ostringstream ostr;
652
653 ostr << "invalid IDF file\n";
654 ostr << "* violation: inconsistent PLACEMENT data; ";
655 ostr << "* SIDE value has changed from " << GetLayerString( tL );
656 ostr << " to " << GetLayerString( side ) << "\n";
657 ostr << "* line: '" << iline << "'\n";
658 ostr << "* file position: " << pos;
659
660 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
661 }
662
663 xoff -= tX;
664 yoff -= tY;
665 aoff -= tA;
666 }
667 else
668 {
669 parent->SetPosition( xoff, yoff, aoff, side );
670 parent->SetPlacement( placement );
671
672 xoff = 0;
673 yoff = 0;
674 aoff = 0;
675 }
676
677 if( placement != parent->GetPlacement() )
678 {
679 outline = nullptr;
680 ostringstream ostr;
681
682 ostr << "invalid IDF file\n";
683 ostr << "* violation: inconsistent PLACEMENT data; ";
684 ostr << "* PLACEMENT value has changed from ";
685 ostr << GetPlacementString( parent->GetPlacement() );
686 ostr << " to " << GetPlacementString( placement ) << "\n";
687 ostr << "* line: '" << iline << "'\n";
688 ostr << "* file position: " << pos;
689
690 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
691 }
692
693 }
694
695 // copy internal data to a new object and push it into the component's outline list
697 *cdp = *this;
698 if( outline ) outline->incrementRef();
699 outline = nullptr;
700
701 if( !parent->AddOutlineData( cdp ) )
702 {
703 delete cdp;
704
705 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
706 "could not add outline data object" ) );
707 }
708
709 return true;
710}
711
712
713void IDF3_COMP_OUTLINE_DATA::writePlaceData( std::ostream& aBoardFile,
714 double aXpos, double aYpos, double aAngle,
715 const std::string& aRefDes,
716 IDF3::IDF_PLACEMENT aPlacement,
717 IDF3::IDF_LAYER aSide )
718{
719 if( outline == nullptr )
720 return;
721
722 if( outline->GetUID().empty() )
723 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
724 "empty GEOM and PART names" ) );
725
726 if( aPlacement == IDF_PLACEMENT::PS_INVALID )
727 {
728 ERROR_IDF << "placement invalid (" << aRefDes << ":";
729 aPlacement = IDF_PLACEMENT::PS_PLACED;
730 }
731
732 if( aSide != IDF_LAYER::LYR_TOP && aSide != IDF_LAYER::LYR_BOTTOM )
733 {
734 ostringstream ostr;
735 ostr << "\n* invalid side (" << GetLayerString( aSide ) << "); ";
736 ostr << "must be TOP or BOTTOM\n";
737
738 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
739 }
740
741 // calculate the final position based on layer
742 double xpos, ypos, ang;
743
744 switch( aSide )
745 {
747 xpos = aXpos + xoff;
748 ypos = aYpos + yoff;
749 ang = aAngle + aoff;
750 break;
751
752 default:
753 xpos = aXpos - xoff;
754 ypos = aYpos + yoff;
755 ang = aAngle - aoff;
756 break;
757 }
758
759 std::string arefdes = aRefDes;
760
761 if( arefdes.empty() || !arefdes.compare( "~" )
762 || ( arefdes.size() >= 8 && CompareToken( "NOREFDES", arefdes.substr(0, 8) ) ) )
763 arefdes = "NOREFDES";
764
765 aBoardFile << "\"" << outline->GetGeomName() << "\" \"" << outline->GetPartName() << "\" "
766 << arefdes << "\n";
767
769
770 if( parent )
771 unit = parent->GetUnit();
772
773 if( unit == IDF_UNIT::UNIT_MM )
774 {
775 aBoardFile << setiosflags(ios::fixed) << setprecision(5) << xpos << " "
776 << ypos << " " << setprecision(3) << zoff << " "
777 << ang << " ";
778 }
779 else
780 {
781 aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (xpos / IDF_THOU_TO_MM) << " "
782 << (ypos / IDF_THOU_TO_MM) << " " << (zoff / IDF_THOU_TO_MM) << " "
783 << setprecision(3) << ang << " ";
784 }
785
786 WriteLayersText( aBoardFile, aSide );
787
788 switch( aPlacement )
789 {
791 aBoardFile << " PLACED\n";
792 break;
793
795 aBoardFile << " UNPLACED\n";
796 break;
797
799 aBoardFile << " MCAD\n";
800 break;
801
802 default:
803 aBoardFile << " ECAD\n";
804 break;
805 }
806}
807
808
810{
811 xpos = 0.0;
812 ypos = 0.0;
813 angle = 0.0;
814
815 hasPosition = false;
818
819 parent = aParent;
820}
821
822
824{
825 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itcS = components.begin();
826 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itcE = components.end();
827
828 while( itcS != itcE )
829 {
830 delete *itcS;
831 ++itcS;
832 }
833
834 components.clear();
835
836 std::list< IDF_DRILL_DATA* >::iterator itdS = drills.begin();
837 std::list< IDF_DRILL_DATA* >::iterator itdE = drills.end();
838
839 while( itdS != itdE )
840 {
841 delete *itdS;
842 ++itdS;
843 }
844
845 drills.clear();
846}
847
848
849#ifndef DISABLE_IDF_OWNERSHIP
850bool IDF3_COMPONENT::checkOwnership( int aSourceLine, const char* aSourceFunc )
851{
852 if( !parent )
853 {
854 ostringstream ostr;
855 ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
856 ostr << "\n* BUG: parent not set";
857 errormsg = ostr.str();
858
859 return false;
860 }
861
862 IDF3::CAD_TYPE pcad = parent->GetCadType();
863
864 switch( placement )
865 {
869 break;
870
872
873 if( pcad != CAD_TYPE::CAD_MECH )
874 {
875 ostringstream ostr;
876 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
877 ostr << "\n* ownership violation; internal CAD type (MCAD) conflicts with "
878 "PLACEMENT (";
879 ostr << GetPlacementString( placement ) << ")";
880 errormsg = ostr.str();
881
882 return false;
883 }
884
885 break;
886
888
889 if( pcad != CAD_TYPE::CAD_ELEC )
890 {
891 ostringstream ostr;
892 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
893 ostr << "\n* ownership violation; internal CAD type (MCAD) conflicts with "
894 "PLACEMENT (";
895 ostr << GetPlacementString( placement ) << ")";
896 errormsg = ostr.str();
897
898 return false;
899 }
900 break;
901
902 default:
903 do
904 {
905 ostringstream ostr;
906 ostr << "\n* BUG: unhandled internal placement value (" << static_cast<int>( placement ) << ")";
907 errormsg = ostr.str();
908
909 return false;
910 } while( 0 );
911
912 break;
913 }
914
915 return true;
916}
917#endif
918
919
921{
922 parent = aParent;
923 return;
924}
925
927{
928 if( parent )
929 return parent->GetCadType();
930
932}
933
935{
936 if( parent )
937 return parent->GetUnit();
938
940}
941
942bool IDF3_COMPONENT::SetRefDes( const std::string& aRefDes )
943{
944#ifndef DISABLE_IDF_OWNERSHIP
945 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
946 return false;
947#endif
948
949 if( aRefDes.empty() )
950 {
951 ostringstream ostr;
952 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): invalid RefDes (empty)";
953 errormsg = ostr.str();
954
955 return false;
956 }
957
958 if( CompareToken( "PANEL", aRefDes ) )
959 {
960 ostringstream ostr;
961 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
962 ostr << "* BUG: PANEL is a reserved designator and may not be used by components";
963 errormsg = ostr.str();
964
965 return false;
966 }
967
968 refdes = aRefDes;
969 return true;
970}
971
972
973const std::string& IDF3_COMPONENT::GetRefDes( void )
974{
975 return refdes;
976}
977
978
979IDF_DRILL_DATA* IDF3_COMPONENT::AddDrill( double aDia, double aXpos, double aYpos,
980 IDF3::KEY_PLATING aPlating,
981 const std::string& aHoleType,
982 IDF3::KEY_OWNER aOwner )
983{
984 IDF_DRILL_DATA* dp = nullptr;
985
986 try
987 {
988 dp = new IDF_DRILL_DATA( aDia, aXpos, aYpos, aPlating, refdes, aHoleType, aOwner );
989 }
990 catch( std::bad_alloc& )
991 {
992 return nullptr;
993 }
994
995 drills.push_back( dp );
996
997 return dp;
998}
999
1000
1002{
1003 if( !aDrilledHole )
1004 return nullptr;
1005
1006 if( CompareToken( "PANEL", refdes ) )
1007 {
1008 ERROR_IDF;
1009 cerr << "\n* BUG: PANEL drills not supported at component level\n";
1010 return nullptr;
1011 }
1012
1013 if( refdes.compare( aDrilledHole->GetDrillRefDes() ) )
1014 {
1015 ERROR_IDF;
1016 cerr << "\n* BUG: pushing an incorrect REFDES ('" << aDrilledHole->GetDrillRefDes();
1017 cerr << "') to component ('" << refdes << "')\n";
1018 return nullptr;
1019 }
1020
1021 drills.push_back( aDrilledHole );
1022
1023 return aDrilledHole;
1024}
1025
1026
1027bool IDF3_COMPONENT::DelDrill( double aDia, double aXpos, double aYpos )
1028{
1029#ifndef DISABLE_IDF_OWNERSHIP
1030 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
1031 return false;
1032#endif
1033
1034 errormsg.clear();
1035
1036 if( drills.empty() )
1037 return false;
1038
1039 bool val = false;
1040
1041 list< IDF_DRILL_DATA* >::iterator itS = drills.begin();
1042 list< IDF_DRILL_DATA* >::iterator itE = drills.end();
1043
1044 while( !drills.empty() && itS != itE )
1045 {
1046 if( (*itS)->Matches( aDia, aXpos, aYpos ) )
1047 {
1048 val = true;
1049 delete *itS;
1050 itS = drills.erase( itS );
1051 continue;
1052 }
1053
1054 ++itS;
1055 }
1056
1057 return val;
1058}
1059
1060
1062{
1063#ifndef DISABLE_IDF_OWNERSHIP
1064 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
1065 return false;
1066#endif
1067
1068 errormsg.clear();
1069
1070 if( drills.empty() )
1071 return false;
1072
1073 list< IDF_DRILL_DATA* >::iterator itS = drills.begin();
1074 list< IDF_DRILL_DATA* >::iterator itE = drills.end();
1075
1076 while( !drills.empty() && itS != itE )
1077 {
1078 if( *itS == aDrill )
1079 {
1080 delete *itS;
1081 drills.erase( itS );
1082 return true;
1083 }
1084
1085 ++itS;
1086 }
1087
1088 return false;
1089}
1090
1091
1092const std::list<IDF_DRILL_DATA*>* IDF3_COMPONENT::GetDrills( void )
1093{
1094 return &drills;
1095}
1096
1098{
1099 if( aComponentOutline == nullptr )
1100 {
1101 ostringstream ostr;
1102 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ <<
1103 "(): invalid aComponentOutline (nullptr)";
1104 errormsg = ostr.str();
1105
1106 return false;
1107 }
1108
1109
1110 components.push_back( aComponentOutline );
1111
1112 return true;
1113}
1114
1115
1117{
1118#ifndef DISABLE_IDF_OWNERSHIP
1119 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
1120 return false;
1121#endif
1122
1123 if( components.empty() )
1124 {
1125 ostringstream ostr;
1126 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): component list is empty";
1127 errormsg = ostr.str();
1128
1129 return false;
1130 }
1131
1132 if( aComponentOutline == nullptr )
1133 {
1134 ostringstream ostr;
1135 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ <<
1136 "(): invalid aComponentOutline (nullptr)";
1137 errormsg = ostr.str();
1138
1139 return false;
1140 }
1141
1142 errormsg.clear();
1143
1144 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itS = components.begin();
1145 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itE = components.end();
1146
1147 while( itS != itE )
1148 {
1149 if( *itS == aComponentOutline )
1150 {
1151 delete *itS;
1152 components.erase( itS );
1153 return true;
1154 }
1155
1156 ++itS;
1157 }
1158
1159 return false;
1160}
1161
1162
1164{
1165#ifndef DISABLE_IDF_OWNERSHIP
1166 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
1167 return false;
1168#endif
1169
1170 if( aIndex >= components.size() )
1171 {
1172 ostringstream ostr;
1173 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1174 ostr << "* aIndex (" << aIndex << ") out of range; list size is " << components.size();
1175 errormsg = ostr.str();
1176
1177 return false;
1178 }
1179
1180 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itS = components.begin();
1181 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itE = components.end();
1182 size_t idx = 0;
1183
1184 while( itS != itE )
1185 {
1186 if( idx == aIndex )
1187 {
1188 delete *itS;
1189 components.erase( itS );
1190 return true;
1191 }
1192
1193 ++idx;
1194 ++itS;
1195 }
1196
1197 return false;
1198}
1199
1200
1202{
1203 return components.size();
1204}
1205
1206
1207const std::list< IDF3_COMP_OUTLINE_DATA* >* IDF3_COMPONENT::GetOutlinesData( void )
1208{
1209 return &components;
1210}
1211
1212
1213bool IDF3_COMPONENT::GetPosition( double& aXpos, double& aYpos, double& aAngle,
1214 IDF3::IDF_LAYER& aLayer )
1215{
1216 errormsg.clear();
1217
1218 if( !hasPosition )
1219 {
1220 aXpos = 0.0;
1221 aYpos = 0.0;
1222 aAngle = 0.0;
1224 return false;
1225 }
1226
1227 aXpos = xpos;
1228 aYpos = ypos;
1229 aAngle = angle;
1230 aLayer = layer;
1231 return true;
1232}
1233
1234
1235bool IDF3_COMPONENT::SetPosition( double aXpos, double aYpos, double aAngle,
1236 IDF3::IDF_LAYER aLayer )
1237{
1238#ifndef DISABLE_IDF_OWNERSHIP
1239 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
1240 return false;
1241#endif
1242
1243 errormsg.clear();
1244
1245 switch( aLayer )
1246 {
1247 case IDF_LAYER::LYR_TOP:
1249 break;
1250
1251 default:
1252 do
1253 {
1254 ostringstream ostr;
1255 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1256 ostr << "\n* invalid side (must be TOP or BOTTOM only): " <<
1257 GetLayerString( aLayer );
1258 errormsg = ostr.str();
1259
1260 return false;
1261 } while( 0 );
1262
1263 break;
1264 }
1265
1266 if( hasPosition )
1267 return false;
1268
1269 hasPosition = true;
1270 xpos = aXpos;
1271 ypos = aYpos;
1272 angle = aAngle;
1273 layer = aLayer;
1274 return true;
1275}
1276
1277
1282
1283
1285{
1286 if( aPlacementValue < IDF_PLACEMENT::PS_UNPLACED || aPlacementValue >= IDF_PLACEMENT::PS_INVALID )
1287 {
1288 ostringstream ostr;
1289 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1290 ostr << "\n* invalid PLACEMENT value (" << static_cast<int>( aPlacementValue ) << ")";
1291 errormsg = ostr.str();
1292
1293 return false;
1294 }
1295
1296#ifndef DISABLE_IDF_OWNERSHIP
1297 if( !checkOwnership( __LINE__, __FUNCTION__ ) )
1298 return false;
1299#endif
1300
1301 placement = aPlacementValue;
1302
1303 return true;
1304}
1305
1306
1307bool IDF3_COMPONENT::writeDrillData( std::ostream& aBoardFile )
1308{
1309 if( drills.empty() )
1310 return true;
1311
1312 std::list< IDF_DRILL_DATA* >::iterator itS = drills.begin();
1313 std::list< IDF_DRILL_DATA* >::iterator itE = drills.end();
1314
1315 while( itS != itE )
1316 {
1317 (*itS)->write( aBoardFile, GetUnit() );
1318 ++itS;
1319 }
1320
1321 return true;
1322}
1323
1324
1325bool IDF3_COMPONENT::writePlaceData( std::ostream& aBoardFile )
1326{
1327 if( components.empty() )
1328 return true;
1329
1330 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itS = components.begin();
1331 std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itE = components.end();
1332
1333 while( itS != itE )
1334 {
1335 (*itS)->writePlaceData( aBoardFile, xpos, ypos, angle, refdes, placement, layer );
1336 ++itS;
1337 }
1338
1339 return true;
1340}
1341
1342
1344{
1346 m_cadType = aCadType;
1347 m_userPrec = 5;
1348 m_userScale = 1.0;
1349 m_userXoff = 0.0;
1350 m_userYoff = 0.0;
1351 m_brdFileVersion = 0;
1352 m_libFileVersion = 0;
1353 m_refDesCounter = 0;
1355
1356 // unlike other outlines which are created as necessary,
1357 // the board outline always exists and its parent must
1358 // be set here
1359 m_boardOutline.setParent( this );
1360 m_boardOutline.setThickness( 1.6 );
1361
1362 return;
1363}
1364
1365
1367{
1368 Clear();
1369
1370 return;
1371}
1372
1373
1374const std::string& IDF3_BOARD::GetNewRefDes( void )
1375{
1376 ostringstream ostr;
1377 ostr << "NOREFDESn" << m_refDesCounter++;
1378
1379 m_refDesString = ostr.str();
1380
1381 return m_refDesString;
1382}
1383
1384
1385#ifndef DISABLE_IDF_OWNERSHIP
1386bool IDF3_BOARD::checkComponentOwnership( int aSourceLine, const char* aSourceFunc,
1387 IDF3_COMPONENT* aComponent )
1388{
1389 if( !aComponent )
1390 {
1391 ostringstream ostr;
1392 ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc;
1393 ostr << "(): Invalid component pointer (nullptr)";
1394 m_errormsg = ostr.str();
1395
1396 return false;
1397 }
1398
1399 IDF3::IDF_PLACEMENT place = aComponent->GetPlacement();
1400
1401 if( place == IDF_PLACEMENT::PS_PLACED || place == IDF_PLACEMENT::PS_UNPLACED )
1402 return true;
1403
1405 return true;
1406
1408 return true;
1409
1410 do
1411 {
1412 ostringstream ostr;
1413 ostr << "* " << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
1414 ostr << "* ownership violation; CAD type is ";
1415
1417 ostr << "MCAD ";
1418 else
1419 ostr << "ECAD ";
1420
1421 ostr << "while outline owner is " << GetPlacementString( place ) << "\n";
1422 m_errormsg = ostr.str();
1423
1424 } while( 0 );
1425
1426 return false;
1427}
1428#endif
1429
1430
1432{
1433 switch( aUnit )
1434 {
1435 case IDF_UNIT::UNIT_MM:
1437 m_unit = aUnit;
1438 break;
1439
1440 case IDF_UNIT::UNIT_TNM:
1441 ERROR_IDF << "\n* TNM unit is not supported; defaulting to mm\n";
1443 break;
1444
1445 default:
1446 do
1447 {
1448 ostringstream ostr;
1449 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1450 ostr << "* invalid board unit (" << static_cast<int>( aUnit ) << ")";
1451 m_errormsg = ostr.str();
1452
1453 return false;
1454 } while( 0 );
1455
1456 break;
1457 }
1458
1459 // iterate through all owned OUTLINE objects (except IDF3_COMP_OUTLINE)
1460 // and set to the same unit
1461
1462 m_boardOutline.SetUnit( aUnit );
1463
1464 do
1465 {
1466 std::map<std::string, OTHER_OUTLINE*>::iterator its = m_otherOutlines.begin();
1467 std::map<std::string, OTHER_OUTLINE*>::iterator ite = m_otherOutlines.end();
1468
1469 while( its != ite )
1470 {
1471 its->second->SetUnit( aUnit );
1472 ++its;
1473 }
1474
1475 } while( 0 );
1476
1477 do
1478 {
1479 std::list<ROUTE_OUTLINE*>::iterator its = m_routeOutlines.begin();
1480 std::list<ROUTE_OUTLINE*>::iterator ite = m_routeOutlines.end();
1481
1482 while( its != ite )
1483 {
1484 (*its)->SetUnit( aUnit );
1485 ++its;
1486 }
1487
1488 } while( 0 );
1489
1490 do
1491 {
1492 std::list<PLACE_OUTLINE*>::iterator its = m_placeOutlines.begin();
1493 std::list<PLACE_OUTLINE*>::iterator ite = m_placeOutlines.end();
1494
1495 while( its != ite )
1496 {
1497 (*its)->SetUnit( aUnit );
1498 ++its;
1499 }
1500
1501 } while( 0 );
1502
1503 do
1504 {
1505 std::list<ROUTE_KO_OUTLINE*>::iterator its = m_routeKeepoutOutlines.begin();
1506 std::list<ROUTE_KO_OUTLINE*>::iterator ite = m_routeKeepoutOutlines.end();
1507
1508 while( its != ite )
1509 {
1510 (*its)->SetUnit( aUnit );
1511 ++its;
1512 }
1513
1514 } while( 0 );
1515
1516 do
1517 {
1518 std::list<VIA_KO_OUTLINE*>::iterator its = m_viaKeepoutOutlines.begin();
1519 std::list<VIA_KO_OUTLINE*>::iterator ite = m_viaKeepoutOutlines.end();
1520
1521 while( its != ite )
1522 {
1523 (*its)->SetUnit( aUnit );
1524 ++its;
1525 }
1526
1527 } while( 0 );
1528
1529 do
1530 {
1531 std::list<PLACE_KO_OUTLINE*>::iterator its = m_placeKeepoutOutlines.begin();
1532 std::list<PLACE_KO_OUTLINE*>::iterator ite = m_placeKeepoutOutlines.end();
1533
1534 while( its != ite )
1535 {
1536 (*its)->SetUnit( aUnit );
1537 ++its;
1538 }
1539
1540 } while( 0 );
1541
1542 do
1543 {
1544 std::multimap<std::string, GROUP_OUTLINE*>::iterator its = m_groupOutlines.begin();
1545 std::multimap<std::string, GROUP_OUTLINE*>::iterator ite = m_groupOutlines.end();
1546
1547 while( its != ite )
1548 {
1549 its->second->SetUnit( aUnit );
1550 ++its;
1551 }
1552
1553 } while( 0 );
1554
1555 //iterate through all owned IDF3_COMP_OUTLINE objects and
1556 // set to the same unit IF convert = true
1557 if( convert )
1558 {
1559 std::map<std::string, IDF3_COMP_OUTLINE*>::iterator its = m_componentOutlines.begin();
1560 std::map<std::string, IDF3_COMP_OUTLINE*>::iterator ite = m_componentOutlines.end();
1561
1562 while( its != ite )
1563 {
1564 its->second->SetUnit( aUnit );
1565 ++its;
1566 }
1567
1568 }
1569
1570 return true;
1571}
1572
1573
1574bool IDF3_BOARD::SetBoardThickness( double aBoardThickness )
1575{
1576 if( aBoardThickness <= 0.0 )
1577 {
1578 ostringstream ostr;
1579 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): ";
1580 ostr << "board thickness (" << aBoardThickness << ") must be > 0";
1581 m_errormsg = ostr.str();
1582
1583 return false;
1584 }
1585
1586 if( !m_boardOutline.SetThickness( aBoardThickness ) )
1587 {
1588 m_errormsg = m_boardOutline.GetError();
1589 return false;
1590 }
1591
1592 return true;
1593}
1594
1595
1597{
1598 return m_boardOutline.GetThickness();
1599}
1600
1601
1602void IDF3_BOARD::readBrdDrills( std::istream& aBoardFile, FILE_STATE& aBoardState )
1603{
1604 IDF_DRILL_DATA drill;
1605
1606 while( drill.read( aBoardFile, m_unit, aBoardState, m_idfVer ) )
1607 {
1609 *dp = drill;
1610
1611 if( AddDrill( dp ) == nullptr )
1612 {
1613 delete dp;
1614
1615 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1616 "\n* BUG: could not add drill data; cannot continue reading the file" ) );
1617 }
1618 }
1619}
1620
1621
1622void IDF3_BOARD::readBrdNotes( std::istream& aBoardFile, FILE_STATE& aBoardState )
1623{
1624 IDF_NOTE note;
1625
1626 while( note.readNote( aBoardFile, aBoardState, m_unit ) )
1627 {
1628 IDF_NOTE *np = new IDF_NOTE;
1629 *np = note;
1630 m_notes.push_back( np );
1631 }
1632}
1633
1634
1635void IDF3_BOARD::readBrdPlacement( std::istream& aBoardFile, FILE_STATE& aBoardState,
1636 bool aNoSubstituteOutlines )
1637{
1639
1640 while( oldata.readPlaceData( aBoardFile, aBoardState, this, m_idfVer, aNoSubstituteOutlines ) );
1641}
1642
1643
1644void IDF3_BOARD::readBrdHeader( std::istream& aBoardFile, FILE_STATE& aBoardState )
1645{
1646 std::string iline; // the input line
1647 bool isComment; // true if a line just read in is a comment line
1648 std::streampos pos;
1649 int idx = 0;
1650 bool quoted = false;
1651 std::string token;
1652
1653 // RECORD 1: ".HEADER" must be the very first line
1654 while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() );
1655
1656 if( !aBoardFile.good() )
1657 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "problems reading board header" ) );
1658
1659 if( isComment )
1660 {
1661 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1662 "invalid IDF file\n"
1663 "* Violation of specification: first line must be .HEADER\n" ) );
1664 }
1665
1666 if( !CompareToken( ".HEADER", iline ) )
1667 {
1668 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1669 "invalid IDF file\n"
1670 "* Violation of specification:\n"
1671 "* first line must be .HEADER and have no quotes or trailing text" ) );
1672 }
1673
1674 // RECORD 2:
1675 // File Type [str]: BOARD_FILE (PANEL_FILE not supported)
1676 // IDF Version Number [float]: must be 3.0
1677 // Source System [str]: ignored
1678 // Date [str]: ignored
1679 // Board File Version [int]: ignored
1680 while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() );
1681
1682 if( !aBoardFile.good() )
1683 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "problems reading board header, RECORD 2" ) );
1684
1685 if( isComment )
1686 {
1687 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1688 "invalid IDF file\n"
1689 "* Violation of specification: comment within .HEADER section" ) );
1690 }
1691
1692 idx = 0;
1693 GetIDFString( iline, token, quoted, idx );
1694
1695 if( quoted )
1696 {
1697 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1698 "invalid IDF file\n"
1699 "* Violation of specification:\n"
1700 "* File Type in HEADER section must not be in quotes" ) );
1701 }
1702
1703 if( !CompareToken( "BOARD_FILE", token ) )
1704 {
1705 ERROR_IDF;
1706
1707 if( CompareToken( "PANEL_FILE", token ) )
1708 {
1709 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1710 "not a board file\n"
1711 "* PANEL_FILE is not supported (expecting BOARD_FILE)" ) );
1712 }
1713 else
1714 {
1715 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1716 "invalid IDF file\n"
1717 "* Expecting string: BOARD_FILE" ) );
1718 }
1719 }
1720
1721 if( !GetIDFString( iline, token, quoted, idx ) )
1722 {
1723 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1724 "invalid IDF file\n"
1725 "* Violation of specification: HEADER section, RECORD 2: no FIELD 2" ) );
1726 }
1727
1728 if( quoted )
1729 {
1730 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1731 "invalid IDF file\n"
1732 "* Violation of specification: IDF Version must not be in quotes" ) );
1733 }
1734
1735 if( !token.compare( "3.0" ) || !token.compare( "3." ) || !token.compare( "3" ) )
1736 {
1738 }
1739 else if( !token.compare( "2.0" ) || !token.compare( "2." ) || !token.compare( "2" ) )
1740 {
1742 }
1743 else
1744 {
1745 ostringstream ostr;
1746
1747 ostr << "unsupported IDF version\n";
1748 ostr << "* Expecting version to be a variant of '3.0', '2.0' (value: '" << token << "')\n";
1749
1750 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1751 }
1752
1753 if( !GetIDFString( iline, token, quoted, idx ) )
1754 {
1755 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1756 "invalid IDF file\n"
1757 "* Violation of specification:\n"
1758 "* HEADER section, RECORD 2, FIELD 3: no Source System string" ) );
1759 }
1760
1761 m_brdSource = token;
1762
1763 if( !GetIDFString( iline, token, quoted, idx ) )
1764 {
1765 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1766 "invalid IDF file\n"
1767 "* Violation of specification:\n"
1768 "* HEADER section, RECORD 2, FIELD 4: no Date string" ) );
1769 }
1770
1771 m_brdDate = token;
1772
1773 if( !GetIDFString( iline, token, quoted, idx ) )
1774 {
1775 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1776 "invalid IDF file\n"
1777 "* Violation of specification:\n"
1778 "* HEADER section, RECORD 2, FIELD 5: no Board File Version number" ) );
1779 }
1780
1781 std::istringstream istr;
1782 istr.str( token );
1783
1784 istr >> m_brdFileVersion;
1785
1786 if( istr.fail() )
1787 {
1788 ERROR_IDF << "invalid Board File Version in header\n";
1789 cerr << "* Setting default version of 1\n";
1790 m_brdFileVersion = 1;
1791 }
1792
1793 if( quoted )
1794 {
1795 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1796 "invalid IDF file\n"
1797 "* Violation of specification:\n"
1798 "* HEADER section, RECORD 2, FIELD 5: Board File Version must not be in quotes" ) );
1799 }
1800
1801 // RECORD 3:
1802 // Board Name [str]: stored
1803 // Units [str]: MM or THOU
1804 while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() );
1805
1806 if( !aBoardFile.good() )
1807 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "\n* problems reading board header, RECORD 2" ) );
1808
1809 if( isComment )
1810 {
1811 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1812 "invalid IDF file\n"
1813 "* Violation of specification: comment within .HEADER section" ) );
1814 }
1815
1816 idx = 0;
1817 GetIDFString( iline, token, quoted, idx );
1818
1819 m_boardName = token;
1820
1821 if( !GetIDFString( iline, token, quoted, idx ) )
1822 {
1823 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1824 "invalid IDF file\n"
1825 "* Violation of specification:\n"
1826 "* HEADER section, RECORD 3, FIELD 1: no Board Name" ) );
1827 }
1828
1829 if( quoted )
1830 {
1831 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1832 "invalid IDF file\n"
1833 "* Violation of specification:\n"
1834 "* HEADER section, RECORD 3, FIELD 2: UNIT may not be in quotes" ) );
1835 }
1836
1837 if( CompareToken( "MM", token ) )
1838 {
1840 }
1841 else if( CompareToken( "THOU", token ) )
1842 {
1844 }
1845 else if( ( m_idfVer == IDF_VERSION::IDF_V2 ) && CompareToken( "TNM", token ) )
1846 {
1848 }
1849 else
1850 {
1851 ostringstream ostr;
1852
1853 ostr << "invalid IDF file\n";
1854 ostr << "* HEADER section, RECORD 3, FIELD 2: expecting MM or THOU (got '" << token <<
1855 "')\n";
1856
1857 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1858 }
1859
1860 m_boardOutline.SetUnit( m_unit );
1861
1862 // RECORD 4:
1863 // .END_HEADER
1864 while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() );
1865
1866 if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() )
1867 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "problems reading board header, RECORD 4" ) );
1868
1869 if( isComment )
1870 {
1871 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1872 "invalid IDF file\n"
1873 "* Violation of specification: comment within .HEADER section\n" ) );
1874 }
1875
1876 if( !CompareToken( ".END_HEADER", iline ) )
1877 {
1878 ostringstream ostr;
1879
1880 ostr << "invalid IDF file\n";
1881 ostr << "* Violation of specification: expected .END_HEADER\n";
1882 ostr << "* line: '" << iline << "'";
1883
1884 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1885 }
1886
1887 aBoardState = FILE_STATE::FILE_HEADER;
1888}
1889
1890
1891void IDF3_BOARD::readBrdSection( std::istream& aBoardFile, FILE_STATE& aBoardState,
1892 bool aNoSubstituteOutlines )
1893{
1894 std::list< std::string > comments; // comments associated with a section
1895
1896 // Reads in .SECTION_ID or #COMMENTS
1897 // Expected SECTION IDs:
1898 // .BOARD_OUTLINE
1899 // .PANEL_OUTLINE (NOT SUPPORTED)
1900 // .OTHER_OUTLINE
1901 // .ROUTE_OUTLINE
1902 // .PLACE_OUTLINE
1903 // .ROUTE_KEEPOUT
1904 // .VIA_KEEPOUT
1905 // .PLACE_KEEPOUT
1906 // .PLACE_REGION
1907 // .DRILLED_HOLES
1908 // .NOTES
1909 // .PLACEMENT
1910 std::string iline; // the input line
1911 bool isComment; // true if a line just read in is a comment line
1912 std::streampos pos;
1913 int idx = 0;
1914 bool quoted = false;
1915 std::string token;
1916
1917 while( aBoardFile.good() )
1918 {
1919 while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() );
1920
1921 if( !aBoardFile.good() )
1922 {
1923 if( aBoardFile.eof() && aBoardState >= FILE_STATE::FILE_HEADER &&
1924 aBoardState < FILE_STATE::FILE_INVALID )
1925 {
1926 if( !comments.empty() )
1927 ERROR_IDF << "[warning]: trailing comments in IDF file (comments will be lost)\n";
1928
1929 return;
1930 }
1931
1932 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1933 "problems reading board section" ) );
1934 }
1935
1936 if( isComment )
1937 {
1938 comments.push_back( iline );
1939 continue;
1940 }
1941
1942 // This must be a header
1943 GetIDFString( iline, token, quoted, idx );
1944
1945 if( quoted )
1946 {
1947 ostringstream ostr;
1948
1949 ostr << "invalid IDF file\n";
1950 ostr << "* Violation of specification: quoted string where SECTION HEADER expected\n";
1951 ostr << "* line: '" << iline << "'";
1952 ostr << "* position: " << pos;
1953
1954 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1955 }
1956
1957 if( CompareToken( ".BOARD_OUTLINE", token ) )
1958 {
1959 if( aBoardState != FILE_STATE::FILE_HEADER )
1960 {
1961 aBoardState = FILE_STATE::FILE_INVALID;
1962 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1963 "invalid IDF file\n"
1964 "* Violation of specification: no HEADER section" ) );
1965 }
1966
1967 m_boardOutline.readData( aBoardFile, iline, m_idfVer );
1968
1969 if( !comments.empty() )
1970 {
1971 std::list<std::string>::iterator its = comments.begin();
1972 std::list<std::string>::iterator ite = comments.end();
1973
1974 while( its != ite )
1975 {
1976 m_boardOutline.AddComment( *its );
1977 ++its;
1978 }
1979 }
1980
1981 aBoardState = FILE_STATE::FILE_OUTLINE;
1982 return;
1983 }
1984
1985 if( CompareToken( ".PANEL_OUTLINE", token ) )
1986 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "PANEL_OUTLINE not supported" ) );
1987
1988 if( CompareToken( ".OTHER_OUTLINE", token ) )
1989 {
1990 if( aBoardState != FILE_STATE::FILE_OUTLINE )
1991 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1992 "invalid IDF file\n"
1993 "* Violation of specification: expecting .BOARD_OUTLINE, have .OTHER_OUTLINE" ) );
1994
1995 OTHER_OUTLINE* op = nullptr;
1996
1997 try
1998 {
1999 op = new OTHER_OUTLINE( this );
2000 }
2001 catch( std::bad_alloc& )
2002 {
2003 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2004 "could not create OTHER_OUTLINE object" ) );
2005 }
2006
2007 if( op == nullptr )
2008
2009 op->SetUnit( m_unit );
2010 op->readData( aBoardFile, iline, m_idfVer );
2011
2012 if( !comments.empty() )
2013 {
2014 std::list<std::string>::iterator its = comments.begin();
2015 std::list<std::string>::iterator ite = comments.end();
2016
2017 while( its != ite )
2018 {
2019 op->AddComment( *its );
2020 ++its;
2021 }
2022 }
2023
2024 if( m_otherOutlines.emplace( op->GetOutlineIdentifier(), op ).second == false )
2025 {
2026 ostringstream ostr;
2027 ostr << "invalid IDF file\n";
2028 ostr << "* Violation of specification. Non-unique ID in OTHER_OUTLINE '";
2029 ostr << op->GetOutlineIdentifier() << "'\n";
2030 ostr << "* line: '" << iline << "'\n";
2031 ostr << "* pos: " << pos;
2032 delete op;
2033
2034 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2035 }
2036
2037 return;
2038 }
2039
2040 if( CompareToken( ".ROUTE_OUTLINE", token ) )
2041 {
2042 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2043 {
2044 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2045 "invalid IDF file\n"
2046 "* Violation of specification: expecting .BOARD_OUTLINE, have .ROUTE_OUTLINE" ) );
2047 }
2048
2049 ROUTE_OUTLINE* op = nullptr;
2050
2051 try
2052 {
2053 op = new ROUTE_OUTLINE( this );
2054 }
2055 catch( std::bad_alloc& )
2056 {
2057 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2058 "could not create ROUTE_OUTLINE object" ) );
2059 }
2060
2061 op->SetUnit( m_unit );
2062 op->readData( aBoardFile, iline, m_idfVer );
2063
2064 if( !comments.empty() )
2065 {
2066 std::list<std::string>::iterator its = comments.begin();
2067 std::list<std::string>::iterator ite = comments.end();
2068
2069 while( its != ite )
2070 {
2071 op->AddComment( *its );
2072 ++its;
2073 }
2074 }
2075
2076 m_routeOutlines.push_back( op );
2077
2078 return;
2079 }
2080
2081 if( CompareToken( ".PLACE_OUTLINE", token ) )
2082 {
2083 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2084 {
2085 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2086 "invalid IDF file\n"
2087 "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_OUTLINE" ) );
2088 }
2089
2090 PLACE_OUTLINE* op = nullptr;
2091
2092 try
2093 {
2094 op = new PLACE_OUTLINE( this );
2095 }
2096 catch( std::bad_alloc& )
2097 {
2098 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2099 "could not create PLACE_OUTLINE object" ) );
2100 }
2101
2102 op->SetUnit( m_unit );
2103 op->readData( aBoardFile, iline, m_idfVer );
2104
2105 if( !comments.empty() )
2106 {
2107 std::list<std::string>::iterator its = comments.begin();
2108 std::list<std::string>::iterator ite = comments.end();
2109
2110 while( its != ite )
2111 {
2112 op->AddComment( *its );
2113 ++its;
2114 }
2115 }
2116
2117 m_placeOutlines.push_back( op );
2118
2119 return;
2120 }
2121
2122 if( CompareToken( ".ROUTE_KEEPOUT", token ) )
2123 {
2124 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2125 {
2126 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2127 "invalid IDF file\n"
2128 "* Violation of specification: expecting .BOARD_OUTLINE, have .ROUTE_KEEPOUT" ) );
2129 }
2130
2131 ROUTE_KO_OUTLINE* op = nullptr;
2132
2133 try
2134 {
2135 op = new ROUTE_KO_OUTLINE( this );
2136 }
2137 catch( std::bad_alloc& )
2138 {
2139 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2140 "could not create ROUTE_KEEPOUT object" ) );
2141 }
2142
2143 op->SetUnit( m_unit );
2144 op->readData( aBoardFile, iline, m_idfVer );
2145
2146 if( !comments.empty() )
2147 {
2148 std::list<std::string>::iterator its = comments.begin();
2149 std::list<std::string>::iterator ite = comments.end();
2150
2151 while( its != ite )
2152 {
2153 op->AddComment( *its );
2154 ++its;
2155 }
2156 }
2157
2158 m_routeKeepoutOutlines.push_back( op );
2159
2160 return;
2161 }
2162
2163 if( CompareToken( ".VIA_KEEPOUT", token ) )
2164 {
2165 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2166 {
2167 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2168 "invalid IDF file\n"
2169 "* Violation of specification: expecting .BOARD_OUTLINE, have .VIA_KEEPOUT" ) );
2170 }
2171
2172 VIA_KO_OUTLINE* op = nullptr;
2173
2174 try
2175 {
2176 op = new VIA_KO_OUTLINE( this );
2177 }
2178 catch( std::bad_alloc& )
2179 {
2180 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "could not create VIA_KEEPOUT object" ) );
2181 }
2182
2183 op->SetUnit( m_unit );
2184 op->readData( aBoardFile, iline, m_idfVer );
2185
2186 if( !comments.empty() )
2187 {
2188 std::list<std::string>::iterator its = comments.begin();
2189 std::list<std::string>::iterator ite = comments.end();
2190
2191 while( its != ite )
2192 {
2193 op->AddComment( *its );
2194 ++its;
2195 }
2196 }
2197
2198 m_viaKeepoutOutlines.push_back( op );
2199
2200 return;
2201 }
2202
2203 if( CompareToken( ".PLACE_KEEPOUT", token ) )
2204 {
2205 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2206 {
2207 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2208 "invalid IDF file\n"
2209 "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_KEEPOUT" ) );
2210 }
2211
2212 PLACE_KO_OUTLINE* op = nullptr;
2213 try
2214 {
2215 op = new PLACE_KO_OUTLINE( this );
2216 }
2217 catch( std::bad_alloc& )
2218 {
2219 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "could not create PLACE_KEEPOUT object" ) );
2220 }
2221
2222 op->SetUnit( m_unit );
2223 op->readData( aBoardFile, iline, m_idfVer );
2224
2225 if( !comments.empty() )
2226 {
2227 std::list<std::string>::iterator its = comments.begin();
2228 std::list<std::string>::iterator ite = comments.end();
2229
2230 while( its != ite )
2231 {
2232 op->AddComment( *its );
2233 ++its;
2234 }
2235 }
2236
2237 m_placeKeepoutOutlines.push_back( op );
2238
2239 return;
2240 }
2241
2242 if( CompareToken( ".PLACE_REGION", token ) )
2243 {
2244 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2245 {
2246 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2247 "invalid IDF file\n"
2248 "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_REGION" ) );
2249 }
2250
2251 GROUP_OUTLINE* op = nullptr;
2252
2253 try
2254 {
2255 op = new GROUP_OUTLINE( this );
2256 }
2257 catch( std::bad_alloc& )
2258 {
2259 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "could not create PLACE_REGION object" ) );
2260 }
2261
2262 op->SetUnit( m_unit );
2263 op->readData( aBoardFile, iline, m_idfVer );
2264
2265 if( !comments.empty() )
2266 {
2267 std::list<std::string>::iterator its = comments.begin();
2268 std::list<std::string>::iterator ite = comments.end();
2269
2270 while( its != ite )
2271 {
2272 op->AddComment( *its );
2273 ++its;
2274 }
2275 }
2276
2277 m_groupOutlines.emplace( op->GetGroupName(), op );
2278
2279 return;
2280 }
2281
2282 if( CompareToken( ".DRILLED_HOLES", token ) )
2283 {
2284 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2285 {
2286 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2287 "invalid IDF file\n"
2288 "* Violation of specification: expecting .BOARD_OUTLINE, have .DRILLED_HOLES" ) );
2289 }
2290
2291 readBrdDrills( aBoardFile, aBoardState );
2292
2293 if( !comments.empty() )
2294 {
2295 std::list<std::string>::iterator its = comments.begin();
2296 std::list<std::string>::iterator ite = comments.end();
2297
2298 while( its != ite )
2299 {
2300 m_drillComments.push_back( *its );
2301 ++its;
2302 }
2303 }
2304
2305 return;
2306 }
2307
2308 if( CompareToken( ".NOTES", token ) )
2309 {
2310 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2311 {
2312 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2313 "invalid IDF file\n"
2314 "* Violation of specification: expecting .BOARD_OUTLINE, have .NOTES" ) );
2315 }
2316
2318 {
2319 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2320 "invalid IDFv2 file\n"
2321 "* Violation of specification: NOTES section not in specification" ) );
2322 }
2323
2324 readBrdNotes( aBoardFile, aBoardState );
2325
2326 if( !comments.empty() )
2327 {
2328 std::list<std::string>::iterator its = comments.begin();
2329 std::list<std::string>::iterator ite = comments.end();
2330
2331 while( its != ite )
2332 {
2333 m_noteComments.push_back( *its );
2334 ++its;
2335 }
2336 }
2337
2338 return;
2339 }
2340
2341 if( CompareToken( ".PLACEMENT", token ) )
2342 {
2343 if( aBoardState != FILE_STATE::FILE_OUTLINE )
2344 {
2345 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2346 "invalid IDF file\n"
2347 "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACEMENT" ) );
2348 }
2349
2350 readBrdPlacement( aBoardFile, aBoardState, aNoSubstituteOutlines );
2351
2352 if( !comments.empty() )
2353 {
2354 std::list<std::string>::iterator its = comments.begin();
2355 std::list<std::string>::iterator ite = comments.end();
2356
2357 while( its != ite )
2358 {
2359 m_placeComments.push_back( *its );
2360 ++its;
2361 }
2362 }
2363
2364 return;
2365 }
2366 }
2367}
2368
2369
2370void IDF3_BOARD::readBoardFile( const std::string& aFileName, bool aNoSubstituteOutlines )
2371{
2372 OPEN_ISTREAM( brd, aFileName.c_str() );
2373
2374 try
2375 {
2376 brd.exceptions ( std::ios_base::badbit );
2377
2378 if( brd.fail() )
2379 {
2380 ostringstream ostr;
2381 ostr << "\n* could not open file: '" << aFileName << "'";
2382
2383 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2384 }
2385
2386 brd.imbue( std::locale( "C" ) );
2387 std::string iline; // the input line
2388 bool isComment; // true if a line just read in is a comment line
2389 std::streampos pos;
2391
2392 // note: as per IDFv3 specification:
2393 // "The Header section must be the first section in the file, the second
2394 // section must be the Outline section, and the last section must be the
2395 // Placement section. All other sections may be in any order."
2396
2397 // further notes: Except for the HEADER section, sections may be preceded by
2398 // comment lines which will be copied back out on write(). No comments may
2399 // be associated with the board file itself since the only logical location
2400 // for unambiguous association is at the end of the file, which is inconvenient
2401 // for large files.
2402
2403 readBrdHeader( brd, state );
2404
2405 // read the various sections
2406 while( state != FILE_STATE::FILE_PLACEMENT && brd.good() )
2407 readBrdSection( brd, state, aNoSubstituteOutlines );
2408
2409 if( !brd.good() )
2410 {
2411 // check if we have valid data
2412 if( brd.eof() && state >= FILE_STATE::FILE_OUTLINE && state < FILE_STATE::FILE_INVALID )
2413 {
2414 CLOSE_STREAM( brd );
2415 return;
2416 }
2417
2418 CLOSE_STREAM( brd );
2419 ostringstream ostr;
2420 ostr << "\n* empty IDF file: '" << aFileName << "'";
2421
2422 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2423 }
2424
2425 if( brd.good() && state == FILE_STATE::FILE_PLACEMENT )
2426 {
2427 // read in any trailing lines and report on ignored comments (minor fault)
2428 // and any non-comment item (non-compliance with IDFv3)
2429 while( brd.good() )
2430 {
2431 while( !FetchIDFLine( brd, iline, isComment, pos ) && brd.good() );
2432
2433 // normally this is a fault but we have all the data in accordance with specs
2434 if( ( !brd.good() && !brd.eof() ) || iline.empty() )
2435 break;
2436
2437 if( isComment )
2438 {
2439 ERROR_IDF << "[warning]: trailing comments after PLACEMENT\n";
2440 }
2441 else
2442 {
2443 ostringstream ostr;
2444 ostr << "\n* problems reading file: '" << aFileName << "'";
2445
2446 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2447 "invalid IDF file\n"
2448 "* Violation of specification: non-comment lines after PLACEMENT section" ) );
2449 }
2450 }
2451 }
2452 }
2453 catch( const std::exception& )
2454 {
2455 brd.exceptions ( std::ios_base::goodbit );
2456 CLOSE_STREAM( brd );
2457 throw;
2458 }
2459
2460 CLOSE_STREAM( brd );
2461}
2462
2463
2464void IDF3_BOARD::readLibSection( std::istream& aLibFile, FILE_STATE& aLibState,
2465 IDF3_BOARD* aBoard )
2466{
2467 if( aBoard == nullptr )
2468 {
2469 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2470 "\n* BUG: invoked with nullptr reference aBoard" ) );
2471 }
2472
2473 std::list< std::string > comments; // comments associated with a section
2474
2475 // Reads in .ELECTRICAL, .MECHANICAL or #COMMENTS
2476 std::string iline; // the input line
2477 bool isComment; // true if a line just read in is a comment line
2478 std::streampos pos;
2479 int idx = 0;
2480 bool quoted = false;
2481 std::string token;
2482 IDF3_COMP_OUTLINE* pout = nullptr;
2483
2484 try
2485 {
2486 pout = new IDF3_COMP_OUTLINE( this );
2487 }
2488 catch( std::bad_alloc& )
2489 {
2490 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "\n* memory allocation failure" ) );
2491 }
2492
2493 while( aLibFile.good() )
2494 {
2495 while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() );
2496
2497 if( !aLibFile.good() && !aLibFile.eof() )
2498 {
2499 delete pout;
2500 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "problems reading library section" ) );
2501 }
2502
2503 // no data was read; this only happens at eof()
2504 if( iline.empty() )
2505 {
2506 delete pout;
2507 return;
2508 }
2509
2510 if( isComment )
2511 {
2512 comments.push_back( iline );
2513 continue;
2514 }
2515
2516 // This must be a header
2517 GetIDFString( iline, token, quoted, idx );
2518
2519 if( quoted )
2520 {
2521 ostringstream ostr;
2522 ostr << "invalid IDF library\n";
2523 ostr << "* Violation of specification: quoted string where .ELECTRICAL or .MECHANICAL expected\n";
2524 ostr << "* line: '" << iline << "'\n";
2525 ostr << "* pos: " << pos;
2526 delete pout;
2527
2528 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2529 }
2530
2531 if( CompareToken( ".ELECTRICAL", token ) || CompareToken( ".MECHANICAL", token ) )
2532 {
2533 pout->readData( aLibFile, token, m_idfVer );
2534
2535 if( !comments.empty() )
2536 {
2537 std::list<std::string>::iterator its = comments.begin();
2538 std::list<std::string>::iterator ite = comments.end();
2539
2540 while( its != ite )
2541 {
2542 pout->AddComment( *its );
2543 ++its;
2544 }
2545 }
2546
2547 IDF3_COMP_OUTLINE* cop = aBoard->GetComponentOutline( pout->GetUID() );
2548
2549 if( cop == nullptr )
2550 {
2551 m_componentOutlines.emplace( pout->GetUID(), pout );
2552 }
2553 else
2554 {
2555 if( MatchCompOutline( pout, cop ) )
2556 {
2557 delete pout;
2558 // everything is fine; the outlines are genuine duplicates
2559 return;
2560 }
2561
2562 ostringstream ostr;
2563 ostr << "invalid IDF library\n";
2564 ostr << "duplicate Component Outline: '" << pout->GetUID() << "'\n";
2565 ostr << "* Violation of specification: multiple outlines have the same GEOM and PART name\n";
2566 ostr << "* line: '" << iline << "'\n";
2567 ostr << "* pos: " << pos;
2568 delete pout;
2569
2570 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2571 }
2572
2573 return;
2574 }
2575 else
2576 {
2577 ostringstream ostr;
2578 ostr << "invalid IDF library\n";
2579 ostr << "* Expecting .ELECTRICAL or .MECHANICAL, got '" << token << "'\n";
2580 ostr << "* line: '" << iline << "'\n";
2581 ostr << "* pos: " << pos;
2582 delete pout;
2583
2584 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2585 }
2586 }
2587
2588 delete pout;
2589
2590 if( !aLibFile.eof() )
2591 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "problems reading IDF library file" ) );
2592}
2593
2594
2595// read the library HEADER
2596void IDF3_BOARD::readLibHeader( std::istream& aLibFile, FILE_STATE& aLibState )
2597{
2598 std::string iline; // the input line
2599 bool isComment; // true if a line just read in is a comment line
2600 std::streampos pos;
2601 int idx = 0;
2602 bool quoted = false;
2603 std::string token;
2604
2605 // RECORD 1: ".HEADER" must be the very first line
2606 while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() );
2607
2608 if( !aLibFile.good() )
2609 {
2610 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2611 "invalid IDF library file\n"
2612 "* premature end of file (no HEADER)" ) );
2613 }
2614
2615 if( isComment )
2616 {
2617 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2618 "invalid IDF library file\n"
2619 "* Violation of specification: first line must be .HEADER" ) );
2620 }
2621
2622 if( !CompareToken( ".HEADER", iline ) )
2623 {
2624 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2625 "invalid IDF library file\n"
2626 "* Violation of specification:\n"
2627 "* first line must be .HEADER and have no quotes or trailing text" ) );
2628 }
2629
2630 // RECORD 2:
2631 // File Type [str]: LIBRARY_FILE
2632 // IDF Version Number [float]: must be 3.0
2633 // Source System [str]: ignored
2634 // Date [str]: ignored
2635 // Library File Version [int]: ignored
2636 while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() );
2637
2638 if( !aLibFile.good() )
2639 {
2640 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2641 "invalid IDF library file\n"
2642 "* premature end of HEADER" ) );
2643 }
2644
2645 if( isComment )
2646 {
2647 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2648 "invalid IDF library file\n"
2649 "* Violation of specification: comment within .HEADER section" ) );
2650 }
2651
2652 idx = 0;
2653 GetIDFString( iline, token, quoted, idx );
2654
2655 if( quoted )
2656 {
2657 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2658 "invalid IDF library file\n"
2659 "* Violation of specification:\n"
2660 "* file Type in HEADER section must not be in quotes" ) );
2661 }
2662
2663 if( !CompareToken( "LIBRARY_FILE", token ) )
2664 {
2665 ostringstream ostr;
2666 ostr << "invalid IDF library\n";
2667 ostr << "* Expecting string: LIBRARY_FILE (got '" << token << "')\n";
2668
2669 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2670 }
2671
2672 if( !GetIDFString( iline, token, quoted, idx ) )
2673 {
2674 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2675 "invalid IDF library file\n"
2676 "* Violation of specification: HEADER section, RECORD 2: no FIELD 2" ) );
2677 }
2678
2679 if( quoted )
2680 {
2681 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2682 "invalid IDF library file\n"
2683 "* Violation of specification: IDF Version must not be in quotes" ) );
2684 }
2685
2686 if( !token.compare( "3.0" ) || !token.compare( "3." ) || !token.compare( "3" ) )
2687 {
2689 }
2690 else if( !token.compare( "2.0" ) || !token.compare( "2." ) || !token.compare( "2" ) )
2691 {
2693 }
2694 else
2695 {
2696 ostringstream ostr;
2697
2698 ostr << "unsupported IDF version\n";
2699 ostr << "* Expecting version to be a variant of '3.0', '2.0' (value: '" << token << "')\n";
2700
2701 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2702 }
2703
2704 if( !GetIDFString( iline, token, quoted, idx ) )
2705 {
2706 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2707 "invalid IDF library file\n"
2708 "* Violation of specification:\n"
2709 "* HEADER section, RECORD 2, FIELD 3: no Source System string" ) );
2710 }
2711
2712 m_libSource = token;
2713
2714 if( !GetIDFString( iline, token, quoted, idx ) )
2715 {
2716 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2717 "invalid IDF library file\n"
2718 "* Violation of specification:\n"
2719 "* HEADER section, RECORD 2, FIELD 4: no Date string" ) );
2720 }
2721
2722 m_libDate = token;
2723
2724 if( !GetIDFString( iline, token, quoted, idx ) )
2725 {
2726 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2727 "invalid IDF library file\n"
2728 "* Violation of specification:\n"
2729 "* HEADER section, RECORD 2, FIELD 5: no Board File Version number" ) );
2730 }
2731
2732 std::istringstream istr;
2733 istr.str( token );
2734
2735 istr >> m_libFileVersion;
2736
2737 if( istr.fail() )
2738 {
2739 ERROR_IDF << "invalid Library File Version in header\n";
2740 cerr << "* Setting default version of 1\n";
2741 m_libFileVersion = 1;
2742 }
2743
2744 if( quoted )
2745 {
2746 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2747 "invalid IDF library file\n"
2748 "* Violation of specification:\n"
2749 "* HEADER section, RECORD 2, FIELD 5: Library File Version must not be in quotes" ) );
2750 }
2751
2752 // RECORD 3:
2753 // .END_HEADER
2754 while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() );
2755
2756 if( ( !aLibFile.good() && !aLibFile.eof() ) || iline.empty() )
2757 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "problems reading library header, RECORD 3" ) );
2758
2759 if( isComment )
2760 {
2761 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2762 "invalid IDF library file\n"
2763 "* Violation of specification: comment within .HEADER section" ) );
2764 }
2765
2766 if( !CompareToken( ".END_HEADER", iline ) )
2767 {
2768 ostringstream ostr;
2769 ostr << "invalid IDF header\n";
2770 ostr << "* Violation of specification: expected .END_HEADER (got '" << iline << "')\n";
2771
2772 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2773 }
2774
2775 aLibState = FILE_STATE::FILE_HEADER;
2776}
2777
2778
2779void IDF3_BOARD::readLibFile( const std::string& aFileName )
2780{
2781 OPEN_ISTREAM( lib, aFileName.c_str() );
2782
2783 try
2784 {
2785 lib.exceptions ( std::ios_base::badbit );
2786
2787 if( lib.fail() )
2788 {
2789 ostringstream ostr;
2790 ostr << "\n* could not open file: '" << aFileName << "'";
2791
2792 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2793 }
2794
2795 lib.imbue( std::locale( "C" ) );
2797
2798 readLibHeader( lib, state );
2799
2800 while( lib.good() ) readLibSection( lib, state, this );
2801 }
2802 catch( const std::exception& )
2803 {
2804 lib.exceptions ( std::ios_base::goodbit );
2805 CLOSE_STREAM( lib );
2806 throw;
2807 }
2808
2809 CLOSE_STREAM( lib );
2810}
2811
2812
2813bool IDF3_BOARD::ReadFile( const wxString& aFullFileName, bool aNoSubstituteOutlines )
2814{
2815 // 1. Check that the file extension is 'emn'
2816 // 2. Check if a file with extension 'emp' exists and read it
2817 // 3. Open the specified filename and read it
2818
2819 wxFileName brdname( aFullFileName );
2820 wxFileName libname( aFullFileName );
2821 wxString ext = brdname.GetExt();
2822
2823 if( !ext.Cmp( wxT( "EMN" ) ) )
2824 {
2825 libname.SetExt( wxT( "EMP" ) );
2826 }
2827 else if( !ext.Cmp( wxT( "emn" ) ) )
2828 {
2829 libname.SetExt( wxT( "emp" ) );
2830 }
2831 else
2832 {
2833 ostringstream ostr;
2834 ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
2835 ostr << "* [INFO] invalid file name: '" << aFullFileName.ToUTF8() << "'";
2836
2837 m_errormsg = ostr.str();
2838 }
2839
2840
2841 brdname.SetExt( wxT( "emn" ) );
2842
2843 std::string bfname = TO_UTF8( aFullFileName );
2844
2845 if( !wxFileExists( bfname ) )
2846 {
2847 brdname.SetExt( wxT( "EMN" ) );
2848 libname.SetExt( wxT( "EMP" ) );
2849 }
2850
2851 try
2852 {
2853 if( !brdname.IsOk() )
2854 {
2855 ostringstream ostr;
2856 ostr << "\n* invalid file name: '" << aFullFileName.ToUTF8() << "'";
2857
2858 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2859 }
2860
2861 if( !brdname.FileExists() )
2862 {
2863 ostringstream ostr;
2864 ostr << "\n* no such file: '" << aFullFileName.ToUTF8() << "'";
2865
2866 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2867 }
2868
2869 if( !brdname.IsFileReadable() )
2870 {
2871 ostringstream ostr;
2872 ostr << "\n* cannot read file: '" << bfname << "'";
2873
2874 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2875 }
2876
2877 bfname = TO_UTF8( brdname.GetFullPath() );
2878 std::string lfname = TO_UTF8( libname.GetFullPath() );
2879
2880 if( !libname.FileExists() )
2881 {
2882 // NOTE: Since this is a common case we simply proceed
2883 // with the assumption that there is no library file;
2884 // however we print a message to inform the user.
2885 ERROR_IDF;
2886 cerr << "no associated library file (*.emp)\n";
2887 }
2888 else if( !libname.IsFileReadable() )
2889 {
2890 ostringstream ostr;
2891 ostr << "\n* cannot read library file: '" << lfname << "'";
2892
2893 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2894 }
2895 else
2896 {
2897 // read the library file before proceeding
2898 readLibFile( lfname );
2899 }
2900
2901 // read the board file
2902 readBoardFile( bfname, aNoSubstituteOutlines );
2903 }
2904 catch( const std::exception& e )
2905 {
2906 Clear();
2907 m_errormsg = e.what();
2908
2909 return false;
2910 }
2911
2912 return true;
2913}
2914
2915
2916bool IDF3_BOARD::writeLibFile( const std::string& aFileName )
2917{
2918 OPEN_OSTREAM( lib, aFileName.c_str() );
2919
2920 try
2921 {
2922 lib.exceptions( std::ios_base::failbit );
2923
2924 if( lib.fail() )
2925 {
2926 ostringstream ostr;
2927 ostr << "\n* could not open file: '" << aFileName << "'";
2928
2929 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2930 }
2931
2932 lib.imbue( std::locale( "C" ) );
2933 wxDateTime tdate( time( nullptr ) );
2934
2935 if( m_idfSource.empty() )
2936 m_idfSource = "KiCad-IDF Framework";
2937
2938 ostringstream fileDate;
2939 fileDate << setfill( '0' ) << setw(4) << tdate.GetYear();
2940 fileDate << "/" << setw(2) << tdate.GetMonth() << "/" << tdate.GetDay();
2941 fileDate << "." << tdate.GetHour() << ":" << tdate.GetMinute() << ":" << tdate.GetSecond();
2942 m_libDate = fileDate.str();
2943
2944 lib << ".HEADER\n";
2945 lib << "LIBRARY_FILE 3.0 \"Created by " << m_idfSource;
2946 lib << "\" " << m_libDate << " " << (++m_libFileVersion ) << "\n";
2947 lib << ".END_HEADER\n\n";
2948
2949 std::map<std::string, IDF3_COMP_OUTLINE*>::iterator its = m_componentOutlines.begin();
2950 std::map<std::string, IDF3_COMP_OUTLINE*>::iterator ite = m_componentOutlines.end();
2951
2952 while( its != ite )
2953 {
2954 its->second->writeData( lib );
2955 ++its;
2956 }
2957
2958 }
2959 catch( const std::exception& )
2960 {
2961 lib.exceptions( std::ios_base::goodbit );
2962 CLOSE_STREAM( lib );
2963 throw;
2964 }
2965
2966 CLOSE_STREAM( lib );
2967 return true;
2968}
2969
2970
2971void IDF3_BOARD::writeBoardFile( const std::string& aFileName )
2972{
2973 OPEN_OSTREAM( brd, aFileName.c_str() );
2974
2975 try
2976 {
2977 brd.exceptions( std::ostream::failbit );
2978
2979 if( brd.fail() )
2980 {
2981 ostringstream ostr;
2982 ostr << "\n* could not open file: '" << aFileName << "'";
2983
2984 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2985 }
2986
2987 brd.imbue( std::locale( "C" ) );
2988 wxDateTime tdate( time( nullptr ) );
2989
2990 if( m_idfSource.empty() )
2991 m_idfSource = "KiCad-IDF Framework";
2992
2993 ostringstream fileDate;
2994 fileDate << setfill( '0' ) << setw(4) << tdate.GetYear();
2995 fileDate << "/" << setw(2) << tdate.GetMonth() << "/" << tdate.GetDay();
2996 fileDate << "." << tdate.GetHour() << ":" << tdate.GetMinute() << ":" << tdate.GetSecond();
2997 m_brdDate = fileDate.str();
2998
2999 brd << ".HEADER\n";
3000 brd << "BOARD_FILE 3.0 \"Created by " << m_idfSource;
3001 brd << "\" " << m_brdDate << " " << (++m_brdFileVersion ) << "\n";
3002
3003 if( m_boardName.empty() )
3004 brd << "\"BOARD WITH NO NAME\" ";
3005 else
3006 brd << "\"" << m_boardName << "\" ";
3007
3008 brd << setw(1) << setfill( ' ' );
3009
3011 brd << "MM\n";
3012 else
3013 brd << "THOU\n";
3014
3015 brd << ".END_HEADER\n\n";
3016
3017 // write the BOARD_OUTLINE
3018 m_boardOutline.writeData( brd );
3019
3020 // OTHER outlines
3021 do
3022 {
3023 std::map<std::string, OTHER_OUTLINE*>::iterator its = m_otherOutlines.begin();
3024 std::map<std::string, OTHER_OUTLINE*>::iterator ite = m_otherOutlines.end();
3025
3026 while(its != ite )
3027 {
3028 its->second->writeData( brd );
3029 ++its;
3030 }
3031
3032 } while( 0 );
3033
3034 // ROUTE outlines
3035 do
3036 {
3037 std::list<ROUTE_OUTLINE*>::iterator its = m_routeOutlines.begin();
3038 std::list<ROUTE_OUTLINE*>::iterator ite = m_routeOutlines.end();
3039
3040 while( its != ite )
3041 {
3042 (*its)->writeData( brd );
3043 ++its;
3044 }
3045
3046 } while( 0 );
3047
3048 // PLACEMENT outlines
3049 do
3050 {
3051 std::list<PLACE_OUTLINE*>::iterator its = m_placeOutlines.begin();
3052 std::list<PLACE_OUTLINE*>::iterator ite = m_placeOutlines.end();
3053
3054 while( its != ite )
3055 {
3056 (*its)->writeData( brd );
3057 ++its;
3058 }
3059
3060 } while( 0 );
3061
3062 // ROUTE KEEPOUT outlines
3063 do
3064 {
3065 std::list<ROUTE_KO_OUTLINE*>::iterator its = m_routeKeepoutOutlines.begin();
3066 std::list<ROUTE_KO_OUTLINE*>::iterator ite = m_routeKeepoutOutlines.end();
3067
3068 while( its != ite )
3069 {
3070 (*its)->writeData( brd );
3071 ++its;
3072 }
3073
3074 } while( 0 );
3075
3076 // VIA KEEPOUT outlines
3077 do
3078 {
3079 std::list<VIA_KO_OUTLINE*>::iterator its = m_viaKeepoutOutlines.begin();
3080 std::list<VIA_KO_OUTLINE*>::iterator ite = m_viaKeepoutOutlines.end();
3081
3082 while( its != ite )
3083 {
3084 (*its)->writeData( brd );
3085 ++its;
3086 }
3087
3088 } while( 0 );
3089
3090 // PLACE KEEPOUT outlines
3091 do
3092 {
3093 std::list<PLACE_KO_OUTLINE*>::iterator its = m_placeKeepoutOutlines.begin();
3094 std::list<PLACE_KO_OUTLINE*>::iterator ite = m_placeKeepoutOutlines.end();
3095
3096 while( its != ite )
3097 {
3098 (*its)->writeData( brd );
3099 ++its;
3100 }
3101
3102 } while( 0 );
3103
3104 // PLACEMENT GROUP outlines
3105 do
3106 {
3107 std::multimap<std::string, GROUP_OUTLINE*>::iterator its = m_groupOutlines.begin();
3108 std::multimap<std::string, GROUP_OUTLINE*>::iterator ite = m_groupOutlines.end();
3109
3110 while( its != ite )
3111 {
3112 its->second->writeData( brd );
3113 ++its;
3114 }
3115
3116 } while( 0 );
3117
3118 // Drilled holes
3119 do
3120 {
3121 std::list<std::string>::iterator itds = m_drillComments.begin();
3122 std::list<std::string>::iterator itde = m_drillComments.end();
3123
3124 while( itds != itde )
3125 {
3126 brd << "# " << *itds << "\n";
3127 ++itds;
3128 }
3129
3130 brd << ".DRILLED_HOLES\n";
3131
3132 std::list<IDF_DRILL_DATA*>::iterator itbs = m_drills.begin();
3133 std::list<IDF_DRILL_DATA*>::iterator itbe = m_drills.end();
3134
3135 while( itbs != itbe )
3136 {
3137 (*itbs)->write( brd, m_unit );
3138 ++itbs;
3139 }
3140
3141 std::map<std::string, IDF3_COMPONENT*>::iterator itcs = m_components.begin();
3142 std::map<std::string, IDF3_COMPONENT*>::iterator itce = m_components.end();
3143
3144 while( itcs != itce )
3145 {
3146 itcs->second->writeDrillData( brd );
3147 ++itcs;
3148 }
3149
3150 brd << ".END_DRILLED_HOLES\n\n";
3151 } while( 0 );
3152
3153 // Notes
3154 if( !m_notes.empty() )
3155 {
3156 std::list<std::string>::iterator itncs = m_noteComments.begin();
3157 std::list<std::string>::iterator itnce = m_noteComments.end();
3158
3159 while( itncs != itnce )
3160 {
3161 brd << "# " << *itncs << "\n";
3162 ++itncs;
3163 }
3164
3165 brd << ".NOTES\n";
3166
3167 std::list<IDF_NOTE*>::iterator itns = m_notes.begin();
3168 std::list<IDF_NOTE*>::iterator itne = m_notes.end();
3169
3170 while( itns != itne )
3171 {
3172 (*itns)->writeNote( brd, m_unit );
3173 ++itns;
3174 }
3175
3176 brd << ".END_NOTES\n\n";
3177
3178 }
3179
3180 // Placement
3181 if( !m_components.empty() )
3182 {
3183 std::list<std::string>::iterator itpcs = m_placeComments.begin();
3184 std::list<std::string>::iterator itpce = m_placeComments.end();
3185
3186 while( itpcs != itpce )
3187 {
3188 brd << "# " << *itpcs << "\n";
3189 ++itpcs;
3190 }
3191
3192 std::map< std::string, IDF3_COMPONENT*>::iterator itcs = m_components.begin();
3193 std::map< std::string, IDF3_COMPONENT*>::iterator itce = m_components.end();
3194
3195 // determine if there are any component outlines at all and avoid
3196 // writing an empty PLACEMENT section if there are no outlines.
3197 // this will cost a little time but prevents software such as
3198 // CircuitWorks from segfaulting on an empty section.
3199
3200 bool hasOutlines = false;
3201
3202 while( itcs != itce )
3203 {
3204 if( itcs->second->GetOutlinesSize() > 0 )
3205 {
3206 itcs = m_components.begin();
3207 hasOutlines = true;
3208 break;
3209 }
3210
3211 ++itcs;
3212 }
3213
3214 if( hasOutlines )
3215 {
3216 brd << ".PLACEMENT\n";
3217
3218 while( itcs != itce )
3219 {
3220 itcs->second->writePlaceData( brd );
3221 ++itcs;
3222 }
3223
3224 brd << ".END_PLACEMENT\n";
3225 }
3226
3227 }
3228
3229 }
3230 catch( const std::exception& )
3231 {
3232 brd.exceptions( std::ios_base::goodbit );
3233 CLOSE_STREAM( brd );
3234 throw;
3235 }
3236
3237 CLOSE_STREAM( brd );
3238}
3239
3240
3241bool IDF3_BOARD::WriteFile( const wxString& aFullFileName, IDF_UNIT aUnits, REPORTER* aReporter )
3242{
3243 setUnit( aUnits, false );
3244
3245 wxFileName brdname( aFullFileName );
3246 wxFileName libname( aFullFileName );
3247
3248 brdname.SetExt( FILEEXT::IdfV3BoardFileExtension );
3249 libname.SetExt( FILEEXT::IdfV3LibraryFileExtension );
3250
3251 std::string bfname = TO_UTF8( aFullFileName );
3252
3253 try
3254 {
3255 if( !brdname.IsOk() )
3256 {
3257 if( aReporter )
3258 {
3259 aReporter->Report( wxString::Format( _( "Invalid output path: %s" ), brdname.GetFullPath() ),
3261 }
3262
3263 return false;
3264 }
3265
3266 if( brdname.FileExists() && !brdname.IsFileWritable() )
3267 {
3268 if( aReporter )
3269 {
3270 aReporter->Report( wxString::Format( _( "Cannot overwrite file: %s" ), brdname.GetFullPath() ),
3272 }
3273
3274 return false;
3275 }
3276
3277 bfname = TO_UTF8( brdname.GetFullPath() );
3278 std::string lfname = TO_UTF8( libname.GetFullPath() );
3279
3280 if( libname.FileExists() && !libname.IsFileWritable() )
3281 {
3282 if( aReporter )
3283 {
3284 aReporter->Report( wxString::Format( _( "Cannot overwrite file: %s" ), libname.GetFullPath() ),
3286 }
3287
3288 return false;
3289 }
3290
3291 writeLibFile( lfname );
3292 writeBoardFile( bfname );
3293 }
3294 catch( const std::exception& e )
3295 {
3296 m_errormsg = e.what();
3297
3298 if( aReporter )
3299 aReporter->Report( wxString::Format( _( "Error writing IDF file: %s" ), e.what() ), RPT_SEVERITY_ERROR );
3300
3301 return false;
3302 }
3303
3304 return true;
3305}
3306
3307
3309{
3310 if( aVersion < 0 )
3311 {
3312 ostringstream ostr;
3313 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3314 ostr << "* board version (" << aVersion << ") must be >= 0";
3315 m_errormsg = ostr.str();
3316
3317 return false;
3318 }
3319
3320 m_brdFileVersion = aVersion;
3321
3322 return true;
3323}
3324
3325
3327{
3328 if( aVersion < 0 )
3329 {
3330 ostringstream ostr;
3331 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3332 ostr << "* library version (" << aVersion << ") must be >= 0";
3333 m_errormsg = ostr.str();
3334
3335 return false;
3336 }
3337
3338 m_libFileVersion = aVersion;
3339
3340 return true;
3341}
3342
3343
3344bool IDF3_BOARD::SetUserScale( double aScaleFactor )
3345{
3346 if( aScaleFactor == 0.0 )
3347 {
3348 ostringstream ostr;
3349 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3350 ostr << "* BUG: user scale factor must not be 0";
3351 m_errormsg = ostr.str();
3352
3353 return false;
3354 }
3355
3356 m_userScale = aScaleFactor;
3357 return true;
3358}
3359
3360
3361bool IDF3_BOARD::SetUserPrecision( int aPrecision )
3362{
3363 if( aPrecision < 1 || aPrecision > 8 )
3364 {
3365 ostringstream ostr;
3366 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3367 ostr << "* precision value (" << aPrecision << ") must be 1..8";
3368 m_errormsg = ostr.str();
3369
3370 return false;
3371 }
3372
3373 m_userPrec = aPrecision;
3374 return true;
3375}
3376
3377
3378void IDF3_BOARD::GetUserOffset( double& aXoff, double& aYoff )
3379{
3380 aXoff = m_userXoff;
3381 aYoff = m_userYoff;
3382}
3383
3384
3385void IDF3_BOARD::SetUserOffset( double aXoff, double aYoff )
3386{
3387 m_userXoff = aXoff;
3388 m_userYoff = aYoff;
3389}
3390
3391
3393{
3394 if( !m_boardOutline.AddOutline( aOutline ) )
3395 {
3396 m_errormsg = m_boardOutline.GetError();
3397
3398 return false;
3399 }
3400
3401 return true;
3402}
3403
3404
3406{
3407 if( !m_boardOutline.DelOutline( aOutline ) )
3408 {
3409 m_errormsg = m_boardOutline.GetError();
3410 return false;
3411 }
3412
3413 return true;
3414}
3415
3416
3417bool IDF3_BOARD::DelBoardOutline( size_t aIndex )
3418{
3419 if( !m_boardOutline.DelOutline( aIndex ) )
3420 {
3421 m_errormsg = m_boardOutline.GetError();
3422 return false;
3423 }
3424
3425 return true;
3426}
3427
3428
3430{
3431 return m_boardOutline.OutlinesSize();
3432}
3433
3434
3435IDF_DRILL_DATA* IDF3_BOARD::AddBoardDrill( double aDia, double aXpos, double aYpos,
3436 IDF3::KEY_PLATING aPlating,
3437 const std::string& aHoleType,
3438 IDF3::KEY_OWNER aOwner )
3439{
3440 IDF_DRILL_DATA* drill = nullptr;
3441
3442 try
3443 {
3444 drill = new IDF_DRILL_DATA( aDia, aXpos, aYpos, aPlating, "BOARD", aHoleType, aOwner );
3445 }
3446 catch( std::bad_alloc& )
3447 {
3448 return nullptr;
3449 }
3450
3451 m_drills.push_back( drill );
3452
3453 return drill;
3454}
3455
3456
3458{
3459 if( !aDrilledHole )
3460 return nullptr;
3461
3462 // note: PANEL drills are essentially BOARD drills which
3463 // the panel requires to be present
3464 if( CompareToken( "BOARD", aDrilledHole->GetDrillRefDes() )
3465 || CompareToken( "PANEL", aDrilledHole->GetDrillRefDes() ) )
3466 {
3467 m_drills.push_back( aDrilledHole );
3468 return aDrilledHole;
3469 }
3470
3471 return addCompDrill( aDrilledHole );
3472}
3473
3474
3475bool IDF3_BOARD::DelBoardDrill( double aDia, double aXpos, double aYpos )
3476{
3477 m_errormsg.clear();
3478
3479 std::list<IDF_DRILL_DATA*>::iterator sp = m_drills.begin();
3480 std::list<IDF_DRILL_DATA*>::iterator ep = m_drills.end();
3481 bool rval = false;
3482
3483 while( sp != ep )
3484 {
3485 if( (*sp)->Matches( aDia, aXpos, aYpos ) )
3486 {
3487#ifndef DISABLE_IDF_OWNERSHIP
3488 IDF3::KEY_OWNER keyo = (*sp)->GetDrillOwner();
3489
3490 if( keyo == KEY_OWNER::UNOWNED || ( keyo == KEY_OWNER::MCAD && m_cadType == CAD_TYPE::CAD_MECH )
3491 || ( keyo == KEY_OWNER::ECAD && m_cadType == CAD_TYPE::CAD_ELEC ) )
3492 {
3493 rval = true;
3494 delete *sp;
3495 sp = m_drills.erase( sp );
3496 continue;
3497 }
3498 else
3499 {
3500 ostringstream ostr;
3501 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3502 ostr << "* ownership violation; drill owner (";
3503
3504 switch( keyo )
3505 {
3506 case KEY_OWNER::ECAD:
3507 ostr << "ECAD";
3508 break;
3509
3510 case KEY_OWNER::MCAD:
3511 ostr << "MCAD";
3512 break;
3513
3514 default:
3515 ostr << "invalid: " << static_cast<int>( keyo );
3516 break;
3517 }
3518
3519 ostr << ") may not be modified by ";
3520
3522 ostr << "MCAD";
3523 else
3524 ostr << "ECAD";
3525
3526 m_errormsg = ostr.str();
3527
3528 ++sp;
3529 continue;
3530 }
3531#else
3532 rval = true;
3533 delete *sp;
3534 sp = m_drills.erase( sp );
3535 continue;
3536#endif
3537 }
3538
3539 ++sp;
3540 }
3541
3542 return rval;
3543}
3544
3545
3546bool IDF3_BOARD::AddSlot( double aWidth, double aLength, double aOrientation, double aX, double aY )
3547{
3548 if( aWidth < IDF_MIN_DIA_MM )
3549 {
3550 ostringstream ostr;
3551 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3552 ostr << "* slot width (" << aWidth << ") must be >= " << IDF_MIN_DIA_MM;
3553 m_errormsg = ostr.str();
3554
3555 return false;
3556 }
3557
3558 if( aLength < IDF_MIN_DIA_MM )
3559 {
3560 ostringstream ostr;
3561 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3562 ostr << "* slot length (" << aLength << ") must be >= " << IDF_MIN_DIA_MM;
3563 m_errormsg = ostr.str();
3564
3565 return false;
3566 }
3567
3568 IDF_POINT c[2]; // centers
3569 IDF_POINT pt[4];
3570
3571 double a1 = aOrientation / 180.0 * M_PI;
3572 double a2 = a1 + M_PI_2;
3573 double d1 = aLength / 2.0;
3574 double d2 = aWidth / 2.0;
3575 double sa1 = sin( a1 );
3576 double ca1 = cos( a1 );
3577 double dsa2 = d2 * sin( a2 );
3578 double dca2 = d2 * cos( a2 );
3579
3580 c[0].x = aX + d1 * ca1;
3581 c[0].y = aY + d1 * sa1;
3582
3583 c[1].x = aX - d1 * ca1;
3584 c[1].y = aY - d1 * sa1;
3585
3586 pt[0].x = c[0].x - dca2;
3587 pt[0].y = c[0].y - dsa2;
3588
3589 pt[1].x = c[1].x - dca2;
3590 pt[1].y = c[1].y - dsa2;
3591
3592 pt[2].x = c[1].x + dca2;
3593 pt[2].y = c[1].y + dsa2;
3594
3595 pt[3].x = c[0].x + dca2;
3596 pt[3].y = c[0].y + dsa2;
3597
3598 IDF_OUTLINE* outline = nullptr;
3599
3600 try
3601 {
3602 outline = new IDF_OUTLINE;
3603 }
3604 catch( std::bad_alloc& )
3605 {
3606 ostringstream ostr;
3607 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3608 ostr << "* could not create an outline object";
3609 m_errormsg = ostr.str();
3610
3611 return false;
3612 }
3613
3614 // first straight run
3615 IDF_SEGMENT* seg = new IDF_SEGMENT( pt[0], pt[1] );
3616 outline->push( seg );
3617
3618 // first 180 degree cap
3619 seg = new IDF_SEGMENT( c[1], pt[1], -180.0, true );
3620 outline->push( seg );
3621
3622 // final straight run
3623 seg = new IDF_SEGMENT( pt[2], pt[3] );
3624 outline->push( seg );
3625
3626 // final 180 degree cap
3627 seg = new IDF_SEGMENT( c[0], pt[3], -180.0, true );
3628 outline->push( seg );
3629
3630 if( !m_boardOutline.addOutline( outline ) )
3631 {
3632 m_errormsg = m_boardOutline.GetError();
3633 return false;
3634 }
3635
3636 return true;
3637}
3638
3639
3640IDF_DRILL_DATA* IDF3_BOARD::addCompDrill( double aDia, double aXpos, double aYpos,
3641 IDF3::KEY_PLATING aPlating,
3642 const std::string& aHoleType,
3643 IDF3::KEY_OWNER aOwner,
3644 const std::string& aRefDes )
3645{
3646 // first find the matching component; if it doesn't exist we must create it somehow -
3647 // question is, do we need a component outline at this stage or can those be added later?
3648 //
3649 // Presumably we can create a component with no outline and add the outlines later.
3650 // If a component is created and an outline specified but the outline is not loaded,
3651 // we're screwed if (a) we have already read the library file (*.emp) or (b) we don't
3652 // know the filename
3653
3654 std::string refdes = aRefDes;
3655
3656 // note: for components 'NOREFDES' would be assigned a Unique ID, but for holes
3657 // there is no way of associating the hole with the correct entity (if any)
3658 // so a hole added with "NOREFDES" goes to a generic component "NOREFDES"
3659 if( refdes.empty() )
3660 refdes = "NOREFDES";
3661
3662 // check if the target is BOARD or PANEL
3663 if( CompareToken( "BOARD", refdes ) )
3664 return AddBoardDrill( aDia, aXpos, aYpos, aPlating, aHoleType, aOwner );
3665
3666 if( CompareToken( "PANEL", refdes ) )
3667 {
3668 ostringstream ostr;
3669 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3670 ostr << "* PANEL data not supported";
3671 m_errormsg = ostr.str();
3672
3673 return nullptr;
3674 }
3675
3676 std::map<std::string, IDF3_COMPONENT*>::iterator ref = m_components.find( refdes );
3677
3678 if( ref == m_components.end() )
3679 {
3680 // create the item
3681 IDF3_COMPONENT* comp = nullptr;
3682 try
3683 {
3684 comp = new IDF3_COMPONENT( this );
3685 }
3686 catch( std::bad_alloc& )
3687 {
3688 ostringstream ostr;
3689 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3690 ostr << "* could not create new component object";
3691 m_errormsg = ostr.str();
3692
3693 return nullptr;
3694 }
3695
3696 comp->SetParent( this );
3697 comp->SetRefDes( refdes );
3698 ref = m_components.emplace( comp->GetRefDes(), comp ).first;
3699 }
3700
3701 // add the drill
3702 IDF_DRILL_DATA* dp = ref->second->AddDrill( aDia, aXpos, aYpos, aPlating, aHoleType, aOwner );
3703
3704 if( !dp )
3705 {
3706 m_errormsg = ref->second->GetError();
3707 return nullptr;
3708 }
3709
3710 return dp;
3711}
3712
3713
3715{
3716 if( !aDrilledHole )
3717 {
3718 ostringstream ostr;
3719 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): nullptr pointer";
3720 m_errormsg = ostr.str();
3721
3722 return nullptr;
3723 }
3724
3725 if( CompareToken( "PANEL", aDrilledHole->GetDrillRefDes() ) )
3726 {
3727 ostringstream ostr;
3728 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3729 ostr << "* PANEL data not supported";
3730 m_errormsg = ostr.str();
3731
3732 return nullptr;
3733 }
3734
3735 std::map<std::string, IDF3_COMPONENT*>::iterator ref = m_components.find( aDrilledHole->GetDrillRefDes() );
3736
3737 if( ref == m_components.end() )
3738 {
3739 // create the item
3741 try
3742 {
3743 comp = new IDF3_COMPONENT( this );
3744 }
3745 catch( std::bad_alloc& )
3746 {
3747 ostringstream ostr;
3748 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3749 ostr << "* could not create new component object";
3750 m_errormsg = ostr.str();
3751
3752 return nullptr;
3753 }
3754
3755 comp->SetParent( this );
3756 comp->SetRefDes( aDrilledHole->GetDrillRefDes() );
3757 ref = m_components.emplace( comp->GetRefDes(), comp ).first;
3758 }
3759
3760 IDF_DRILL_DATA* dp = ref->second->AddDrill( aDrilledHole );
3761
3762 if( !dp )
3763 {
3764 m_errormsg = ref->second->GetError();
3765 return nullptr;
3766 }
3767
3768 return dp;
3769}
3770
3771
3772bool IDF3_BOARD::delCompDrill( double aDia, double aXpos, double aYpos, const std::string& aRefDes )
3773{
3774 m_errormsg.clear();
3775
3776 std::map<std::string, IDF3_COMPONENT*>::iterator ref = m_components.find( aRefDes );
3777
3778 if( ref == m_components.end() )
3779 return false;
3780
3781 if( !ref->second->DelDrill( aDia, aXpos, aYpos ) )
3782 {
3783 m_errormsg = ref->second->GetError();
3784 return false;
3785 }
3786
3787 return true;
3788}
3789
3790
3792{
3793 if( !aComponent )
3794 {
3795 ostringstream ostr;
3796 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__;
3797 ostr << "(): Invalid component pointer (nullptr)";
3798 m_errormsg = ostr.str();
3799
3800 return false;
3801 }
3802
3803 if( m_components.emplace( aComponent->GetRefDes(), aComponent ).second == false )
3804 {
3805 ostringstream ostr;
3806 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
3807 ostr << "* duplicate RefDes ('" << aComponent->GetRefDes() << "')";
3808 m_errormsg = ostr.str();
3809
3810 return false;
3811 }
3812
3813 return true;
3814}
3815
3816
3818{
3819 m_errormsg.clear();
3820
3821#ifndef DISABLE_IDF_OWNERSHIP
3822 if( !checkComponentOwnership( __LINE__, __FUNCTION__, aComponent ) )
3823 return false;
3824#endif
3825
3826 std::map<std::string, IDF3_COMPONENT*>::iterator it = m_components.find( aComponent->GetRefDes() );
3827
3828 if( it == m_components.end() )
3829 return false;
3830
3831 delete it->second;
3832 m_components.erase( it );
3833
3834 return true;
3835}
3836
3837
3838bool IDF3_BOARD::DelComponent( size_t aIndex )
3839{
3840 if( aIndex >= m_components.size() )
3841 {
3842 ostringstream ostr;
3843 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
3844 ostr << "* aIndex (" << aIndex << ") out of range (" << m_components.size() << ")";
3845 m_errormsg = ostr.str();
3846
3847 return false;
3848 }
3849
3850 std::map<std::string, IDF3_COMPONENT*>::iterator it = m_components.begin();
3851
3852 while( aIndex-- > 0 ) ++it;
3853
3854#ifndef DISABLE_IDF_OWNERSHIP
3855 if( !checkComponentOwnership( __LINE__, __FUNCTION__, it->second ) )
3856 return false;
3857#endif
3858
3859 delete it->second;
3860 m_components.erase( it );
3861
3862 return true;
3863}
3864
3865
3867{
3868 return m_components.size();
3869}
3870
3871
3872std::map< std::string, IDF3_COMPONENT* >* IDF3_BOARD::GetComponents( void )
3873{
3874 return &m_components;
3875}
3876
3877
3878IDF3_COMPONENT* IDF3_BOARD::FindComponent( const std::string& aRefDes )
3879{
3880 std::map<std::string, IDF3_COMPONENT*>::iterator it = m_components.find( aRefDes );
3881
3882 if( it == m_components.end() )
3883 return nullptr;
3884
3885 return it->second;
3886}
3887
3888
3890{
3891 std::string fname = TO_UTF8( aFullFileName );
3892 wxFileName idflib( aFullFileName );
3893
3894 if( !idflib.IsOk() )
3895 {
3896 ostringstream ostr;
3897 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
3898 cerr << "* invalid file name: '" << fname << "'";
3899 m_errormsg = ostr.str();
3900
3901 return nullptr;
3902 }
3903
3904 if( !idflib.FileExists() )
3905 {
3906 ostringstream ostr;
3907 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
3908 cerr << "* no such file: '" << fname << "'";
3909 m_errormsg = ostr.str();
3910
3911 return nullptr;
3912 }
3913
3914 if( !idflib.IsFileReadable() )
3915 {
3916 ostringstream ostr;
3917 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
3918 cerr << "* cannot read file: '" << fname << "'";
3919 m_errormsg = ostr.str();
3920
3921 return nullptr;
3922 }
3923
3924 std::map<std::string, std::string>::iterator itm = m_uidFileList.find( fname );
3925
3926 if( itm != m_uidFileList.end() )
3927 return GetComponentOutline( itm->second );
3928
3929 IDF3_COMP_OUTLINE* cp = nullptr;
3930
3931 try
3932 {
3933 cp = new IDF3_COMP_OUTLINE( this );
3934 }
3935 catch( std::bad_alloc& )
3936 {
3937 ostringstream ostr;
3938 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
3939 cerr << "* failed to create outline\n";
3940 cerr << "* filename: '" << fname << "'";
3941 m_errormsg = ostr.str();
3942
3943 return nullptr;
3944 }
3945
3946 OPEN_ISTREAM( model, fname.c_str() );
3947
3948 try
3949 {
3950 model.exceptions ( std::ios_base::badbit );
3951
3952 if( model.fail() )
3953 {
3954 ostringstream ostr;
3955 ostr << "\n* could not open file: '" << fname << "'";
3956
3957 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3958 }
3959
3960 model.imbue( std::locale( "C" ) );
3961 std::string iline; // the input line
3962 bool isComment; // true if a line just read in is a comment line
3963 std::streampos pos;
3964
3965 while( true )
3966 {
3967 while( !FetchIDFLine( model, iline, isComment, pos ) && model.good() );
3968
3969 if( !model.good() )
3970 {
3971 ostringstream ostr;
3972 ostr << "\n* problems reading file: '" << fname << "'";
3973 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3974 }
3975
3976 // accept comment lines, .ELECTRICAL, or .MECHANICAL only
3977 if( isComment )
3978 {
3979 cp->AddComment( iline );
3980 continue;
3981 }
3982
3983 if( CompareToken( ".ELECTRICAL", iline ) || CompareToken( ".MECHANICAL", iline ) )
3984 {
3985 cp->readData( model, iline, m_idfVer );
3986 break;
3987 }
3988 else
3989 {
3990 ostringstream ostr;
3991 ostr << "faulty IDF component definition\n";
3992 ostr << "* Expecting .ELECTRICAL or .MECHANICAL, got '" << iline << "'\n";
3993 cerr << "* File: '" << fname << "'\n";
3994
3995 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3996 }
3997 }
3998 }
3999 catch( const std::exception& e )
4000 {
4001 delete cp;
4002 model.exceptions ( std::ios_base::goodbit );
4004 m_errormsg = e.what();
4005 return nullptr;
4006 }
4007
4009
4010 // check the unique ID against the list from library components
4011 std::list<std::string>::iterator lsts = m_uidLibList.begin();
4012 std::list<std::string>::iterator lste = m_uidLibList.end();
4013 std::string uid = cp->GetUID();
4014 IDF3_COMP_OUTLINE* oldp = nullptr;
4015
4016 while( lsts != lste )
4017 {
4018 if( ! lsts->compare( uid ) )
4019 {
4020 oldp = GetComponentOutline( uid );
4021
4022 if( MatchCompOutline( cp, oldp ) )
4023 {
4024 // everything is fine; the outlines are genuine duplicates; delete the copy
4025 delete cp;
4026
4027 // make sure we can find the item via its filename
4028 m_uidFileList.emplace( fname, uid );
4029
4030 // return the pointer to the original
4031 return oldp;
4032 }
4033 else
4034 {
4035 delete cp;
4036 ostringstream ostr;
4037 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
4038 ostr << "* duplicate UID for different Component Outlines: '" << uid << "'\n";
4039 ostr << "* original loaded from library, duplicate in current file\n";
4040 ostr << "* file: '" << fname << "'";
4041
4042 m_errormsg = ostr.str();
4043 return nullptr;
4044 }
4045 }
4046
4047 ++lsts;
4048 }
4049
4050 // if we got this far then any duplicates are from files previously read
4051 oldp = GetComponentOutline( uid );
4052
4053 if( oldp == nullptr )
4054 {
4055 // everything is fine, there are no existing entries
4056 m_uidFileList.emplace( fname, uid );
4057 m_componentOutlines.emplace( uid, cp );
4058
4059 return cp;
4060 }
4061
4062 if( MatchCompOutline( cp, oldp ) )
4063 {
4064 // everything is fine; the outlines are genuine duplicates; delete the copy
4065 delete cp;
4066
4067 // make sure we can find the item via its other filename
4068 m_uidFileList.emplace( fname, uid );
4069
4070 // return the pointer to the original
4071 return oldp;
4072 }
4073
4074 delete cp;
4075
4076 // determine the file name of the first instance
4077 std::map<std::string, std::string>::iterator ufls = m_uidFileList.begin();
4078 std::map<std::string, std::string>::iterator ufle = m_uidFileList.end();
4079 std::string oldfname;
4080
4081 while( ufls != ufle )
4082 {
4083 if( ! ufls->second.compare( uid ) )
4084 {
4085 oldfname = ufls->first;
4086 break;
4087 }
4088
4089 ++ufls;
4090 }
4091
4092 ostringstream ostr;
4093 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
4094 ostr << "* duplicate UID for different Component Outlines: '" << uid << "'\n";
4095 ostr << "* original file: '" << oldfname << "'\n";
4096 ostr << "* this file: '" << fname << "'";
4097
4098 m_errormsg = ostr.str();
4099 return nullptr;
4100}
4101
4102
4103IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string& aComponentID )
4104{
4105 std::map< std::string, IDF3_COMP_OUTLINE*>::iterator its = m_componentOutlines.find( aComponentID );
4106
4107 if( its != m_componentOutlines.end() )
4108 return its->second;
4109
4110 return nullptr;
4111}
4112
4113
4115 const std::string& aPartName )
4116{
4117 IDF3_COMP_OUTLINE* cp = GetComponentOutline( aGeomName + "_" + aPartName );
4118
4119 if( cp != nullptr )
4120 return cp;
4121
4122 try
4123 {
4124 cp = new IDF3_COMP_OUTLINE( this );
4125 }
4126 catch( std::bad_alloc& )
4127 {
4128 ostringstream ostr;
4129 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n";
4130 cerr << "could not create new outline";
4131 m_errormsg = ostr.str();
4132
4133 return nullptr;
4134 }
4135
4136 cp->SetGeomName( aGeomName );
4137 cp->SetPartName( aPartName );
4138 m_componentOutlines.emplace( cp->GetUID(), cp );
4139
4140 return cp;
4141}
4142
4143
4145 const std::string& aPartName )
4146{
4147 std::string uid;
4148 bool empty = false;
4149
4150 if( aGeomName.empty() && aPartName.empty() )
4151 {
4152 uid = "NOGEOM_NOPART";
4153 empty = true;
4154 }
4155 else
4156 {
4157 uid = aGeomName + "_" + aPartName;
4158 }
4159
4161
4162 if( cp != nullptr )
4163 return cp;
4164
4165 try
4166 {
4167 cp = new IDF3_COMP_OUTLINE( this );
4168 }
4169 catch( std::bad_alloc& )
4170 {
4171 ostringstream ostr;
4172 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): ";
4173 cerr << "could not create new outline";
4174 m_errormsg = ostr.str();
4175
4176 return nullptr;
4177 }
4178
4179 if( empty )
4180 cp->CreateDefaultOutline( "", "" );
4181 else
4182 cp->CreateDefaultOutline( aGeomName, aPartName );
4183
4184 m_componentOutlines.emplace( cp->GetUID(), cp );
4185
4186 return cp;
4187}
4188
4189
4191{
4192 // preserve the board thickness
4193 double thickness = m_boardOutline.GetThickness();
4194
4195 m_idfSource.clear();
4196 m_brdSource.clear();
4197 m_libSource.clear();
4198 m_brdDate.clear();
4199 m_libDate.clear();
4200 m_uidFileList.clear();
4201 m_uidLibList.clear();
4202 m_brdFileVersion = 0;
4203 m_libFileVersion = 0;
4204 m_refDesCounter = 0;
4205 m_refDesString.clear();
4206
4207 // delete comment lists
4208 m_noteComments.clear();
4209 m_drillComments.clear();
4210 m_placeComments.clear();
4211
4212 // delete notes
4213 while( !m_notes.empty() )
4214 {
4215 delete m_notes.front();
4216 m_notes.pop_front();
4217 }
4218
4219 // delete drill list
4220 do
4221 {
4222 std::list<IDF_DRILL_DATA*>::iterator ds = m_drills.begin();
4223 std::list<IDF_DRILL_DATA*>::iterator de = m_drills.end();
4224
4225 while( ds != de )
4226 {
4227 delete *ds;
4228 ++ds;
4229 }
4230
4231 m_drills.clear();
4232 } while( 0 );
4233
4234
4235 // delete components
4236 do
4237 {
4238 std::map<std::string, IDF3_COMPONENT*>::iterator cs = m_components.begin();
4239 std::map<std::string, IDF3_COMPONENT*>::iterator ce = m_components.end();
4240
4241 while( cs != ce )
4242 {
4243 delete cs->second;
4244 ++cs;
4245 }
4246
4247 m_components.clear();
4248 } while( 0 );
4249
4250
4251 // delete component outlines
4252 do
4253 {
4254 std::map<std::string, IDF3_COMP_OUTLINE*>::iterator cs = m_componentOutlines.begin();
4255 std::map<std::string, IDF3_COMP_OUTLINE*>::iterator ce = m_componentOutlines.end();
4256
4257 while( cs != ce )
4258 {
4259 delete cs->second;
4260 ++cs;
4261 }
4262
4263 m_componentOutlines.clear();
4264 } while( 0 );
4265
4266
4267 // delete OTHER outlines
4268 do
4269 {
4270 std::map<std::string, OTHER_OUTLINE*>::iterator os = m_otherOutlines.begin();
4271 std::map<std::string, OTHER_OUTLINE*>::iterator oe = m_otherOutlines.end();
4272
4273 while( os != oe )
4274 {
4275 delete os->second;
4276 ++os;
4277 }
4278
4279 m_otherOutlines.clear();
4280 } while( 0 );
4281
4282
4283 // delete ROUTE outlines
4284 do
4285 {
4286 std::list<ROUTE_OUTLINE*>::iterator os = m_routeOutlines.begin();
4287 std::list<ROUTE_OUTLINE*>::iterator oe = m_routeOutlines.end();
4288
4289 while( os != oe )
4290 {
4291 delete *os;
4292 ++os;
4293 }
4294
4295 m_routeOutlines.clear();
4296 } while( 0 );
4297
4298
4299 // delete PLACE outlines
4300 do
4301 {
4302 std::list<PLACE_OUTLINE*>::iterator os = m_placeOutlines.begin();
4303 std::list<PLACE_OUTLINE*>::iterator oe = m_placeOutlines.end();
4304
4305 while( os != oe )
4306 {
4307 delete *os;
4308 ++os;
4309 }
4310
4311 m_placeOutlines.clear();
4312 } while( 0 );
4313
4314
4315 // delete ROUTE KEEPOUT outlines
4316 do
4317 {
4318 std::list<ROUTE_KO_OUTLINE*>::iterator os = m_routeKeepoutOutlines.begin();
4319 std::list<ROUTE_KO_OUTLINE*>::iterator oe = m_routeKeepoutOutlines.end();
4320
4321 while( os != oe )
4322 {
4323 delete *os;
4324 ++os;
4325 }
4326
4327 m_routeKeepoutOutlines.clear();
4328 } while( 0 );
4329
4330
4331 // delete VIA KEEPOUT outlines
4332 do
4333 {
4334 std::list<VIA_KO_OUTLINE*>::iterator os = m_viaKeepoutOutlines.begin();
4335 std::list<VIA_KO_OUTLINE*>::iterator oe = m_viaKeepoutOutlines.end();
4336
4337 while( os != oe )
4338 {
4339 delete *os;
4340 ++os;
4341 }
4342
4343 m_viaKeepoutOutlines.clear();
4344 } while( 0 );
4345
4346
4347 // delete PLACEMENT KEEPOUT outlines
4348 do
4349 {
4350 std::list<PLACE_KO_OUTLINE*>::iterator os = m_placeKeepoutOutlines.begin();
4351 std::list<PLACE_KO_OUTLINE*>::iterator oe = m_placeKeepoutOutlines.end();
4352
4353 while( os != oe )
4354 {
4355 delete *os;
4356 ++os;
4357 }
4358
4359 m_placeKeepoutOutlines.clear();
4360 } while( 0 );
4361
4362
4363 // delete PLACEMENT GROUP outlines
4364 do
4365 {
4366 std::multimap<std::string, GROUP_OUTLINE*>::iterator os = m_groupOutlines.begin();
4367 std::multimap<std::string, GROUP_OUTLINE*>::iterator oe = m_groupOutlines.end();
4368
4369 while( os != oe )
4370 {
4371 delete os->second;
4372 ++os;
4373 }
4374
4375 m_groupOutlines.clear();
4376 } while( 0 );
4377
4378 m_boardName.clear();
4379 m_boardOutline.setThickness( thickness );
4380
4382 m_userScale = 1.0;
4383 m_userXoff = 0.0;
4384 m_userYoff = 0.0;
4385}
IDF_OUTLINE * GetOutline(size_t aIndex)
Return a pointer to the outline as specified by aIndex.
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 ...
void AddComment(const std::string &aComment)
Add a comment to the outline data.
Regions and layers in which user-specified features or components may be placed.
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read GROUP_OUTLINE data from an open IDFv3 file.
virtual const std::string & GetGroupName(void)
Return a reference to the (non-unique) group name.
void GetUserOffset(double &aXoff, double &aYoff)
bool WriteFile(const wxString &aFullFileName, IDF3::IDF_UNIT aUnits, REPORTER *aReporter=nullptr)
std::list< std::string > m_uidLibList
Definition idf_parser.h:640
std::list< IDF_DRILL_DATA * > m_drills
Definition idf_parser.h:648
void readLibFile(const std::string &aFileName)
void readLibSection(std::istream &aLibFile, IDF3::FILE_STATE &aLibState, IDF3_BOARD *aBoard)
std::list< VIA_KO_OUTLINE * > m_viaKeepoutOutlines
Definition idf_parser.h:680
bool SetBoardThickness(double aBoardThickness)
IDF3::CAD_TYPE m_cadType
Definition idf_parser.h:653
int m_brdFileVersion
Definition idf_parser.h:665
bool SetLibraryVersion(int aVersion)
std::map< std::string, OTHER_OUTLINE * > m_otherOutlines
Definition idf_parser.h:674
bool setUnit(IDF3::IDF_UNIT aUnit, bool convert=false)
std::list< std::string > m_placeComments
Definition idf_parser.h:647
IDF3_COMP_OUTLINE * GetComponentOutline(const wxString &aFullFileName)
const std::string & GetNewRefDes(void)
std::string m_brdSource
Definition idf_parser.h:661
std::map< std::string, IDF3_COMP_OUTLINE * > m_componentOutlines
Definition idf_parser.h:650
std::list< IDF_NOTE * > m_notes
Definition idf_parser.h:644
bool writeLibFile(const std::string &aFileName)
void SetUserOffset(double aXoff, double aYoff)
int m_libFileVersion
Definition idf_parser.h:666
void readBrdNotes(std::istream &aBoardFile, IDF3::FILE_STATE &aBoardState)
double m_userXoff
Definition idf_parser.h:670
std::map< std::string, std::string > m_uidFileList
Definition idf_parser.h:639
std::list< PLACE_OUTLINE * > m_placeOutlines
Definition idf_parser.h:676
double m_userYoff
Definition idf_parser.h:671
std::string m_brdDate
Definition idf_parser.h:663
std::list< ROUTE_KO_OUTLINE * > m_routeKeepoutOutlines
Definition idf_parser.h:679
IDF3::CAD_TYPE GetCadType(void)
Definition idf_parser.h:425
int m_refDesCounter
Definition idf_parser.h:657
std::string m_refDesString
Definition idf_parser.h:658
IDF3::IDF_UNIT m_unit
Definition idf_parser.h:654
std::multimap< std::string, GROUP_OUTLINE * > m_groupOutlines
Definition idf_parser.h:677
bool DelBoardOutline(IDF_OUTLINE *aOutline)
IDF_DRILL_DATA * AddBoardDrill(double aDia, double aXpos, double aYpos, IDF3::KEY_PLATING aPlating, const std::string &aHoleType, IDF3::KEY_OWNER aOwner)
IDF3::IDF_VERSION m_idfVer
Definition idf_parser.h:655
std::string m_libSource
Definition idf_parser.h:662
bool ReadFile(const wxString &aFullFileName, bool aNoSubstituteOutlines=false)
bool delCompDrill(double aDia, double aXpos, double aYpos, const std::string &aRefDes)
void writeBoardFile(const std::string &aFileName)
std::map< std::string, IDF3_COMPONENT * > * GetComponents(void)
IDF3_COMPONENT * FindComponent(const std::string &aRefDes)
std::string m_boardName
Definition idf_parser.h:652
std::string m_errormsg
Definition idf_parser.h:643
IDF_DRILL_DATA * AddDrill(IDF_DRILL_DATA *aDrilledHole)
void readBrdHeader(std::istream &aBoardFile, IDF3::FILE_STATE &aBoardState)
size_t GetComponentsSize(void)
double GetBoardThickness(void)
void readLibHeader(std::istream &aLibFile, IDF3::FILE_STATE &aLibState)
virtual ~IDF3_BOARD()
std::string m_libDate
Definition idf_parser.h:664
bool AddComponent(IDF3_COMPONENT *aComponent)
void readBrdDrills(std::istream &aBoardFile, IDF3::FILE_STATE &aBoardState)
size_t GetBoardOutlinesSize(void)
bool SetUserScale(double aScaleFactor)
std::list< ROUTE_OUTLINE * > m_routeOutlines
Definition idf_parser.h:675
bool checkComponentOwnership(int aSourceLine, const char *aSourceFunc, IDF3_COMPONENT *aComponent)
void readBoardFile(const std::string &aFileName, bool aNoSubstituteOutlines)
void readBrdPlacement(std::istream &aBoardFile, IDF3::FILE_STATE &aBoardState, bool aNoSubstituteOutlines)
double m_userScale
Definition idf_parser.h:669
void readBrdSection(std::istream &aBoardFile, IDF3::FILE_STATE &aBoardState, bool aNoSubstituteOutlines)
IDF3::IDF_UNIT GetUnit(void) const
Definition idf_parser.h:432
bool SetUserPrecision(int aPrecision)
std::list< PLACE_KO_OUTLINE * > m_placeKeepoutOutlines
Definition idf_parser.h:681
void Clear(void)
std::string m_idfSource
Definition idf_parser.h:660
bool DelBoardDrill(double aDia, double aXpos, double aYpos)
BOARD_OUTLINE m_boardOutline
Definition idf_parser.h:673
IDF3_BOARD(IDF3::CAD_TYPE aCadType)
IDF3_COMP_OUTLINE * GetInvalidOutline(const std::string &aGeomName, const std::string &aPartName)
std::list< std::string > m_drillComments
Definition idf_parser.h:646
bool DelComponent(IDF3_COMPONENT *aComponent)
bool AddSlot(double aWidth, double aLength, double aOrientation, double aX, double aY)
bool SetBoardVersion(int aVersion)
bool AddBoardOutline(IDF_OUTLINE *aOutline)
std::map< std::string, IDF3_COMPONENT * > m_components
Definition idf_parser.h:649
IDF_DRILL_DATA * addCompDrill(double aDia, double aXpos, double aYpos, IDF3::KEY_PLATING aPlating, const std::string &aHoleType, IDF3::KEY_OWNER aOwner, const std::string &aRefDes)
std::list< std::string > m_noteComments
Definition idf_parser.h:645
const std::list< IDF3_COMP_OUTLINE_DATA * > * GetOutlinesData(void)
friend class IDF3_BOARD
Definition idf_parser.h:382
IDF3::IDF_PLACEMENT placement
Definition idf_parser.h:410
const std::string & GetRefDes(void)
Retrieve the Reference Designator (RefDes) of this component.
bool SetPlacement(IDF3::IDF_PLACEMENT aPlacementValue)
Set the placement value of the component subject to ownership rules.
IDF3_BOARD * parent
Definition idf_parser.h:414
bool writeDrillData(std::ostream &aBoardFile)
Write the internal drill data to an IDFv3 .DRILLED_HOLES section.
IDF3::IDF_LAYER layer
Definition idf_parser.h:411
bool DeleteOutlineData(IDF3_COMP_OUTLINE_DATA *aComponentOutline)
Remove outline data based on the pointer provided.
std::list< IDF_DRILL_DATA * > drills
Definition idf_parser.h:405
IDF3_COMPONENT(IDF3_BOARD *aParent)
Set the parent object and initializes other internal parameters to default values.
bool SetPosition(double aXpos, double aYpos, double aAngle, IDF3::IDF_LAYER aLayer)
Set the internal position parameters and returns true if the position was set, false if the position ...
std::list< IDF3_COMP_OUTLINE_DATA * > components
Definition idf_parser.h:404
const std::list< IDF_DRILL_DATA * > * GetDrills(void)
Return the internal list of drills.
bool SetRefDes(const std::string &aRefDes)
Set the Reference Designator (RefDes) of this component.
void SetParent(IDF3_BOARD *aParent)
Set the parent object.
IDF3::IDF_UNIT GetUnit(void)
IDF3::CAD_TYPE GetCadType(void)
bool hasPosition
True after SetPosition is called once.
Definition idf_parser.h:412
std::string errormsg
Definition idf_parser.h:415
bool checkOwnership(int aSourceLine, const char *aSourceFunc)
bool writePlaceData(std::ostream &aBoardFile)
Write the component placement data to an IDFv3 .PLACEMENT section.
IDF_DRILL_DATA * AddDrill(double aDia, double aXpos, double aYpos, IDF3::KEY_PLATING aPlating, const std::string &aHoleType, IDF3::KEY_OWNER aOwner)
Add a drill entry to the component and returns its pointer.
std::string refdes
Reference Description (MUST BE UNIQUE)
Definition idf_parser.h:413
size_t GetOutlinesSize(void)
bool GetPosition(double &aXpos, double &aYpos, double &aAngle, IDF3::IDF_LAYER &aLayer)
Retrieve the internal position parameters and returns true if the position was previously set,...
bool DelDrill(double aDia, double aXpos, double aYpos)
Delete a drill entry based on its size and location.
IDF3::IDF_PLACEMENT GetPlacement(void)
bool AddOutlineData(IDF3_COMP_OUTLINE_DATA *aComponentOutline)
Add the given component outline data to this component.
bool checkOwnership(int aSourceLine, const char *aSourceFunc)
bool readPlaceData(std::istream &aBoardFile, IDF3::FILE_STATE &aBoardState, IDF3_BOARD *aBoard, IDF3::IDF_VERSION aIdfVersion, bool aNoSubstituteOutlines)
Read placement data from an open IDFv3 file.
friend class IDF3_BOARD
Definition idf_parser.h:183
void GetOffsets(double &aXoff, double &aYoff, double &aZoff, double &aAngleOff)
Retrieve the position and orientation of this outline item in relation to its parent.
IDF3_COMP_OUTLINE * outline
Definition idf_parser.h:192
void writePlaceData(std::ostream &aBoardFile, double aXpos, double aYpos, double aAngle, const std::string &aRefDes, IDF3::IDF_PLACEMENT aPlacement, IDF3::IDF_LAYER aSide)
Write RECORD 2 and RECORD 3 of a PLACEMENT section as per IDFv3 specification.
IDF3_COMP_OUTLINE_DATA()
Create an object with default settings and no parent or associated outline.
void SetParent(IDF3_COMPONENT *aParent)
Set the parent object.
bool SetOutline(IDF3_COMP_OUTLINE *aOutline)
Set the outline whose position is managed by this object.
IDF3_COMPONENT * parent
Definition idf_parser.h:193
bool SetOffsets(double aXoff, double aYoff, double aZoff, double aAngleOff)
Set the position and orientation of this outline item in relation to its parent.
friend class IDF3_COMPONENT
Definition idf_parser.h:184
A component's outline as stored in an IDF library file.
void SetPartName(const std::string &aPartName)
Set the Part Name (Part Number, IDFv3 spec) of the component outline.
const std::string & GetUID(void)
virtual void readData(std::istream &aLibFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read a component outline from an open IDFv3 file.
IDF3::COMP_TYPE GetComponentClass(void)
bool CreateDefaultOutline(const std::string &aGeom, const std::string &aPart)
Create a default outline with the given Geometry and Part names.
void SetGeomName(const std::string &aGeomName)
Set the Geometry Name (Package Name, IDFv3 spec) of the component outline.
int incrementRef(void)
Increment the internal reference counter to keep track of the number of components referring to this ...
A drilled hole.
Definition idf_common.h:312
const std::string & GetDrillRefDes()
bool read(std::istream &aBoardFile, IDF3::IDF_UNIT aBoardUnit, IDF3::FILE_STATE aBoardState, IDF3::IDF_VERSION aIdfVersion)
Read a drill entry from an IDFv3 file.
An entry in the NOTE section of an IDF file.
Definition idf_common.h:238
bool readNote(std::istream &aBoardFile, IDF3::FILE_STATE &aBoardState, IDF3::IDF_UNIT aBoardUnit)
Read a note entry from an IDFv3 file.
A segment and winding information for an IDF outline.
Definition idf_common.h:551
std::list< IDF_SEGMENT * >::iterator end()
Definition idf_common.h:623
std::list< IDF_SEGMENT * >::iterator begin()
Definition idf_common.h:615
size_t size()
Definition idf_common.h:583
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
Miscellaneous extrusions on the board.
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read an OTHER_OUTLINE data from an IDFv3 file.
virtual const std::string & GetOutlineIdentifier(void)
Function GetOutlineIdentifier returns the object's Outline Identifier.
Regions and layers in which no component may be placed or on which a maximum component height is in e...
Area on the board for placing components.
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read PLACE_OUTLINE data from an open IDFv3 file.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
Regions and layers where no electrical routing is permitted.
Routing areas on the board.
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read ROUTE_OUTLINE data from an IDFv3 file.
Region in which vias are prohibited.
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
static const std::string IdfV3LibraryFileExtension
static const std::string IdfV3BoardFileExtension
#define IDF_THOU_TO_MM
Definition idf_helpers.h:63
#define IDF_MIN_DIA_MM
Definition idf_helpers.h:58
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
#define ERROR_IDF
Definition idf_helpers.h:55
static bool MatchCompOutline(IDF3_COMP_OUTLINE *aOutlineA, IDF3_COMP_OUTLINE *aOutlineB)
std::string GetPlacementString(IDF3::IDF_PLACEMENT aPlacement)
Return a string representing the given IDF Placement type.
FILE_STATE
State values for the IDF parser's input.
Definition idf_common.h:63
KEY_PLATING
The plating condition of a hole.
Definition idf_common.h:107
IDF_PLACEMENT
The placement status of a component.
Definition idf_common.h:188
bool GetIDFString(const std::string &aLine, std::string &aIDFString, bool &hasQuotes, int &aIndex)
Parse a line retrieved via FetchIDFLine() and returns the first IDF string found from the starting po...
CAD_TYPE
The class of CAD program which is opening or modifying a file.
Definition idf_common.h:127
bool FetchIDFLine(std::istream &aModel, std::string &aLine, bool &isComment, std::streampos &aFilePos)
Retrieve a single line from an IDF file and performs minimal processing.
IDF_VERSION
The supported IDF versions (3.0 and 2.0 ONLY).
Definition idf_common.h:76
IDF_UNIT
The native unit of the board and of component outlines.
Definition idf_common.h:177
bool CompareToken(const char *aTokenString, const std::string &aInputString)
Perform a case-insensitive comparison of a token string and an input string.
IDF_LAYER
The various IDF layer classes and groupings.
Definition idf_common.h:137
KEY_OWNER
The type of CAD which has ownership an object.
Definition idf_common.h:85
bool WriteLayersText(std::ostream &aBoardFile, IDF3::IDF_LAYER aLayer)
Write out text corresponding to the given IDF Layer type.
std::string GetLayerString(IDF3::IDF_LAYER aLayer)
Return a string representing the given IDF Layer type.
STL namespace.
@ RPT_SEVERITY_ERROR
#define OPEN_OSTREAM(var, name)
#define CLOSE_STREAM(var)
#define OPEN_ISTREAM(var, name)
KIBIS_MODEL * model
KIBIS_COMPONENT * comp
#define M_PI
Definition of file extensions used in Kicad.