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