KiCad PCB EDA Suite
Loading...
Searching...
No Matches
idf_outlines.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2014-2017 Cirilo Bernardo
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <iostream>
22#include <iomanip>
23#include <sstream>
24#include <cmath>
25#include <utility>
26
27#include <io/idf/idf_helpers.h>
28#include <io/idf/idf_outlines.h>
29#include <io/idf/idf_parser.h>
30
31using namespace IDF3;
32using namespace std;
33
34
35static std::string GetOutlineTypeString( IDF3::OUTLINE_TYPE aOutlineType )
36{
37 switch( aOutlineType )
38 {
40 return ".BOARD_OUTLINE";
41
43 return ".OTHER_OUTLINE";
44
46 return ".PLACEMENT_OUTLINE";
47
49 return ".ROUTE_OUTLINE";
50
52 return ".PLACE_KEEPOUT";
53
55 return ".ROUTE_KEEPOUT";
56
58 return ".VIA_KEEPOUT";
59
61 return ".PLACE_REGION";
62
64 return "COMPONENT OUTLINE";
65
66 default:
67 break;
68 }
69
70 std::ostringstream ostr;
71 ostr << "[INVALID OUTLINE TYPE VALUE]:" << static_cast<int>( aOutlineType );
72
73 return ostr.str();
74}
75
76
77#ifndef DISABLE_IDF_OWNERSHIP
78static bool CheckOwnership( int aSourceLine, const char* aSourceFunc,
79 IDF3_BOARD* aParent, IDF3::KEY_OWNER aOwnerCAD,
80 IDF3::OUTLINE_TYPE aOutlineType, std::string& aErrorString )
81{
82 if( aParent == nullptr )
83 {
84 ostringstream ostr;
85 ostr << "* " << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
86 ostr << "* BUG: outline's parent not set; cannot enforce ownership rules\n";
87 ostr << "* outline type: " << GetOutlineTypeString( aOutlineType );
88 aErrorString = ostr.str();
89
90 return false;
91 }
92
93 // note: component outlines have no owner so we don't care about
94 // who modifies them
95 if( aOwnerCAD == KEY_OWNER::UNOWNED || aOutlineType == IDF3::OUTLINE_TYPE::OTLN_COMPONENT )
96 return true;
97
98 IDF3::CAD_TYPE parentCAD = aParent->GetCadType();
99
100 if( aOwnerCAD == KEY_OWNER::MCAD && parentCAD == CAD_TYPE::CAD_MECH )
101 return true;
102
103 if( aOwnerCAD == KEY_OWNER::ECAD && parentCAD == CAD_TYPE::CAD_ELEC )
104 return true;
105
106 do
107 {
108 ostringstream ostr;
109 ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n";
110 ostr << "* ownership violation; CAD type is ";
111
112 if( parentCAD == CAD_TYPE::CAD_MECH )
113 ostr << "MCAD ";
114 else
115 ostr << "ECAD ";
116
117 ostr << "while outline owner is " << GetOwnerString( aOwnerCAD ) << "\n";
118 ostr << "* outline type: " << GetOutlineTypeString( aOutlineType );
119 aErrorString = ostr.str();
120
121 } while( 0 );
122
123 return false;
124}
125#endif
126
127
137
138
143
144
149
150
151void BOARD_OUTLINE::readOutlines( std::istream& aBoardFile, IDF3::IDF_VERSION aIdfVersion )
152{
153 // reads the outline data from a file
154 double x, y, ang;
155 double dLoc = 1e-5; // distances are equal when closer than 0.1 micron
156 bool comment = false;
157 bool quoted = false;
158 bool closed = false;
159 int idx = 0;
160 int loopidx = -1;
161 int tmp = 0;
162 int npts = 0;
163 std::string iline;
164 std::string entry;
165 std::stringstream tstr;
166 IDF_OUTLINE* op = nullptr;
167 IDF_SEGMENT* sp = nullptr;
168 IDF_POINT prePt;
169 IDF_POINT curPt;
170 std::streampos pos;
171
172 // destroy any existing outline data
174
175 while( aBoardFile.good() )
176 {
177 if( !FetchIDFLine( aBoardFile, iline, comment, pos ) )
178 continue;
179
180 idx = 0;
181 GetIDFString( iline, entry, quoted, idx );
182
183 if( quoted )
184 {
185 ostringstream ostr;
186
187 ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
189 ostr << " is quoted\n";
190 ostr << "* line: '" << iline << "'";
191
192 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
193 }
194
195 // check for the end of the section
196 if( entry.size() >= 5 && CompareToken( ".END_", entry.substr( 0, 5 ) ) )
197 {
198 // rewind to the start of the last line; the routine invoking
199 // this is responsible for checking that the current '.END_ ...'
200 // matches the section header.
201 if( aBoardFile.eof() )
202 aBoardFile.clear();
203
204 aBoardFile.seekg( pos );
205
206 if( outlines.size() > 0 )
207 {
208 if( npts > 0 && !closed )
209 {
210 ostringstream ostr;
211 ostr << "invalid outline (not closed)\n";
212 ostr << "* file position: " << pos;
213
214 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
215 }
216
217 // verify winding
218 if( !single )
219 {
220 if( !outlines.front()->IsCCW() )
221 {
222 ERROR_IDF << "invalid IDF3 file (BOARD_OUTLINE)\n";
223 cerr << "* WARNING: first outline is not in CCW order\n";
224 return;
225 }
226
227 if( outlines.size() > 1 && outlines.back()->IsCCW() &&
228 !outlines.back()->IsCircle() )
229 {
230 ERROR_IDF << "invalid IDF3 file (BOARD_OUTLINE)\n";
231 cerr << "* WARNING: final cutout does not have points in CW order\n";
232 cerr << "* file position: " << pos << "\n";
233 return;
234 }
235 }
236 }
237
238 return;
239 }
240
241 tstr.clear();
242 tstr << entry;
243
244 tstr >> tmp;
245
246 if( tstr.fail() )
247 {
248 if( outlineType == OUTLINE_TYPE::OTLN_COMPONENT && CompareToken( "PROP", entry ) )
249 {
250 aBoardFile.seekg( pos );
251 return;
252 }
253
254 do
255 {
256 ostringstream ostr;
257
258 ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
260 ostr << " is not numeric\n";
261 ostr << "* line: '" << iline << "'\n";
262 ostr << "* file position: " << pos;
263
264 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
265
266 } while( 0 );
267 }
268
269 if( tmp != loopidx )
270 {
271 // index change
272 if( npts > 0 && !closed )
273 {
274 ostringstream ostr;
275 ostr << "invalid outline ( outline # " << loopidx << " not closed)\n";
276 ostr << "* file position: " << pos;
277
278 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
279 }
280
281 if( tmp < 0 )
282 {
283 ostringstream ostr;
284
285 ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
287 ostr << " is invalid\n";
288 ostr << "* line: '" << iline << "'\n";
289 ostr << "* file position: " << pos;
290
291 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
292 }
293
294 if( loopidx == -1 )
295 {
296 // first outline
297 if( single )
298 {
299 // outline may have a Loop Index of 0 or 1
300 if( tmp == 0 || tmp == 1 )
301 {
302 try
303 {
304 op = new IDF_OUTLINE;
305 }
306 catch( std::bad_alloc& )
307 {
309 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
310 "memory allocation failed" ) );
311 }
312
313 outlines.push_back( op );
314 loopidx = tmp;
315 }
316 else
317 {
318 ostringstream ostr;
319
320 ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
322 ostr << " is invalid (must be 0 or 1)\n";
323 ostr << "* line: '" << iline << "'\n";
324 ostr << "* file position: " << pos;
325
326 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
327 }
328 }
329 else
330 {
331 // outline *MUST* have a Loop Index of 0
332 if( tmp != 0 )
333 {
334 ostringstream ostr;
335
336 ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
338 ostr << " is invalid (must be 0)\n";
339 ostr << "* line: '" << iline << "'\n";
340 ostr << "* file position: " << pos;
341
342 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
343 }
344
345 try
346 {
347 op = new IDF_OUTLINE;
348 }
349 catch( std::bad_alloc& )
350 {
352 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
353 "memory allocation failed" ) );
354 }
355
356 outlines.push_back( op );
357 loopidx = tmp;
358 }
359 }
360 else
361 {
362 // outline for cutout
363 if( single )
364 {
365 ostringstream ostr;
366
367 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType );
368 ostr << " section may only have one outline\n";
369 ostr << "* line: '" << iline << "'\n";
370 ostr << "* file position: " << pos;
371
372 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
373 }
374
375 if( tmp - loopidx != 1 )
376 {
377 ostringstream ostr;
378
379 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType );
380 ostr << " section must have cutouts in numeric order from 1 onwards\n";
381 ostr << "* line: '" << iline << "'\n";
382 ostr << "* file position: " << pos;
383
384 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
385 }
386
387 // verify winding of previous outline
388 if( ( loopidx == 0 && !op->IsCCW() )
389 || ( loopidx > 0 && op->IsCCW() && !op->IsCircle() ) )
390 {
391 ostringstream ostr;
392
393 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
394 ostr << "* violation of loop point order rules by Loop Index " << loopidx <<
395 "\n";
396 ostr << "* line: '" << iline << "'\n";
397 ostr << "* file position: " << pos;
398
399 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
400 }
401
402 try
403 {
404 op = new IDF_OUTLINE;
405 }
406 catch( std::bad_alloc& )
407 {
409 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
410 "memory allocation failed" ) );
411 }
412
413 outlines.push_back( op );
414 loopidx = tmp;
415 }
416 // end of index change code
417 npts = 0;
418 closed = false;
419 }
420
421 if( op == nullptr )
422 {
423 ostringstream ostr;
424
425 ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " <<
427 ostr << " is invalid\n";
428 ostr << "* line: '" << iline << "'\n";
429 ostr << "* file position: " << pos;
430
431 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
432 }
433
434 if( !GetIDFString( iline, entry, quoted, idx ) )
435 {
436 ostringstream ostr;
437
438 ostr << "\n* invalid outline: RECORD 3, FIELD 2 of ";
439 ostr << GetOutlineTypeString( outlineType ) << " does not exist\n";
440 ostr << "* line: '" << iline << "'\n";
441 ostr << "* file position: " << pos;
442
443 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
444 }
445
446 if( quoted )
447 {
448 ostringstream ostr;
449
450 ostr << "\n* invalid outline: RECORD 3, FIELD 2 of ";
451 ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n";
452 ostr << "* line: '" << iline << "'\n";
453 ostr << "* file position: " << pos;
454
455 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
456 }
457
458 tstr.clear();
459 tstr << entry;
460
461 tstr >> x;
462
463 if( tstr.fail() )
464 {
465 ostringstream ostr;
466
467 ostr << "\n* invalid outline: RECORD 3, FIELD 2 of ";
468 ostr << GetOutlineTypeString( outlineType ) << " is an invalid X value\n";
469 ostr << "* line: '" << iline << "'\n";
470 ostr << "* file position: " << pos;
471
472 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
473 }
474
475 if( !GetIDFString( iline, entry, quoted, idx ) )
476 {
477 ostringstream ostr;
478
479 ostr << "\n* invalid outline: RECORD 3, FIELD 3 of ";
480 ostr << GetOutlineTypeString( outlineType ) << " does not exist\n";
481 ostr << "* line: '" << iline << "'\n";
482 ostr << "* file position: " << pos;
483
484 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
485 }
486
487 if( quoted )
488 {
489 ostringstream ostr;
490
491 ostr << "\n* invalid outline: RECORD 3, FIELD 3 of ";
492 ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n";
493 ostr << "* line: '" << iline << "'\n";
494 ostr << "* file position: " << pos;
495
496 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
497 }
498
499 tstr.clear();
500 tstr << entry;
501
502 tstr >> y;
503
504 if( tstr.fail() )
505 {
506 ostringstream ostr;
507
508 ostr << "\n* invalid outline: RECORD 3, FIELD 3 of ";
509 ostr << GetOutlineTypeString( outlineType ) << " is an invalid Y value\n";
510 ostr << "* line: '" << iline << "'\n";
511 ostr << "* file position: " << pos;
512
513 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
514 }
515
516 if( !GetIDFString( iline, entry, quoted, idx ) )
517 {
518 ostringstream ostr;
519
520 ostr << "\n* invalid outline: RECORD 3, FIELD 4 of ";
521 ostr << GetOutlineTypeString( outlineType ) << " does not exist\n";
522 ostr << "* line: '" << iline << "'\n";
523 ostr << "* file position: " << pos;
524
525 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
526 }
527
528 if( quoted )
529 {
530 ostringstream ostr;
531
532 ostr << "\n* invalid outline: RECORD 3, FIELD 4 of ";
533 ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n";
534 ostr << "* line: '" << iline << "'\n";
535 ostr << "* file position: " << pos;
536
537 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
538 }
539
540 tstr.clear();
541 tstr << entry;
542
543 tstr >> ang;
544
545 if( tstr.fail() )
546 {
547 ostringstream ostr;
548
549 ostr << "\n* invalid outline: RECORD 3, FIELD 4 of ";
550 ostr << GetOutlineTypeString( outlineType ) << " is not a valid angle\n";
551 ostr << "* line: '" << iline << "'\n";
552 ostr << "* file position: " << pos;
553
554 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
555 }
556
557 // the line was successfully read; convert to mm if necessary
559 {
560 x *= IDF_THOU_TO_MM;
561 y *= IDF_THOU_TO_MM;
562 }
563 else if( ( aIdfVersion == IDF_VERSION::IDF_V2 ) && ( unit == IDF_UNIT::UNIT_TNM ) )
564 {
565 x *= IDF_TNM_TO_MM;
566 y *= IDF_TNM_TO_MM;
567 }
568 else if( unit != IDF_UNIT::UNIT_MM )
569 {
570 ostringstream ostr;
571 ostr << "\n* BUG: invalid UNIT type: " << static_cast<int>( unit );
572
573 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
574 }
575
576 if( npts++ == 0 )
577 {
578 // first point
579 prePt.x = x;
580 prePt.y = y;
581
582 // ensure that the first point is not an arc specification
583 if( ang < -MIN_ANG || ang > MIN_ANG )
584 {
585 ostringstream ostr;
586
587 ostr << "\n* invalid outline: RECORD 3 of ";
588 ostr << GetOutlineTypeString( outlineType ) << "\n";
589 ostr << "* violation: first point of an outline has a non-zero angle\n";
590 ostr << "* line: '" << iline << "'\n";
591 ostr << "* file position: " << pos;
592
593 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
594 }
595 }
596 else
597 {
598 // Nth point
599 if( closed )
600 {
601 ostringstream ostr;
602
603 ostr << "\n* invalid outline: RECORD 3 of ";
604 ostr << GetOutlineTypeString( outlineType ) << "\n";
605 ostr << "* violation: adding a segment to a closed outline\n";
606 ostr << "* line: '" << iline << "'\n";
607 ostr << "* file position: " << pos;
608
609 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
610 }
611
612 curPt.x = x;
613 curPt.y = y;
614
615 try
616 {
617 if( ang > -MIN_ANG && ang < MIN_ANG )
618 {
619 sp = new IDF_SEGMENT( prePt, curPt );
620 }
621 else
622 {
623 sp = new IDF_SEGMENT( prePt, curPt, ang, false );
624 }
625 }
626 catch( std::bad_alloc& )
627 {
629 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
630 "memory allocation failed" ) );
631 }
632
633 if( sp->IsCircle() )
634 {
635 // this is a circle; the loop is closed
636 if( op->size() != 0 )
637 {
638 delete sp;
639
640 ostringstream ostr;
641
642 ostr << "\n* invalid outline: RECORD 3 of ";
643 ostr << GetOutlineTypeString( outlineType ) << "\n";
644 ostr << "* violation: adding a circle to a non-empty outline\n";
645 ostr << "* line: '" << iline << "'\n";
646 ostr << "* file position: " << pos;
647
648 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
649 }
650
651 closed = true;
652 }
653 else if( op->size() != 0 )
654 {
655 if( curPt.Matches( op->front()->startPoint, dLoc ) )
656 closed = true;
657 }
658
659 op->push( sp );
660 prePt.x = x;
661 prePt.y = y;
662 }
663 }
664
665 // NOTE:
666 // 1. ideally we would ensure that there are no arcs with a radius of 0
667
668 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
669 "problems reading file (premature end of outline)" ) );
670
671 return;
672}
673
674
675bool BOARD_OUTLINE::writeComments( std::ostream& aBoardFile )
676{
677 if( comments.empty() )
678 return true;
679
680 list< string >::const_iterator itS = comments.begin();
681 list< string >::const_iterator itE = comments.end();
682
683 while( itS != itE )
684 {
685 aBoardFile << "# " << *itS << "\n";
686 ++itS;
687 }
688
689 return !aBoardFile.fail();
690}
691
692
693bool BOARD_OUTLINE::writeOwner( std::ostream& aBoardFile )
694{
695 switch( owner )
696 {
697 case KEY_OWNER::ECAD:
698 aBoardFile << "ECAD\n";
699 break;
700
701 case KEY_OWNER::MCAD:
702 aBoardFile << "MCAD\n";
703 break;
704
705 default:
706 aBoardFile << "UNOWNED\n";
707 break;
708 }
709
710 return !aBoardFile.fail();
711}
712
713
714void BOARD_OUTLINE::writeOutline( std::ostream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex )
715{
716 std::list<IDF_SEGMENT*>::iterator bo;
717 std::list<IDF_SEGMENT*>::iterator eo;
718
719 if( !aOutline )
720 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
721 "\n* BUG: nullptr outline pointer" ) );
722
723 if( aOutline->size() == 1 )
724 {
725 if( !aOutline->front()->IsCircle() )
726 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
727 "bad outline (single segment item, not circle)" ) );
728
729 if( single )
730 aIndex = 0;
731
732 // NOTE: a circle always has an angle of 360, never -360,
733 // otherwise SolidWorks chokes on the file.
735 {
736 aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(5)
737 << aOutline->front()->startPoint.x << " "
738 << aOutline->front()->startPoint.y << " 0\n";
739
740 aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(5)
741 << aOutline->front()->endPoint.x << " "
742 << aOutline->front()->endPoint.y << " 360\n";
743 }
744 else
745 {
746 aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1)
747 << (aOutline->front()->startPoint.x / IDF_THOU_TO_MM) << " "
748 << (aOutline->front()->startPoint.y / IDF_THOU_TO_MM) << " 0\n";
749
750 aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1)
751 << (aOutline->front()->endPoint.x / IDF_THOU_TO_MM) << " "
752 << (aOutline->front()->endPoint.y / IDF_THOU_TO_MM) << " 360\n";
753 }
754
755 return;
756 }
757
758 if( single )
759 {
760 // only indices 0 (CCW) and 1 (CW) are valid; set the index according to
761 // the outline's winding
762 if( aOutline->IsCCW() )
763 aIndex = 0;
764 else
765 aIndex = 1;
766 }
767
768
769 // check if we must reverse things
770 if( ( aOutline->IsCCW() && ( aIndex > 0 ) ) || ( ( !aOutline->IsCCW() ) && ( aIndex == 0 ) ) )
771 {
772 eo = aOutline->begin();
773 bo = aOutline->end();
774 --bo;
775
776 // ensure that the very last point is the same as the very first point
777 if( aOutline->size() > 1 )
778 {
779 std::list<IDF_SEGMENT*>::iterator to = eo;
780 ++to;
781 (*to)->startPoint = (*eo)->endPoint;
782 }
783
784 // for the first item we write out both points
786 {
787 if( aOutline->front()->angle < MIN_ANG && aOutline->front()->angle > -MIN_ANG )
788 {
789 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
790 << aOutline->front()->endPoint.x << " " << aOutline->front()->endPoint.y
791 << " 0\n";
792
793 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
794 << aOutline->front()->startPoint.x << " "
795 << aOutline->front()->startPoint.y << " 0\n";
796 }
797 else
798 {
799 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
800 << aOutline->front()->endPoint.x << " " << aOutline->front()->endPoint.y
801 << " 0\n";
802
803 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
804 << aOutline->front()->startPoint.x << " "
805 << aOutline->front()->startPoint.y << " " << setprecision( 3 )
806 << -aOutline->front()->angle << "\n";
807 }
808 }
809 else
810 {
811 if( aOutline->front()->angle < MIN_ANG && aOutline->front()->angle > -MIN_ANG )
812 {
813 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
814 << ( aOutline->front()->endPoint.x / IDF_THOU_TO_MM ) << " "
815 << ( aOutline->front()->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
816
817 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
818 << ( aOutline->front()->startPoint.x / IDF_THOU_TO_MM ) << " "
819 << ( aOutline->front()->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
820 }
821 else
822 {
823 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
824 << ( aOutline->front()->endPoint.x / IDF_THOU_TO_MM ) << " "
825 << ( aOutline->front()->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
826
827 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
828 << ( aOutline->front()->startPoint.x / IDF_THOU_TO_MM ) << " "
829 << ( aOutline->front()->startPoint.y / IDF_THOU_TO_MM ) << " "
830 << setprecision( 3 ) << -aOutline->front()->angle << "\n";
831 }
832 }
833
834 // for all other segments we only write out the start point
835 while( bo != eo )
836 {
838 {
839 if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
840 {
841 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
842 << ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " 0\n";
843 }
844 else
845 {
846 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
847 << ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " "
848 << setprecision( 3 ) << -( *bo )->angle << "\n";
849 }
850 }
851 else
852 {
853 if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
854 {
855 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
856 << ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
857 << ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
858 }
859 else
860 {
861 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
862 << ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
863 << ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " "
864 << setprecision( 3 ) << -( *bo )->angle << "\n";
865 }
866 }
867
868 --bo;
869 }
870 }
871 else
872 {
873 // ensure that the very last point is the same as the very first point
874 if( aOutline->size() > 1 )
875 aOutline->back()-> endPoint = aOutline->front()->startPoint;
876
877 bo = aOutline->begin();
878 eo = aOutline->end();
879
880 // for the first item we write out both points
882 {
883 if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
884 {
885 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
886 << ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " 0\n";
887
888 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
889 << ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " 0\n";
890 }
891 else
892 {
893 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
894 << ( *bo )->startPoint.x << " " << ( *bo )->startPoint.y << " 0\n";
895
896 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
897 << ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " "
898 << setprecision( 3 ) << ( *bo )->angle << "\n";
899 }
900 }
901 else
902 {
903 if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
904 {
905 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
906 << ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
907 << ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
908
909 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
910 << ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
911 << ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
912 }
913 else
914 {
915 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
916 << ( ( *bo )->startPoint.x / IDF_THOU_TO_MM ) << " "
917 << ( ( *bo )->startPoint.y / IDF_THOU_TO_MM ) << " 0\n";
918
919 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
920 << ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
921 << ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " " << setprecision( 3 )
922 << ( *bo )->angle << "\n";
923 }
924 }
925
926 ++bo;
927
928 // for all other segments we only write out the last point
929 while( bo != eo )
930 {
932 {
933 if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
934 {
935 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
936 << ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " 0\n";
937 }
938 else
939 {
940 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 5 )
941 << ( *bo )->endPoint.x << " " << ( *bo )->endPoint.y << " "
942 << setprecision( 3 ) << ( *bo )->angle << "\n";
943 }
944 }
945 else
946 {
947 if( ( *bo )->angle < MIN_ANG && ( *bo )->angle > -MIN_ANG )
948 {
949 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
950 << ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
951 << ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " 0\n";
952 }
953 else
954 {
955 aBoardFile << aIndex << " " << setiosflags( ios::fixed ) << setprecision( 1 )
956 << ( ( *bo )->endPoint.x / IDF_THOU_TO_MM ) << " "
957 << ( ( *bo )->endPoint.y / IDF_THOU_TO_MM ) << " "
958 << setprecision( 3 ) << ( *bo )->angle << "\n";
959 }
960 }
961
962 ++bo;
963 }
964 }
965}
966
967
968void BOARD_OUTLINE::writeOutlines( std::ostream& aBoardFile )
969{
970 if( outlines.empty() )
971 return;
972
973 int idx = 0;
974 std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
975 std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
976
977 while( itS != itE )
978 {
979 writeOutline( aBoardFile, *itS, idx++ );
980 ++itS;
981 }
982}
983
984
986{
987 // note: although IDF_UNIT::UNIT_TNM is accepted here without reservation,
988 // this can only affect data being read from a file.
989 if( aUnit != IDF_UNIT::UNIT_MM && aUnit != IDF_UNIT::UNIT_THOU && aUnit != IDF_UNIT::UNIT_TNM )
990 {
991 ostringstream ostr;
992 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
993 ostr << "* BUG: invalid IDF UNIT: " << static_cast<int>( aUnit ) << "\n";
994 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
995 errormsg = ostr.str();
996
997 return false;
998 }
999
1000 unit = aUnit;
1001 return true;
1002}
1003
1004
1006{
1007 return unit;
1008}
1009
1010
1011bool BOARD_OUTLINE::setThickness( double aThickness )
1012{
1013 if( aThickness < 0.0 )
1014 {
1015 ostringstream ostr;
1016 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1017 ostr << "* BUG: aThickness < 0.0\n";
1018 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
1019 errormsg = ostr.str();
1020
1021 return false;
1022 }
1023
1024 thickness = aThickness;
1025 return true;
1026}
1027
1028
1029bool BOARD_OUTLINE::SetThickness( double aThickness )
1030{
1031#ifndef DISABLE_IDF_OWNERSHIP
1032 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1033 return false;
1034#endif
1035
1036 return setThickness( aThickness );
1037}
1038
1039
1041{
1042 return thickness;
1043}
1044
1045void BOARD_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
1046 IDF3::IDF_VERSION aIdfVersion )
1047{
1048 // BOARD_OUTLINE (PANEL_OUTLINE)
1049 // .BOARD_OUTLINE [OWNER]
1050 // [thickness]
1051 // [outlines]
1052
1053 // check RECORD 1
1054 std::string token;
1055 bool quoted = false;
1056 int idx = 0;
1057 std::streampos pos;
1058
1059 pos = aBoardFile.tellg();
1060
1061 if( !GetIDFString( aHeader, token, quoted, idx ) )
1062 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1063 "invalid invocation: blank header line" ) );
1064
1065 if( quoted )
1066 {
1067 ostringstream ostr;
1068
1069 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1070 ostr << "* violation: section names may not be in quotes\n";
1071 ostr << "* line: '" << aHeader << "'\n";
1072 ostr << "* file position: " << pos;
1073
1074 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1075 }
1076
1077 if( !CompareToken( ".BOARD_OUTLINE", token ) )
1078 {
1079 ostringstream ostr;
1080
1081 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1082 ostr << "* violation: not a board outline\n";
1083 ostr << "* line: '" << aHeader << "'\n";
1084 ostr << "* file position: " << pos;
1085
1086 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1087 }
1088
1089 if( !GetIDFString( aHeader, token, quoted, idx ) )
1090 {
1091 if( aIdfVersion > IDF_VERSION::IDF_V2 )
1092 ERROR_IDF << "no OWNER; setting to UNOWNED\n";
1093
1095 }
1096 else
1097 {
1098 if( !ParseOwner( token, owner ) )
1099 {
1100 ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
1102 }
1103 }
1104
1105 // check RECORD 2
1106 std::string iline;
1107 bool comment = false;
1108 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
1109
1110 if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() )
1111 {
1112 ostringstream ostr;
1113
1114 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1115 ostr << "* violation: premature end\n";
1116 ostr << "* file position: " << pos;
1117
1118 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1119 }
1120
1121 idx = 0;
1122
1123 if( comment )
1124 {
1125 ostringstream ostr;
1126
1127 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1128 ostr << "* violation: comment within .BOARD_OUTLINE section\n";
1129 ostr << "* line: '" << iline << "'\n";
1130 ostr << "* file position: " << pos;
1131
1132 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1133 }
1134
1135 if( !GetIDFString( iline, token, quoted, idx ) )
1136 {
1137 ostringstream ostr;
1138
1139 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1140 ostr << "* violation: no thickness specified\n";
1141 ostr << "* file position: " << pos;
1142
1143 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1144 }
1145
1146 std::stringstream teststr;
1147 teststr << token;
1148
1149 teststr >> thickness;
1150
1151 if( teststr.fail() )
1152 {
1153 ostringstream ostr;
1154
1155 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1156 ostr << "* violation: invalid RECORD 2 (thickness)\n";
1157 ostr << "* line: '" << iline << "'\n";
1158 ostr << "* file position: " << pos;
1159
1160 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1161 }
1162
1163 if( unit == IDF_UNIT::UNIT_THOU )
1164 {
1166 }
1167 else if( ( aIdfVersion == IDF_VERSION::IDF_V2 ) && ( unit == IDF_UNIT::UNIT_TNM ) )
1168 {
1170 }
1171 else if( unit != IDF_UNIT::UNIT_MM )
1172 {
1173 ostringstream ostr;
1174 ostr << "\n* BUG: invalid UNIT type: " << static_cast<int>( unit );
1175
1176 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1177 }
1178
1179 // for some unknown reason IDF allows 0 or negative thickness, but this
1180 // is a problem so we fix it here
1181 if( thickness <= 0.0 )
1182 {
1183 if( thickness == 0.0 )
1184 {
1185 ERROR_IDF << "\n* WARNING: setting board thickness to default 1.6mm (";
1186 cerr << thickness << ")\n";
1187 thickness = 1.6;
1188 }
1189 else
1190 {
1192 ERROR_IDF << "\n* WARNING: setting board thickness to positive number (";
1193 cerr << thickness << ")\n";
1194 }
1195 }
1196
1197 // read RECORD 3 values
1198 readOutlines( aBoardFile, aIdfVersion );
1199
1200 // check RECORD 4
1201 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
1202
1203 if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
1204 {
1205 ostringstream ostr;
1206
1207 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1208 ostr << "* violation: premature end\n";
1209 ostr << "* file position: " << pos;
1210
1211 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1212 }
1213
1214 idx = 0;
1215
1216 if( comment )
1217 {
1218 ostringstream ostr;
1219
1220 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1221 ostr << "* violation: comment within section\n";
1222 ostr << "* line: '" << iline << "'\n";
1223 ostr << "* file position: " << pos;
1224
1225 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1226 }
1227
1228 if( !CompareToken( ".END_BOARD_OUTLINE", iline ) )
1229 {
1230 ostringstream ostr;
1231
1232 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1233 ostr << "* violation: no .END_BOARD_OUTLINE found\n";
1234 ostr << "* file position: " << pos;
1235
1236 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1237 }
1238}
1239
1240
1241void BOARD_OUTLINE::writeData( std::ostream& aBoardFile )
1242{
1243 writeComments( aBoardFile );
1244
1245 // note: a BOARD_OUTLINE section is required, even if it is empty
1246 aBoardFile << ".BOARD_OUTLINE ";
1247
1248 writeOwner( aBoardFile );
1249
1250 if( unit != IDF_UNIT::UNIT_THOU )
1251 aBoardFile << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << "\n";
1252 else
1253 aBoardFile << setiosflags( ios::fixed ) << setprecision( 1 )
1254 << ( thickness / IDF_THOU_TO_MM ) << "\n";
1255
1256 writeOutlines( aBoardFile );
1257
1258 aBoardFile << ".END_BOARD_OUTLINE\n\n";
1259}
1260
1262{
1263 comments.clear();
1264 clearOutlines();
1265
1267 return;
1268}
1269
1270
1272{
1273#ifndef DISABLE_IDF_OWNERSHIP
1274 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1275 return false;
1276#endif
1277
1278 clear();
1279
1280 return true;
1281}
1282
1283
1285{
1286 parent = aParent;
1287}
1288
1289
1291{
1292 return parent;
1293}
1294
1295
1297{
1298 std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
1299 std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
1300
1301 try
1302 {
1303 while( itS != itE )
1304 {
1305 if( *itS == aOutline )
1306 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
1307 "duplicate outline pointer" ) );
1308
1309 ++itS;
1310 }
1311
1312 outlines.push_back( aOutline );
1313
1314 }
1315 catch( const std::exception& e )
1316 {
1317 errormsg = e.what();
1318
1319 return false;
1320 }
1321
1322 return true;
1323}
1324
1325
1327{
1328#ifndef DISABLE_IDF_OWNERSHIP
1329 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1330 return false;
1331#endif
1332
1333 return addOutline( aOutline );
1334}
1335
1336
1338{
1339 std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
1340 std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
1341
1342 if( !aOutline )
1343 {
1344 ostringstream ostr;
1345 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1346 ostr << "* BUG: nullptr aOutline pointer\n";
1347 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
1348 errormsg = ostr.str();
1349
1350 return false;
1351 }
1352
1353 if( outlines.empty() )
1354 {
1355 errormsg.clear();
1356 return false;
1357 }
1358
1359 // if there are more than 1 outlines it makes no sense to delete
1360 // the first outline (board outline) since that would have the
1361 // undesirable effect of substituting a cutout outline as the board outline
1362 if( aOutline == outlines.front() )
1363 {
1364 if( outlines.size() > 1 )
1365 {
1366 ostringstream ostr;
1367 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1368 ostr << "* BUG: attempting to delete first outline in list\n";
1369 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
1370 errormsg = ostr.str();
1371
1372 return false;
1373 }
1374
1375 outlines.clear();
1376 return true;
1377 }
1378
1379 while( itS != itE )
1380 {
1381 if( *itS == aOutline )
1382 {
1383 outlines.erase( itS );
1384 return true;
1385 }
1386
1387 ++itS;
1388 }
1389
1390 errormsg.clear();
1391 return false;
1392}
1393
1394
1395bool BOARD_OUTLINE::DelOutline( size_t aIndex )
1396{
1397 std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
1398
1399 if( outlines.empty() )
1400 {
1401 errormsg.clear();
1402 return false;
1403 }
1404
1405 if( aIndex >= outlines.size() )
1406 {
1407 ostringstream ostr;
1408 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1409 ostr << "* BUG: index out of bounds (" << aIndex << " / " << outlines.size() << ")\n";
1410 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
1411 errormsg = ostr.str();
1412
1413 return false;
1414 }
1415
1416 if( aIndex == 0 )
1417 {
1418 // if there are more than 1 outlines it makes no sense to delete
1419 // the first outline (board outline) since that would have the
1420 // undesirable effect of substituting a cutout outline as the board outline
1421 if( outlines.size() > 1 )
1422 {
1423 ostringstream ostr;
1424 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1425 ostr << "* BUG: attempting to delete first outline in list\n";
1426 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
1427 errormsg = ostr.str();
1428
1429 return false;
1430 }
1431
1432 delete *itS;
1433 outlines.clear();
1434
1435 return true;
1436 }
1437
1438 for( ; aIndex > 0; --aIndex )
1439 ++itS;
1440
1441 delete *itS;
1442 outlines.erase( itS );
1443
1444 return true;
1445}
1446
1447
1448const std::list<IDF_OUTLINE*>* BOARD_OUTLINE::GetOutlines( void )
1449{
1450 return &outlines;
1451}
1452
1453
1455{
1456 return outlines.size();
1457}
1458
1459
1461{
1462 if( aIndex >= outlines.size() )
1463 {
1464 ostringstream ostr;
1465 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1466 ostr << "* aIndex (" << aIndex << ") is out of range (" << outlines.size() << ")";
1467 errormsg = ostr.str();
1468
1469 return nullptr;
1470 }
1471
1472 std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
1473
1474 for( ; aIndex > 0; --aIndex )
1475 ++itS;
1476
1477 return *itS;
1478}
1479
1480
1482{
1483 return owner;
1484}
1485
1486
1488{
1489#ifndef DISABLE_IDF_OWNERSHIP
1490 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1491 return false;
1492#endif
1493
1494 owner = aOwner;
1495 return true;
1496}
1497
1498
1500{
1501 return single;
1502}
1503
1504
1506{
1507 std::list< IDF_OUTLINE* >::iterator itS = outlines.begin();
1508 std::list< IDF_OUTLINE* >::iterator itE = outlines.end();
1509
1510 while( itS != itE )
1511 {
1512 delete *itS;
1513 ++itS;
1514 }
1515
1516 outlines.clear();
1517}
1518
1519
1520void BOARD_OUTLINE::AddComment( const std::string& aComment )
1521{
1522 if( aComment.empty() )
1523 return;
1524
1525 comments.push_back( aComment );
1526}
1527
1528
1530{
1531 return comments.size();
1532}
1533
1534
1535std::list< std::string >* BOARD_OUTLINE::GetComments( void )
1536{
1537 return &comments;
1538}
1539
1540
1541const std::string* BOARD_OUTLINE::GetComment( size_t aIndex )
1542{
1543 if( aIndex >= comments.size() )
1544 return nullptr;
1545
1546 std::list< std::string >::iterator itS = comments.begin();
1547
1548 for( ; aIndex > 0; --aIndex )
1549 ++itS;
1550
1551 return &(*itS);
1552}
1553
1554
1555bool BOARD_OUTLINE::DeleteComment( size_t aIndex )
1556{
1557 if( aIndex >= comments.size() )
1558 return false;
1559
1560 std::list< std::string >::iterator itS = comments.begin();
1561
1562 for( ; aIndex > 0; --aIndex )
1563 ++itS;
1564
1565 comments.erase( itS );
1566 return true;
1567}
1568
1569
1571{
1572 comments.clear();
1573}
1574
1575
1583
1584
1585bool OTHER_OUTLINE::SetOutlineIdentifier( const std::string& aUniqueID )
1586{
1587#ifndef DISABLE_IDF_OWNERSHIP
1588 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1589 return false;
1590#endif
1591
1592 uniqueID = aUniqueID;
1593
1594 return true;
1595}
1596
1597
1598const std::string& OTHER_OUTLINE::GetOutlineIdentifier( void )
1599{
1600 return uniqueID;
1601}
1602
1603
1605{
1606#ifndef DISABLE_IDF_OWNERSHIP
1607 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1608 return false;
1609#endif
1610
1611 switch( aSide )
1612 {
1613 case IDF_LAYER::LYR_TOP:
1615 side = aSide;
1616 break;
1617
1618 default:
1619 do
1620 {
1621 ostringstream ostr;
1622 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
1623 ostr << "* BUG: invalid side (" << static_cast<int>( aSide ) << "); must be one of TOP/BOTTOM\n";
1624 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
1625 errormsg = ostr.str();
1626 } while( 0 );
1627
1629 return false;
1630
1631 break;
1632 }
1633
1634 return true;
1635}
1636
1637
1639{
1640 return side;
1641}
1642
1643
1644void OTHER_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
1645 IDF3::IDF_VERSION aIdfVersion )
1646{
1647 // OTHER_OUTLINE/VIA_KEEPOUT
1648 // .OTHER_OUTLINE [OWNER]
1649 // [outline identifier] [thickness] [board side: Top/Bot] {not present in VA\IA KEEPOUT}
1650 // [outline]
1651
1652 // check RECORD 1
1653 std::string token;
1654 bool quoted = false;
1655 int idx = 0;
1656 std::streampos pos = aBoardFile.tellg();
1657
1658 if( !GetIDFString( aHeader, token, quoted, idx ) )
1659 {
1660 ostringstream ostr;
1661 ostr << "\n* BUG: invalid invocation: blank header line\n";
1662
1663 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1664 }
1665
1666 if( quoted )
1667 {
1668 ostringstream ostr;
1669
1670 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1671 ostr << "* violation: section names must not be in quotes\n";
1672 ostr << "* line: '" << aHeader << "'\n";
1673 ostr << "* file position: " << pos;
1674
1675 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1676 }
1677
1679 {
1680 if( !CompareToken( ".OTHER_OUTLINE", token ) )
1681 {
1682 ostringstream ostr;
1683
1684 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1685 ostr << "* BUG: not an .OTHER outline\n";
1686
1687 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1688 }
1689 }
1690 else
1691 {
1692 if( !CompareToken( ".VIA_KEEPOUT", token ) )
1693 {
1694 ostringstream ostr;
1695
1696 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1697 ostr << "* BUG: not a .VIA_KEEPOUT outline\n";
1698
1699 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1700 }
1701 }
1702
1703 if( !GetIDFString( aHeader, token, quoted, idx ) )
1704 {
1705 if( aIdfVersion > IDF_VERSION::IDF_V2 )
1706 ERROR_IDF << "no OWNER; setting to UNOWNED\n";
1707
1709 }
1710 else
1711 {
1712 if( !ParseOwner( token, owner ) )
1713 {
1714 ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
1716 }
1717 }
1718
1719 std::string iline;
1720 bool comment = false;
1721
1723 {
1724 // check RECORD 2
1725 // [outline identifier] [thickness] [board side: Top/Bot]
1726 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
1727
1728 if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
1729 {
1730 ostringstream ostr;
1731
1732 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1733 ostr << "* violation: premature end\n";
1734 ostr << "* file position: " << pos;
1735
1736 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1737 }
1738
1739 idx = 0;
1740 if( comment )
1741 {
1742 ostringstream ostr;
1743
1744 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1745 ostr << "* violation: comment within .OTHER_OUTLINE section\n";
1746 ostr << "* line: '" << iline << "'\n";
1747 ostr << "* file position: " << pos;
1748
1749 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1750 }
1751
1752 if( !GetIDFString( iline, token, quoted, idx ) )
1753 {
1754 ostringstream ostr;
1755
1756 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1757 ostr << "* violation: no outline identifier\n";
1758 ostr << "* line: '" << iline << "'\n";
1759 ostr << "* file position: " << pos;
1760
1761 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1762 }
1763
1764 uniqueID = token;
1765
1766 if( !GetIDFString( iline, token, quoted, idx ) )
1767 {
1768 ostringstream ostr;
1769
1770 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1771 ostr << "* violation: no thickness\n";
1772 ostr << "* line: '" << iline << "'\n";
1773 ostr << "* file position: " << pos;
1774
1775 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1776 }
1777
1778 std::stringstream teststr;
1779 teststr << token;
1780
1781 teststr >> thickness;
1782
1783 if( teststr.fail() )
1784 {
1785 ostringstream ostr;
1786
1787 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1788 ostr << "* violation: invalid thickness\n";
1789 ostr << "* line: '" << iline << "'\n";
1790 ostr << "* file position: " << pos;
1791
1792 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1793 }
1794
1795 if( unit == IDF_UNIT::UNIT_THOU )
1796 {
1798 }
1799 else if( ( aIdfVersion == IDF_VERSION::IDF_V2 ) && ( unit == IDF_UNIT::UNIT_TNM ) )
1800 {
1802 }
1803 else if( unit != IDF_UNIT::UNIT_MM )
1804 {
1805 ostringstream ostr;
1806 ostr << "\n* BUG: invalid UNIT type: " << static_cast<int>( unit );
1807
1808 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1809 }
1810
1811 if( aIdfVersion == IDF_VERSION::IDF_V2 )
1812 {
1814 }
1815 else
1816 {
1817 if( !GetIDFString( iline, token, quoted, idx ) )
1818 {
1819 ostringstream ostr;
1820
1821 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1822 ostr << "* violation: no board side\n";
1823 ostr << "* line: '" << iline << "'\n";
1824 ostr << "* file position: " << pos;
1825
1826 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1827 }
1828
1829 if( !ParseIDFLayer( token, side ) || ( side != IDF_LAYER::LYR_TOP && side != IDF_LAYER::LYR_BOTTOM ) )
1830 {
1831 ostringstream ostr;
1832
1833 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1834 ostr << "* violation: invalid side (must be TOP or BOTTOM only)\n";
1835 ostr << "* line: '" << iline << "'\n";
1836 ostr << "* file position: " << pos;
1837
1838 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1839 }
1840 }
1841
1842 }
1843
1844 // read RECORD 3 values
1845 readOutlines( aBoardFile, aIdfVersion );
1846
1847 // check RECORD 4
1848 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
1849
1850 if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
1851 {
1852 ostringstream ostr;
1853
1854 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1855 ostr << "* violation: premature end\n";
1856 ostr << "* file position: " << pos;
1857
1858 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1859 }
1860
1861 idx = 0;
1862
1863 if( comment )
1864 {
1865 ostringstream ostr;
1866
1867 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1868 ostr << "* violation: comment within section\n";
1869 ostr << "* line: '" << iline << "'\n";
1870 ostr << "* file position: " << pos;
1871
1872 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1873 }
1874
1876 {
1877 if( !CompareToken( ".END_OTHER_OUTLINE", iline ) )
1878 {
1879 ostringstream ostr;
1880
1881 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1882 ostr << "* violation: no .END_OTHER_OUTLINE found\n";
1883 ostr << "* file position: " << pos;
1884
1885 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1886 }
1887 }
1888 else
1889 {
1890 if( !CompareToken( ".END_VIA_KEEPOUT", iline ) )
1891 {
1892 ostringstream ostr;
1893
1894 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
1895 ostr << "* violation: no .END_VIA_KEEPOUT found\n";
1896 ostr << "* file position: " << pos;
1897
1898 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1899 }
1900 }
1901}
1902
1903
1904void OTHER_OUTLINE::writeData( std::ostream& aBoardFile )
1905{
1906 // this section is optional; do not write if not required
1907 if( outlines.empty() )
1908 return;
1909
1910 writeComments( aBoardFile );
1911
1912 // write RECORD 1
1914 aBoardFile << ".OTHER_OUTLINE ";
1915 else
1916 aBoardFile << ".VIA_KEEPOUT ";
1917
1918 writeOwner( aBoardFile );
1919
1920 // write RECORD 2
1922 {
1923 aBoardFile << "\"" << uniqueID << "\" ";
1924
1925 if( unit != IDF_UNIT::UNIT_THOU )
1926 aBoardFile << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << " ";
1927 else
1928 aBoardFile << setiosflags( ios::fixed ) << setprecision( 1 )
1929 << ( thickness / IDF_THOU_TO_MM ) << " ";
1930
1931 switch( side )
1932 {
1933 case IDF_LAYER::LYR_TOP:
1935 WriteLayersText( aBoardFile, side );
1936 break;
1937
1938 default:
1939 do
1940 {
1941 ostringstream ostr;
1942 ostr << "\n* invalid OTHER_OUTLINE side (neither top nor bottom): ";
1943 ostr << static_cast<int>( side );
1944 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
1945 } while( 0 );
1946
1947 break;
1948 }
1949 }
1950
1951 // write RECORD 3
1952 writeOutlines( aBoardFile );
1953
1954 // write RECORD 4
1956 aBoardFile << ".END_OTHER_OUTLINE\n\n";
1957 else
1958 aBoardFile << ".END_VIA_KEEPOUT\n\n";
1959}
1960
1961
1963{
1964#ifndef DISABLE_IDF_OWNERSHIP
1965 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1966 return false;
1967#endif
1968
1969 clear();
1971 uniqueID.clear();
1972
1973 return true;
1974}
1975
1976
1984
1985
1987{
1988#ifndef DISABLE_IDF_OWNERSHIP
1989 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
1990 return false;
1991#endif
1992
1993 layers = aLayer;
1994
1995 return true;
1996}
1997
1998
2000{
2001 return layers;
2002}
2003
2004
2005void ROUTE_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
2006 IDF3::IDF_VERSION aIdfVersion )
2007{
2008 // ROUTE_OUTLINE (or ROUTE_KEEPOUT)
2009 // .ROUTE_OUTLINE [OWNER]
2010 // [layers]
2011 // [outline]
2012
2013 // check RECORD 1
2014 std::string token;
2015 bool quoted = false;
2016 int idx = 0;
2017 std::streampos pos = aBoardFile.tellg();
2018
2019 if( !GetIDFString( aHeader, token, quoted, idx ) )
2020 {
2021 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2022 "\n* BUG: invalid invocation; blank header line" ) );
2023 }
2024
2025 if( quoted )
2026 {
2027 ostringstream ostr;
2028
2029 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2030 ostr << "* violation: section names must not be in quotes\n";
2031 ostr << "* line: '" << aHeader << "'\n";
2032 ostr << "* file position: " << pos;
2033
2034 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2035 }
2036
2038 {
2039 if( !CompareToken( ".ROUTE_OUTLINE", token ) )
2040 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2041 "\n* BUG: not a ROUTE outline" ) );
2042 }
2043 else
2044 {
2045 if( !CompareToken( ".ROUTE_KEEPOUT", token ) )
2046 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2047 "\n* BUG: not a ROUTE KEEPOUT outline" ) );
2048 }
2049
2050 if( !GetIDFString( aHeader, token, quoted, idx ) )
2051 {
2052 if( aIdfVersion > IDF_VERSION::IDF_V2 )
2053 ERROR_IDF << "no OWNER; setting to UNOWNED\n";
2054
2056 }
2057 else
2058 {
2059 if( !ParseOwner( token, owner ) )
2060 {
2061 ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
2063 }
2064 }
2065
2066 // check RECORD 2
2067 // [layers: TOP, BOTTOM, BOTH, INNER, ALL]
2068 std::string iline;
2069 bool comment = false;
2070
2072 {
2073 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
2074
2075 if( !aBoardFile.good() )
2076 {
2077 ostringstream ostr;
2078
2079 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2080 ostr << "* violation: premature end\n";
2081 ostr << "* file position: " << pos;
2082
2083 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2084 }
2085
2086 idx = 0;
2087
2088 if( comment )
2089 {
2090 ostringstream ostr;
2091
2092 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2093 ostr << "* violation: comment within a section\n";
2094 ostr << "* line: '" << iline << "'\n";
2095 ostr << "* file position: " << pos;
2096
2097 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2098 }
2099
2100 if( !GetIDFString( iline, token, quoted, idx ) )
2101 {
2102 ostringstream ostr;
2103
2104 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2105 ostr << "* violation: no layers specification\n";
2106 ostr << "* line: '" << iline << "'\n";
2107 ostr << "* file position: " << pos;
2108
2109 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2110 }
2111
2112 if( quoted )
2113 {
2114 ostringstream ostr;
2115
2116 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2117 ostr << "* violation: layers specification must not be in quotes\n";
2118 ostr << "* line: '" << iline << "'\n";
2119 ostr << "* file position: " << pos;
2120
2121 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2122 }
2123
2124 if( !ParseIDFLayer( token, layers ) )
2125 {
2126 ostringstream ostr;
2127
2128 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2129 ostr << "* violation: invalid layers specification\n";
2130 ostr << "* line: '" << iline << "'\n";
2131 ostr << "* file position: " << pos;
2132
2133 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2134 }
2135
2136 if( aIdfVersion == IDF_VERSION::IDF_V2 )
2137 {
2139 {
2140 ostringstream ostr;
2141
2142 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2143 ostr << "* violation: IDFv2 allows only TOP/BOTTOM/BOTH; layer was '";
2144 ostr << token << "'\n";
2145 ostr << "* line: '" << iline << "'\n";
2146 ostr << "* file position: " << pos;
2147
2148 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2149 }
2150 }
2151 }
2152 else
2153 {
2155 }
2156
2157 // read RECORD 3 values
2158 readOutlines( aBoardFile, aIdfVersion );
2159
2160 // check RECORD 4
2161 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
2162
2163 if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
2164 {
2165 ostringstream ostr;
2166
2167 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2168 ostr << "* violation: premature end\n";
2169 ostr << "* file position: " << pos;
2170
2171 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2172 }
2173
2174 idx = 0;
2175
2176 if( comment )
2177 {
2178 ostringstream ostr;
2179
2180 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2181 ostr << "* violation: comment within section\n";
2182 ostr << "* line: '" << iline << "'\n";
2183 ostr << "* file position: " << pos;
2184
2185 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2186 }
2187
2189 {
2190 if( !CompareToken( ".END_ROUTE_OUTLINE", iline ) )
2191 {
2192 ostringstream ostr;
2193
2194 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2195 ostr << "* violation: no .END_ROUTE_OUTLINE found\n";
2196 ostr << "* file position: " << pos;
2197
2198 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2199 }
2200 }
2201 else
2202 {
2203 if( !CompareToken( ".END_ROUTE_KEEPOUT", iline ) )
2204 {
2205 ostringstream ostr;
2206
2207 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2208 ostr << "* violation: no .END_ROUTE_KEEPOUT found\n";
2209 ostr << "* file position: " << pos;
2210
2211 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2212 }
2213 }
2214}
2215
2216
2217void ROUTE_OUTLINE::writeData( std::ostream& aBoardFile )
2218{
2219 // this section is optional; do not write if not required
2220 if( outlines.empty() )
2221 return;
2222
2224 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2225 "layer not specified" ) );
2226
2227 writeComments( aBoardFile );
2228
2229 // write RECORD 1
2231 aBoardFile << ".ROUTE_OUTLINE ";
2232 else
2233 aBoardFile << ".ROUTE_KEEPOUT ";
2234
2235 writeOwner( aBoardFile );
2236
2237 // write RECORD 2
2238 WriteLayersText( aBoardFile, layers );
2239 aBoardFile << "\n";
2240
2241 // write RECORD 3
2242 writeOutlines( aBoardFile );
2243
2244 // write RECORD 4
2246 aBoardFile << ".END_ROUTE_OUTLINE\n\n";
2247 else
2248 aBoardFile << ".END_ROUTE_KEEPOUT\n\n";
2249}
2250
2251
2253{
2254#ifndef DISABLE_IDF_OWNERSHIP
2255 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
2256 return false;
2257#endif
2258
2259 clear();
2261
2262 return true;
2263}
2264
2265
2267{
2268 setParent( aParent );
2270 single = true;
2271 thickness = -1.0;
2273}
2274
2275
2277{
2278#ifndef DISABLE_IDF_OWNERSHIP
2279 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
2280 return false;
2281#endif
2282
2283 switch( aSide )
2284 {
2285 case IDF_LAYER::LYR_TOP:
2288 side = aSide;
2289 break;
2290
2291 default:
2292 do
2293 {
2295 ostringstream ostr;
2296 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
2297 ostr << "* BUG: invalid layer (" << static_cast<int>( aSide ) << "): must be one of TOP/BOTTOM/BOTH\n";
2298 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
2299 errormsg = ostr.str();
2300
2301 return false;
2302 } while( 0 );
2303
2304 break;
2305 }
2306
2307 return true;
2308}
2309
2310
2312{
2313 return side;
2314}
2315
2316
2317bool PLACE_OUTLINE::SetMaxHeight( double aHeight )
2318{
2319#ifndef DISABLE_IDF_OWNERSHIP
2320 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
2321 return false;
2322#endif
2323
2324 if( aHeight < 0.0 )
2325 {
2326 thickness = 0.0;
2327
2328 do
2329 {
2330 ostringstream ostr;
2331 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
2332 ostr << "* BUG: invalid height (" << aHeight << "): must be >= 0.0";
2333 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
2334 errormsg = ostr.str();
2335
2336 return false;
2337 } while( 0 );
2338 }
2339
2340 thickness = aHeight;
2341 return true;
2342}
2343
2344
2346{
2347 return thickness;
2348}
2349
2350
2351void PLACE_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
2352 IDF3::IDF_VERSION aIdfVersion )
2353{
2354 // PLACE_OUTLINE/KEEPOUT
2355 // .PLACE_OUTLINE [OWNER]
2356 // [board side: Top/Bot/Both] [height]
2357 // [outline]
2358
2359 // check RECORD 1
2360 std::string token;
2361 bool quoted = false;
2362 int idx = 0;
2363 std::streampos pos = aBoardFile.tellg();
2364
2365 if( !GetIDFString( aHeader, token, quoted, idx ) )
2366 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2367 "\n* BUG: invalid invocation: blank header line\n" ) );
2368
2369 if( quoted )
2370 {
2371 ostringstream ostr;
2372
2373 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2374 ostr << "* violation: section name must not be in quotes\n";
2375 ostr << "* line: '" << aHeader << "'\n";
2376 ostr << "* file position: " << pos;
2377
2378 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2379 }
2380
2382 {
2383 if( !CompareToken( ".PLACE_OUTLINE", token ) )
2384 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2385 "\n* BUG: not a .PLACE_OUTLINE" ) );
2386 }
2387 else
2388 {
2389 if( !CompareToken( ".PLACE_KEEPOUT", token ) )
2390 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2391 "\n* BUG: not a .PLACE_KEEPOUT" ) );
2392 }
2393
2394 if( !GetIDFString( aHeader, token, quoted, idx ) )
2395 {
2396 if( aIdfVersion > IDF_VERSION::IDF_V2 )
2397 ERROR_IDF << "no OWNER; setting to UNOWNED\n";
2398
2400 }
2401 else
2402 {
2403 if( !ParseOwner( token, owner ) )
2404 {
2405 ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
2407 }
2408 }
2409
2410 // check RECORD 2
2411 // [board side: Top/Bot/Both] [height]
2412 std::string iline;
2413 bool comment = false;
2414
2416 {
2417 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
2418
2419 if( !aBoardFile.good() )
2420 {
2421 ostringstream ostr;
2422
2423 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2424 ostr << "* violation: premature end\n";
2425 ostr << "* file position: " << pos;
2426
2427 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2428 }
2429
2430 idx = 0;
2431
2432 if( comment )
2433 {
2434 ostringstream ostr;
2435
2436 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2437 ostr << "* violation: comment within the section\n";
2438 ostr << "* line: '" << iline << "'\n";
2439 ostr << "* file position: " << pos;
2440
2441 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2442 }
2443
2444 if( !GetIDFString( iline, token, quoted, idx ) )
2445 {
2446 ostringstream ostr;
2447
2448 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2449 ostr << "* violation: no board side information\n";
2450 ostr << "* line: '" << iline << "'\n";
2451 ostr << "* file position: " << pos;
2452
2453 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2454 }
2455
2456 if( !ParseIDFLayer( token, side ) ||
2458 {
2459 ostringstream ostr;
2460
2461 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2462 ostr << "* violation: invalid board side: must be one of TOP/BOTTOM/BOTH\n";
2463 ostr << "* line: '" << iline << "'\n";
2464 ostr << "* file position: " << pos;
2465
2466 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2467 }
2468
2469 if( GetIDFString( iline, token, quoted, idx ) )
2470 {
2471 std::stringstream teststr;
2472 teststr << token;
2473
2474 teststr >> thickness;
2475
2476 if( teststr.fail() )
2477 {
2478 ostringstream ostr;
2479
2480 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2481 ostr << "* violation: invalid height\n";
2482 ostr << "* line: '" << iline << "'\n";
2483 ostr << "* file position: " << pos;
2484
2485 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2486 }
2487
2488 if( thickness < 0.0 )
2489 {
2490 ostringstream ostr;
2491
2492 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2493 ostr << "* violation: thickness < 0\n";
2494 ostr << "* line: '" << iline << "'\n";
2495 ostr << "* file position: " << pos;
2496
2497 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2498 }
2499
2500 if( unit == IDF_UNIT::UNIT_THOU )
2501 {
2503 }
2504 else if( ( aIdfVersion == IDF_VERSION::IDF_V2 ) && ( unit == IDF_UNIT::UNIT_TNM ) )
2505 {
2507 }
2508 else if( unit != IDF_UNIT::UNIT_MM )
2509 {
2510 ostringstream ostr;
2511 ostr << "\n* BUG: invalid UNIT type: " << static_cast<int>( unit );
2512
2513 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2514 }
2515
2516 if( thickness < 0.0 )
2517 thickness = 0.0;
2518 }
2519 else
2520 {
2521 // for OUTLINE_TYPE::OTLN_PLACE, thickness may be omitted, but is required for OUTLINE_TYPE::OTLN_PLACE_KEEPOUT
2523 {
2524 ostringstream ostr;
2525
2526 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2527 ostr << "* violation: missing thickness\n";
2528 ostr << "* line: '" << iline << "'\n";
2529 ostr << "* file position: " << pos;
2530
2531 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2532 }
2533
2534 thickness = -1.0;
2535 }
2536 }
2537 else
2538 {
2540 thickness = 0.0;
2541 }
2542
2543 // read RECORD 3 values
2544 readOutlines( aBoardFile, aIdfVersion );
2545
2546 // check RECORD 4
2547 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
2548
2549 if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
2550 {
2551 ostringstream ostr;
2552
2553 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2554 ostr << "* violation: premature end\n";
2555 ostr << "* file position: " << pos;
2556
2557 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2558 }
2559
2560 idx = 0;
2561
2562 if( comment )
2563 {
2564 ostringstream ostr;
2565
2566 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2567 ostr << "* violation: comment within section\n";
2568 ostr << "* line: '" << iline << "'\n";
2569 ostr << "* file position: " << pos;
2570
2571 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2572 }
2573
2575 {
2576 if( !GetIDFString( iline, token, quoted, idx )
2577 || !CompareToken( ".END_PLACE_OUTLINE", token ) )
2578 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2579 "invalid .PLACE_OUTLINE section: no .END_PLACE_OUTLINE found" ) );
2580 }
2581 else
2582 {
2583 if( !GetIDFString( iline, token, quoted, idx )
2584 || !CompareToken( ".END_PLACE_KEEPOUT", token ) )
2585 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2586 "invalid .PLACE_KEEPOUT section: no .END_PLACE_KEEPOUT found" ) );
2587 }
2588}
2589
2590
2591void PLACE_OUTLINE::writeData( std::ostream& aBoardFile )
2592{
2593 // this section is optional; do not write if not required
2594 if( outlines.empty() )
2595 return;
2596
2597 writeComments( aBoardFile );
2598
2599 // write RECORD 1
2601 aBoardFile << ".PLACE_OUTLINE ";
2602 else
2603 aBoardFile << ".PLACE_KEEPOUT ";
2604
2605 writeOwner( aBoardFile );
2606
2607 // write RECORD 2
2608 switch( side )
2609 {
2610 case IDF_LAYER::LYR_TOP:
2613 WriteLayersText( aBoardFile, side );
2614 break;
2615
2616 default:
2617 do
2618 {
2619 ostringstream ostr;
2620 ostr << "\n* invalid PLACE_OUTLINE/KEEPOUT side (";
2621 ostr << static_cast<int>( side ) << "); must be one of TOP/BOTTOM/BOTH";
2622 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2623 } while( 0 );
2624
2625 break;
2626 }
2627
2628 // thickness is optional for OUTLINE_TYPE::OTLN_PLACE, but mandatory for OUTLINE_TYPE::OTLN_PLACE_KEEPOUT
2630 {
2631 aBoardFile << "\n";
2632 }
2633 else
2634 {
2635 aBoardFile << " ";
2636
2637 if( unit != IDF_UNIT::UNIT_THOU )
2638 aBoardFile << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << "\n";
2639 else
2640 aBoardFile << setiosflags( ios::fixed ) << setprecision( 1 )
2641 << ( thickness / IDF_THOU_TO_MM ) << "\n";
2642 }
2643
2644 // write RECORD 3
2645 writeOutlines( aBoardFile );
2646
2647 // write RECORD 4
2649 aBoardFile << ".END_PLACE_OUTLINE\n\n";
2650 else
2651 aBoardFile << ".END_PLACE_KEEPOUT\n\n";
2652
2653 return;
2654}
2655
2656
2658{
2659#ifndef DISABLE_IDF_OWNERSHIP
2660 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
2661 return false;
2662#endif
2663
2664 clear();
2665 thickness = 0.0;
2667
2668 return true;
2669}
2670
2671
2678
2679
2686
2687
2694
2695
2697{
2698 setParent( aParent );
2700 thickness = 0.0;
2702 single = true;
2703 return;
2704}
2705
2706
2708{
2709#ifndef DISABLE_IDF_OWNERSHIP
2710 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
2711 return false;
2712#endif
2713
2714 switch( aSide )
2715 {
2716 case IDF_LAYER::LYR_TOP:
2719 side = aSide;
2720 break;
2721
2722 default:
2723 do
2724 {
2725 ostringstream ostr;
2726 ostr << "invalid side (" << static_cast<int>( aSide ) << "); must be one of TOP/BOTTOM/BOTH\n";
2727 ostr << "* outline type: " << GetOutlineTypeString( outlineType );
2728 errormsg = ostr.str();
2729
2730 return false;
2731 } while( 0 );
2732
2733 break;
2734 }
2735
2736 return true;
2737}
2738
2739
2741{
2742 return side;
2743}
2744
2745
2746bool GROUP_OUTLINE::SetGroupName( std::string aGroupName )
2747{
2748#ifndef DISABLE_IDF_OWNERSHIP
2749 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
2750 return false;
2751#endif
2752
2753 groupName = std::move( aGroupName );
2754
2755 return true;
2756}
2757
2758
2759const std::string& GROUP_OUTLINE::GetGroupName( void )
2760{
2761 return groupName;
2762}
2763
2764
2765void GROUP_OUTLINE::readData( std::istream& aBoardFile, const std::string& aHeader,
2766 IDF3::IDF_VERSION aIdfVersion )
2767{
2768 // Placement Group
2769 // .PLACE_REGION [OWNER]
2770 // [side: Top/Bot/Both ] [component group name]
2771 // [outline]
2772
2773 // check RECORD 1
2774 std::string token;
2775 bool quoted = false;
2776 int idx = 0;
2777 std::streampos pos = aBoardFile.tellg();
2778
2779 if( !GetIDFString( aHeader, token, quoted, idx ) )
2780 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2781 "\n* BUG: invalid invocation: blank header line" ) );
2782
2783 if( quoted )
2784 {
2785 ostringstream ostr;
2786
2787 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2788 ostr << "* violation: section name must not be in quotes\n";
2789 ostr << "* line: '" << aHeader << "'\n";
2790 ostr << "* file position: " << pos;
2791
2792 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2793 }
2794
2795 if( !CompareToken( ".PLACE_REGION", token ) )
2796 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "\n* BUG: not a .PLACE_REGION" ) );
2797
2798 if( !GetIDFString( aHeader, token, quoted, idx ) )
2799 {
2800 if( aIdfVersion > IDF_VERSION::IDF_V2 )
2801 ERROR_IDF << "no OWNER; setting to UNOWNED\n";
2802
2804 }
2805 else
2806 {
2807 if( !ParseOwner( token, owner ) )
2808 {
2809 ERROR_IDF << "invalid OWNER (reverting to UNOWNED): " << token << "\n";
2811 }
2812 }
2813
2814 std::string iline;
2815 bool comment = false;
2816
2817 // check RECORD 2
2818 // [side: Top/Bot/Both ] [component group name]
2819 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
2820
2821 if( !aBoardFile.good() )
2822 {
2823 ostringstream ostr;
2824
2825 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2826 ostr << "* violation: premature end\n";
2827 ostr << "* file position: " << pos;
2828
2829 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2830 }
2831
2832 idx = 0;
2833
2834 if( comment )
2835 {
2836 ostringstream ostr;
2837
2838 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2839 ostr << "* violation: comment within section\n";
2840 ostr << "* line: '" << iline << "'\n";
2841 ostr << "* file position: " << pos;
2842
2843 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2844 }
2845
2846 if( !GetIDFString( iline, token, quoted, idx ) )
2847 {
2848 ostringstream ostr;
2849
2850 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2851 ostr << "* violation: no board side specified\n";
2852 ostr << "* line: '" << iline << "'\n";
2853 ostr << "* file position: " << pos;
2854
2855 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2856 }
2857
2858 if( !ParseIDFLayer( token, side ) ||
2860 {
2861 ostringstream ostr;
2862
2863 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2864 ostr << "* violation: invalid board side, must be one of TOP/BOTTOM/BOTH\n";
2865 ostr << "* line: '" << iline << "'\n";
2866 ostr << "* file position: " << pos;
2867
2868 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2869 }
2870
2871 if( !GetIDFString( iline, token, quoted, idx ) )
2872 {
2873 ostringstream ostr;
2874
2875 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2876 ostr << "* violation: no outline identifier\n";
2877 ostr << "* line: '" << iline << "'\n";
2878 ostr << "* file position: " << pos;
2879
2880 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2881 }
2882
2883 groupName = token;
2884
2885 // read RECORD 3 values
2886 readOutlines( aBoardFile, aIdfVersion );
2887
2888 // check RECORD 4
2889 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) );
2890
2891 if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() )
2892 {
2893 ostringstream ostr;
2894
2895 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2896 ostr << "* violation: premature end\n";
2897 ostr << "* file position: " << pos;
2898
2899 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2900 }
2901
2902 idx = 0;
2903
2904 if( comment )
2905 {
2906 ostringstream ostr;
2907
2908 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
2909 ostr << "* violation: comment within section\n";
2910 ostr << "* line: '" << iline << "'\n";
2911 ostr << "* file position: " << pos;
2912
2913 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2914 }
2915
2916 if( !GetIDFString( iline, token, quoted, idx ) || !CompareToken( ".END_PLACE_REGION", token ) )
2917 {
2918 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
2919 "\n* invalid .PLACE_REGION section: no .END_PLACE_REGION found" ) );
2920 }
2921}
2922
2923
2924void GROUP_OUTLINE::writeData( std::ostream& aBoardFile )
2925{
2926 // this section is optional; do not write if not required
2927 if( outlines.empty() )
2928 return;
2929
2930 writeComments( aBoardFile );
2931
2932 // write RECORD 1
2933 aBoardFile << ".PLACE_REGION ";
2934
2935 writeOwner( aBoardFile );
2936
2937 // write RECORD 2
2938 switch( side )
2939 {
2940 case IDF_LAYER::LYR_TOP:
2943 WriteLayersText( aBoardFile, side );
2944 break;
2945
2946 default:
2947 do
2948 {
2949 ostringstream ostr;
2950 ostr << "\n* invalid PLACE_REGION side (must be TOP/BOTTOM/BOTH): ";
2951 ostr << static_cast<int>( side );
2952
2953 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
2954 } while( 0 );
2955
2956 break;
2957 }
2958
2959 aBoardFile << " \"" << groupName << "\"\n";
2960
2961 // write RECORD 3
2962 writeOutlines( aBoardFile );
2963
2964 // write RECORD 4
2965 aBoardFile << ".END_PLACE_REGION\n\n";
2966}
2967
2968
2970{
2971#ifndef DISABLE_IDF_OWNERSHIP
2972 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
2973 return false;
2974#endif
2975
2976 clear();
2977 thickness = 0.0;
2979 groupName.clear();
2980
2981 return true;
2982}
2983
2984
2986{
2987 setParent( aParent );
2988 single = true;
2991 refNum = 0;
2992 return;
2993}
2994
2995
2996void IDF3_COMP_OUTLINE::readProperties( std::istream& aLibFile )
2997{
2998 bool quoted = false;
2999 bool comment = false;
3000 std::string iline;
3001 std::string token;
3002 std::streampos pos;
3003 std::string pname; // property name
3004 std::string pval; // property value
3005 int idx = 0;
3006
3007 while( aLibFile.good() )
3008 {
3009 if( !FetchIDFLine( aLibFile, iline, comment, pos ) )
3010 continue;
3011
3012 idx = 0;
3013
3014 if( comment )
3015 {
3016 ostringstream ostr;
3017
3018 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3019 ostr << "* violation: comment within section\n";
3020 ostr << "* line: '" << iline << "'\n";
3021 ostr << "* file position: " << pos;
3022
3023 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3024 }
3025
3026 if( !GetIDFString( iline, token, quoted, idx ) )
3027 {
3028 ostringstream ostr;
3029
3030 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3031 ostr << "* violation: bad property section (no PROP)\n";
3032 ostr << "* line: '" << iline << "'\n";
3033 ostr << "* file position: " << pos;
3034
3035 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3036 }
3037
3038 if( quoted )
3039 {
3040 ostringstream ostr;
3041
3042 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3043 ostr << "* violation: PROP or .END must not be quoted\n";
3044 ostr << "* line: '" << iline << "'\n";
3045 ostr << "* file position: " << pos;
3046
3047 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3048 }
3049
3050 if( token.size() >= 5 && CompareToken( ".END_", token.substr( 0, 5 ) ) )
3051 {
3052 if(aLibFile.eof())
3053 aLibFile.clear();
3054
3055 aLibFile.seekg( pos );
3056 return;
3057 }
3058
3059 if( !CompareToken( "PROP", token ) )
3060 {
3061 ostringstream ostr;
3062
3063 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3064 ostr << "* violation: expecting PROP or .END_ELECTRICAL\n";
3065 ostr << "* line: '" << iline << "'\n";
3066 ostr << "* file position: " << pos;
3067
3068 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3069 }
3070
3071 if( !GetIDFString( iline, token, quoted, idx ) )
3072 {
3073 ostringstream ostr;
3074
3075 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3076 ostr << "* violation: no PROP name\n";
3077 ostr << "* line: '" << iline << "'\n";
3078 ostr << "* file position: " << pos;
3079
3080 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3081 }
3082
3083 pname = token;
3084
3085 if( !GetIDFString( iline, token, quoted, idx ) )
3086 {
3087 ostringstream ostr;
3088
3089 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3090 ostr << "* violation: no PROP value\n";
3091 ostr << "* line: '" << iline << "'\n";
3092 ostr << "* file position: " << pos;
3093
3094 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3095 }
3096
3097 pval = token;
3098
3099 if( props.insert( pair< string, string >(pname, pval) ).second == false )
3100 {
3101 ostringstream ostr;
3102
3103 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3104 ostr << "* violation: duplicate property name \"" << pname << "\"\n";
3105 ostr << "* line: '" << iline << "'\n";
3106 ostr << "* file position: " << pos;
3107
3108 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3109 }
3110 }
3111}
3112
3113
3114bool IDF3_COMP_OUTLINE::writeProperties( std::ostream& aLibFile )
3115{
3116 if( props.empty() )
3117 return true;
3118
3119 std::map< std::string, std::string >::const_iterator itS = props.begin();
3120 std::map< std::string, std::string >::const_iterator itE = props.end();
3121
3122 while( itS != itE )
3123 {
3124 aLibFile << "PROP " << "\"" << itS->first << "\" \""
3125 << itS->second << "\"\n";
3126 ++itS;
3127 }
3128
3129 return !aLibFile.fail();
3130}
3131
3132
3133void IDF3_COMP_OUTLINE::readData( std::istream& aLibFile, const std::string& aHeader,
3134 IDF3::IDF_VERSION aIdfVersion )
3135{
3136 // .ELECTRICAL/.MECHANICAL
3137 // [GEOM] [PART] [UNIT] [HEIGHT]
3138 // [outline]
3139 // [PROP] [prop name] [prop value]
3140 // check RECORD 1
3141 std::string token;
3142 bool quoted = false;
3143 int idx = 0;
3144 std::streampos pos = aLibFile.tellg();
3145
3146 if( !GetIDFString( aHeader, token, quoted, idx ) )
3147 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__,
3148 "\n* BUG: invalid invocation: blank header line" ) );
3149
3150 if( quoted )
3151 {
3152 ostringstream ostr;
3153
3154 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3155 ostr << "* violation: section name must not be in quotes\n";
3156 ostr << "* line: '" << aHeader << "'\n";
3157 ostr << "* file position: " << pos;
3158
3159 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3160 }
3161
3162 if( CompareToken( ".ELECTRICAL", token ) )
3163 {
3165 }
3166 else if( CompareToken( ".MECHANICAL", token ) )
3167 {
3169 }
3170 else
3171 {
3172 ostringstream ostr;
3173
3174 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3175 ostr << "* violation: expecting .ELECTRICAL or .MECHANICAL header\n";
3176 ostr << "* line: '" << aHeader << "'\n";
3177 ostr << "* file position: " << pos;
3178
3179 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3180 }
3181
3182 // check RECORD 2
3183 // [GEOM] [PART] [UNIT] [HEIGHT]
3184 std::string iline;
3185 bool comment = false;
3186
3187 while( aLibFile.good() && !FetchIDFLine( aLibFile, iline, comment, pos ) );
3188
3189 if( !aLibFile.good() )
3190 {
3191 ostringstream ostr;
3192
3193 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3194 ostr << "* violation: premature end\n";
3195 ostr << "* file position: " << pos;
3196
3197 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3198 }
3199
3200 idx = 0;
3201
3202 if( comment )
3203 {
3204 ostringstream ostr;
3205
3206 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3207 ostr << "* violation: comment within section\n";
3208 ostr << "* line: '" << iline << "'\n";
3209 ostr << "* file position: " << pos;
3210
3211 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3212 }
3213
3214 if( !GetIDFString( iline, token, quoted, idx ) )
3215 {
3216 ostringstream ostr;
3217
3218 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3219 ostr << "* violation: no GEOMETRY NAME\n";
3220 ostr << "* line: '" << iline << "'\n";
3221 ostr << "* file position: " << pos;
3222
3223 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3224 }
3225
3226 geometry = token;
3227
3228 if( !GetIDFString( iline, token, quoted, idx ) )
3229 {
3230 ostringstream ostr;
3231
3232 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3233 ostr << "* violation: no PART NAME\n";
3234 ostr << "* line: '" << iline << "'\n";
3235 ostr << "* file position: " << pos;
3236
3237 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3238 }
3239
3240 part = token;
3241
3242 if( part.empty() && geometry.empty() )
3243 {
3244 ostringstream ostr;
3245
3246 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3247 ostr << "* violation: both GEOMETRY and PART names are empty\n";
3248 ostr << "* line: '" << iline << "'\n";
3249 ostr << "* file position: " << pos;
3250
3251 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3252 }
3253
3254 if( !GetIDFString( iline, token, quoted, idx ) )
3255 {
3256 ostringstream ostr;
3257
3258 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3259 ostr << "* violation: no UNIT type\n";
3260 ostr << "* line: '" << iline << "'\n";
3261 ostr << "* file position: " << pos;
3262
3263 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3264 }
3265
3266 if( CompareToken( "MM", token ) )
3267 {
3269 }
3270 else if( CompareToken( "THOU", token ) )
3271 {
3273 }
3274 else if( aIdfVersion == IDF_VERSION::IDF_V2 && !CompareToken( "TNM", token ) )
3275 {
3277 }
3278 else
3279 {
3280 ostringstream ostr;
3281
3282 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3283 ostr << "* violation: invalid UNIT '" << token << "': must be one of MM or THOU\n";
3284 ostr << "* line: '" << iline << "'\n";
3285 ostr << "* file position: " << pos;
3286
3287 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3288 }
3289
3290 if( !GetIDFString( iline, token, quoted, idx ) )
3291 {
3292 ostringstream ostr;
3293
3294 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3295 ostr << "* violation: no height specified\n";
3296 ostr << "* line: '" << iline << "'\n";
3297 ostr << "* file position: " << pos;
3298
3299 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3300 }
3301
3302 std::istringstream teststr;
3303 teststr.str( token );
3304
3305 teststr >> thickness;
3306 if( teststr.fail() )
3307 {
3308 ostringstream ostr;
3309
3310 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3311 ostr << "* violation: invalid height '" << token << "'\n";
3312 ostr << "* line: '" << iline << "'\n";
3313 ostr << "* file position: " << pos;
3314
3315 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3316 }
3317
3318 if( unit == IDF_UNIT::UNIT_THOU )
3319 {
3321 }
3322 else if( ( aIdfVersion == IDF_VERSION::IDF_V2 ) && ( unit == IDF_UNIT::UNIT_TNM ) )
3323 {
3325 }
3326 else if( unit != IDF_UNIT::UNIT_MM )
3327 {
3328 ostringstream ostr;
3329 ostr << "\n* BUG: invalid UNIT type: " << static_cast<int>( unit );
3330
3331 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3332 }
3333
3334 // read RECORD 3 values
3335 readOutlines( aLibFile, aIdfVersion );
3336
3337 if( compType == COMP_TYPE::COMP_ELEC && aIdfVersion > IDF_VERSION::IDF_V2 )
3338 readProperties( aLibFile );
3339
3340 // check RECORD 4
3341 while( aLibFile.good() && !FetchIDFLine( aLibFile, iline, comment, pos ) );
3342
3343 if( ( !aLibFile.good() && aLibFile.eof() ) && iline.empty() )
3344 {
3345 ostringstream ostr;
3346
3347 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3348 ostr << "* violation: premature end\n";
3349 ostr << "* file position: " << pos;
3350
3351 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3352 }
3353
3354 idx = 0;
3355
3356 if( comment )
3357 {
3358 ostringstream ostr;
3359
3360 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3361 ostr << "* violation: comment within section\n";
3362 ostr << "* line: '" << iline << "'\n";
3363 ostr << "* file position: " << pos;
3364
3365 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3366 }
3367
3369 {
3370 if( !CompareToken( ".END_ELECTRICAL", iline ) )
3371 {
3372 ostringstream ostr;
3373
3374 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3375 ostr << "* violation: no .END_ELECTRICAL found\n";
3376 ostr << "* line: '" << iline << "'\n";
3377 ostr << "* file position: " << pos;
3378
3379 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3380 }
3381 }
3382 else
3383 {
3384 if( !CompareToken( ".END_MECHANICAL", iline ) )
3385 {
3386 ostringstream ostr;
3387
3388 ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n";
3389 ostr << "* violation: no .END_MECHANICAL found\n";
3390 ostr << "* line: '" << iline << "'\n";
3391 ostr << "* file position: " << pos;
3392
3393 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3394 }
3395 }
3396}
3397
3398
3399void IDF3_COMP_OUTLINE::writeData( std::ostream& aLibFile )
3400{
3401 if( refNum == 0 )
3402 return; // nothing to do
3403
3405 {
3406 ostringstream ostr;
3407 ostr << "\n* component type not set or invalid: " << static_cast<int>( compType );
3408
3409 throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) );
3410 }
3411
3412 writeComments( aLibFile );
3413
3414 // note: the outline section is required, even if it is empty
3416 aLibFile << ".ELECTRICAL\n";
3417 else
3418 aLibFile << ".MECHANICAL\n";
3419
3420 // RECORD 2
3421 // [GEOM] [PART] [UNIT] [HEIGHT]
3422 aLibFile << "\"" << geometry << "\" \"" << part << "\" ";
3423
3424 if( unit != IDF_UNIT::UNIT_THOU )
3425 aLibFile << "MM " << setiosflags( ios::fixed ) << setprecision( 5 ) << thickness << "\n";
3426 else
3427 aLibFile << "THOU " << setiosflags( ios::fixed ) << setprecision( 1 )
3428 << ( thickness / IDF_THOU_TO_MM ) << "\n";
3429
3430 writeOutlines( aLibFile );
3431
3433 {
3434 writeProperties( aLibFile );
3435 aLibFile << ".END_ELECTRICAL\n\n";
3436 }
3437 else
3438 {
3439 aLibFile << ".END_MECHANICAL\n\n";
3440 }
3441}
3442
3443
3445{
3446#ifndef DISABLE_IDF_OWNERSHIP
3447 if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) )
3448 return false;
3449#endif
3450
3451 clear();
3452 uid.clear();
3453 geometry.clear();
3454 part.clear();
3456 refNum = 0;
3457 props.clear();
3458
3459 return true;
3460}
3461
3462
3464{
3465 switch( aCompClass )
3466 {
3469 compType = aCompClass;
3470 break;
3471
3472 default:
3473 do
3474 {
3475 ostringstream ostr;
3476 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3477 ostr << "* BUG: invalid component class (must be ELECTRICAL or MECHANICAL): ";
3478 ostr << static_cast<int>( aCompClass ) << "\n";
3479 errormsg = ostr.str();
3480
3481 return false;
3482 } while( 0 );
3483
3484 break;
3485 }
3486
3487 return true;
3488}
3489
3490
3495
3496
3497void IDF3_COMP_OUTLINE::SetGeomName( const std::string& aGeomName )
3498{
3499 geometry = aGeomName;
3500 uid.clear();
3501}
3502
3503
3504const std::string& IDF3_COMP_OUTLINE::GetGeomName( void )
3505{
3506 return geometry;
3507}
3508
3509
3510void IDF3_COMP_OUTLINE::SetPartName( const std::string& aPartName )
3511{
3512 part = aPartName;
3513 uid.clear();
3514}
3515
3516
3517const std::string& IDF3_COMP_OUTLINE::GetPartName( void )
3518{
3519 return part;
3520}
3521
3522
3523const std::string& IDF3_COMP_OUTLINE::GetUID( void )
3524{
3525 if( !uid.empty() )
3526 return uid;
3527
3528 if( geometry.empty() && part.empty() )
3529 return uid;
3530
3531 uid = geometry + "_" + part;
3532
3533 return uid;
3534}
3535
3536
3538{
3539 return ++refNum;
3540}
3541
3542
3544{
3545 if( refNum == 0 )
3546 {
3547 ostringstream ostr;
3548 ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n";
3549 ostr << "* BUG: decrementing refNum beyond 0";
3550 errormsg = ostr.str();
3551
3552 return -1;
3553 }
3554
3555 --refNum;
3556 return refNum;
3557}
3558
3559
3560bool IDF3_COMP_OUTLINE::CreateDefaultOutline( const std::string& aGeom, const std::string& aPart )
3561{
3562 Clear();
3563
3564 if( aGeom.empty() && aPart.empty() )
3565 {
3566 geometry = "NOGEOM";
3567 part = "NOPART";
3568 uid = "NOGEOM_NOPART";
3569 }
3570 else
3571 {
3572 geometry = aGeom;
3573 part = aPart;
3574 uid = aGeom + "_" + aPart;
3575 }
3576
3578 thickness = 5.0;
3580
3581 // Create a star shape 5mm high with points on 5 and 3 mm circles
3582 double a, da;
3583 da = M_PI / 5.0;
3584 a = da / 2.0;
3585
3586 IDF_POINT p1, p2;
3587 IDF_SEGMENT* sp;
3588 IDF_OUTLINE* ol;
3589
3590 p1.x = 1.5 * cos( a );
3591 p1.y = 1.5 * sin( a );
3592
3593 try
3594 {
3595 ol = new IDF_OUTLINE;
3596 }
3597 catch( std::bad_alloc& )
3598 {
3599 return false;
3600 }
3601
3602 for( int i = 0; i < 10; ++i )
3603 {
3604 if( i & 1 )
3605 {
3606 p2.x = 2.5 * cos( a );
3607 p2.y = 2.5 * sin( a );
3608 }
3609 else
3610 {
3611 p2.x = 1.5 * cos( a );
3612 p2.y = 1.5 * sin( a );
3613 }
3614
3615 try
3616 {
3617 sp = new IDF_SEGMENT( p1, p2 );
3618 }
3619 catch( std::bad_alloc& )
3620 {
3621 Clear();
3622 return false;
3623 }
3624
3625 ol->push( sp );
3626 a += da;
3627 p1 = p2;
3628 }
3629
3630 a = da / 2.0;
3631 p2.x = 1.5 * cos( a );
3632 p2.y = 1.5 * sin( a );
3633
3634 try
3635 {
3636 sp = new IDF_SEGMENT( p1, p2 );
3637 }
3638 catch( std::bad_alloc& )
3639 {
3640 Clear();
3641 return false;
3642 }
3643
3644 ol->push( sp );
3645 outlines.push_back( ol );
3646
3647 return true;
3648}
void ClearComments(void)
Deletes all comments.
virtual bool Clear(void)
Free memory and reinitializes all internal data except for the parent pointer.
bool addOutline(IDF_OUTLINE *aOutline)
std::string errormsg
bool AddOutline(IDF_OUTLINE *aOutline)
Add the specified outline to this object.
virtual bool setThickness(double aThickness)
virtual void clear(void)
friend class IDF3_BOARD
virtual ~BOARD_OUTLINE()
IDF3::KEY_OWNER GetOwner(void)
IDF_OUTLINE * GetOutline(size_t aIndex)
Return a pointer to the outline as specified by aIndex.
IDF3::IDF_UNIT unit
bool DeleteComment(size_t aIndex)
Deletes a comment based on the given index.
bool writeComments(std::ostream &aBoardFile)
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion)
Read data from a .BOARD_OUTLINE section.
const std::string * GetComment(size_t aIndex)
void writeOutlines(std::ostream &aBoardFile)
IDF3::OUTLINE_TYPE outlineType
bool IsSingle(void)
std::list< std::string > * GetComments(void)
bool writeOwner(std::ostream &aBoardFile)
void clearOutlines(void)
IDF3::KEY_OWNER owner
virtual bool SetThickness(double aThickness)
Set the thickness or height of the outline (mm).
virtual double GetThickness(void)
bool DelOutline(IDF_OUTLINE *aOutline)
Remove the given outline, subject to IDF ownership rules, if it is owned by this object.
const std::list< IDF_OUTLINE * > * GetOutlines(void)
Return outlines list.
IDF3_BOARD * parent
virtual void writeData(std::ostream &aBoardFile)
Write the comments and .BOARD_OUTLINE section to an IDFv3 file.
void readOutlines(std::istream &aBoardFile, IDF3::IDF_VERSION aIdfVersion)
bool SetOwner(IDF3::KEY_OWNER aOwner)
Set the ownership status of the outline subject to IDF ownership rules.
std::list< std::string > comments
IDF3_BOARD * GetParent(void)
size_t OutlinesSize(void)
void writeOutline(std::ostream &aBoardFile, IDF_OUTLINE *aOutline, size_t aIndex)
size_t CommentsSize(void)
IDF3::OUTLINE_TYPE GetOutlineType(void)
void setParent(IDF3_BOARD *aParent)
Set the parent IDF_BOARD object.
virtual bool SetUnit(IDF3::IDF_UNIT aUnit)
Function SetUnit sets the native unit of the outline; except for component outlines this must be the ...
std::list< IDF_OUTLINE * > outlines
void AddComment(const std::string &aComment)
Add a comment to the outline data.
virtual IDF3::IDF_UNIT GetUnit(void)
Return the native unit type of the outline.
virtual bool SetGroupName(std::string aGroupName)
Set the name of the group, subject to IDF ownership rules.
friend class IDF3_BOARD
IDF3::IDF_LAYER side
virtual bool Clear(void) override
Delete internal data, subject to IDF ownership rules.
virtual void writeData(std::ostream &aBoardFile) override
Write the data to a .PLACE_REGION section of an IDFv3 file.
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read GROUP_OUTLINE data from an open IDFv3 file.
virtual IDF3::IDF_LAYER GetSide(void)
std::string groupName
virtual const std::string & GetGroupName(void)
Return a reference to the (non-unique) group name.
GROUP_OUTLINE(IDF3_BOARD *aParent)
virtual bool SetSide(IDF3::IDF_LAYER aSide)
Set the side which this outline applies to (TOP, BOTTOM, BOTH).
IDF3::CAD_TYPE GetCadType(void)
Definition idf_parser.h:425
void SetPartName(const std::string &aPartName)
Set the Part Name (Part Number, IDFv3 spec) of the component outline.
void readProperties(std::istream &aLibFile)
const std::string & GetUID(void)
friend class IDF3_BOARD
virtual void writeData(std::ostream &aLibFile) override
Write comments and component outline data to an IDFv3 Library file.
virtual void readData(std::istream &aLibFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read a component outline from an open IDFv3 file.
IDF3::COMP_TYPE GetComponentClass(void)
std::map< std::string, std::string > props
IDF3_COMP_OUTLINE(IDF3_BOARD *aParent)
virtual bool Clear(void) override
Delete internal outline data.
IDF3::COMP_TYPE compType
bool CreateDefaultOutline(const std::string &aGeom, const std::string &aPart)
Create a default outline with the given Geometry and Part names.
int decrementRef(void)
Decrement the internal reference counter to keep track of the number of components referring to this ...
void SetGeomName(const std::string &aGeomName)
Set the Geometry Name (Package Name, IDFv3 spec) of the component outline.
std::string geometry
bool SetComponentClass(IDF3::COMP_TYPE aCompClass)
Set the type of component outline (.ELECTRICAL or .MECHANICAL).
bool writeProperties(std::ostream &aLibFile)
const std::string & GetGeomName(void)
int incrementRef(void)
Increment the internal reference counter to keep track of the number of components referring to this ...
const std::string & GetPartName(void)
Return the Part Name (Part Number) of the component outline.
A segment and winding information for an IDF outline.
Definition idf_common.h:551
std::list< IDF_SEGMENT * >::iterator end()
Definition idf_common.h:623
std::list< IDF_SEGMENT * >::iterator begin()
Definition idf_common.h:615
size_t size()
Definition idf_common.h:583
IDF_SEGMENT *& back()
Definition idf_common.h:607
IDF_SEGMENT *& front()
Definition idf_common.h:599
bool push(IDF_SEGMENT *item)
Add a segment to the internal segment list.
A point as used by the various IDF related classes.
Definition idf_common.h:426
bool Matches(const IDF_POINT &aPoint, double aRadius=1e-5) const
Return true if the given coordinate point is within the given radius of the point.
double x
Definition idf_common.h:457
double y
Definition idf_common.h:458
A segment as used in IDFv3 outlines.
Definition idf_common.h:468
IDF_POINT endPoint
end point coordinates in mm
Definition idf_common.h:537
IDF_POINT startPoint
starting point coordinates in mm
Definition idf_common.h:536
double angle
included angle (degrees) according to IDFv3 specification
Definition idf_common.h:541
friend class IDF3_BOARD
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read an OTHER_OUTLINE data from an IDFv3 file.
IDF3::IDF_LAYER side
std::string uniqueID
virtual bool Clear(void) override
Function Clear deletes internal data except for the parent object.
virtual bool SetOutlineIdentifier(const std::string &aUniqueID)
Function SetOutlineIdentifier sets the Outline Identifier string of this OTHER_OUTLINE object as per ...
virtual const std::string & GetOutlineIdentifier(void)
Function GetOutlineIdentifier returns the object's Outline Identifier.
virtual void writeData(std::ostream &aBoardFile) override
Write the OTHER_OUTLINE data to an open IDFv3 file.
virtual bool SetSide(IDF3::IDF_LAYER aSide)
Function SetSide sets the side which this outline is applicable to (TOP, BOTTOM).
OTHER_OUTLINE(IDF3_BOARD *aParent)
virtual IDF3::IDF_LAYER GetSide(void)
Function GetSide returns the side which this outline is applicable to.
PLACE_KO_OUTLINE(IDF3_BOARD *aParent)
friend class IDF3_BOARD
virtual double GetMaxHeight(void)
Function GetMaxHeight returns the maximum allowable height for a component in this region.
IDF3::IDF_LAYER side
virtual bool SetMaxHeight(double aHeight)
Function SetMaxHeight sets the maximum height of a component within this outline.
virtual bool SetSide(IDF3::IDF_LAYER aSide)
Function SetSide sets the side (TOP, BOTTOM, BOTH) which this outline applies to.
virtual IDF3::IDF_LAYER GetSide(void)
Function GetSide returns the side which this outline is applicable to.
virtual void writeData(std::ostream &aBoardFile) override
Write the PLACE_OUTLINE data to an open IDFv3 file.
virtual bool Clear(void) override
Function Clear deletes all internal data.
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read PLACE_OUTLINE data from an open IDFv3 file.
PLACE_OUTLINE(IDF3_BOARD *aParent)
ROUTE_KO_OUTLINE(IDF3_BOARD *aParent)
friend class IDF3_BOARD
virtual void writeData(std::ostream &aBoardFile) override
Write the ROUTE_OUTLINE data to an open IDFv3 file.
virtual bool Clear(void) override
Function Clear deletes internal data except for the parent object.
virtual bool SetLayers(IDF3::IDF_LAYER aLayer)
Function SetLayers sets the layer or group of layers this outline is applicable to.
ROUTE_OUTLINE(IDF3_BOARD *aParent)
IDF3::IDF_LAYER layers
virtual void readData(std::istream &aBoardFile, const std::string &aHeader, IDF3::IDF_VERSION aIdfVersion) override
Read ROUTE_OUTLINE data from an IDFv3 file.
virtual IDF3::IDF_LAYER GetLayers(void)
Function GetLayers returns the layer or group of layers which this outline is applicable to.
VIA_KO_OUTLINE(IDF3_BOARD *aParent)
#define MIN_ANG
Definition idf_common.h:35
#define IDF_THOU_TO_MM
Definition idf_helpers.h:63
#define IDF_TNM_TO_MM
Definition idf_helpers.h:65
#define ERROR_IDF
Definition idf_helpers.h:55
static bool CheckOwnership(int aSourceLine, const char *aSourceFunc, IDF3_BOARD *aParent, IDF3::KEY_OWNER aOwnerCAD, IDF3::OUTLINE_TYPE aOutlineType, std::string &aErrorString)
static std::string GetOutlineTypeString(IDF3::OUTLINE_TYPE aOutlineType)
bool ParseIDFLayer(const std::string &aToken, IDF3::IDF_LAYER &aLayer)
Parse an input string for a valid IDF layer specification.
bool GetIDFString(const std::string &aLine, std::string &aIDFString, bool &hasQuotes, int &aIndex)
Parse a line retrieved via FetchIDFLine() and returns the first IDF string found from the starting po...
CAD_TYPE
The class of CAD program which is opening or modifying a file.
Definition idf_common.h:127
std::string GetOwnerString(IDF3::KEY_OWNER aOwner)
bool FetchIDFLine(std::istream &aModel, std::string &aLine, bool &isComment, std::streampos &aFilePos)
Retrieve a single line from an IDF file and performs minimal processing.
OUTLINE_TYPE
The class of outline.
Definition idf_common.h:150
IDF_VERSION
The supported IDF versions (3.0 and 2.0 ONLY).
Definition idf_common.h:76
IDF_UNIT
The native unit of the board and of component outlines.
Definition idf_common.h:177
bool CompareToken(const char *aTokenString, const std::string &aInputString)
Perform a case-insensitive comparison of a token string and an input string.
IDF_LAYER
The various IDF layer classes and groupings.
Definition idf_common.h:137
KEY_OWNER
The type of CAD which has ownership an object.
Definition idf_common.h:85
bool WriteLayersText(std::ostream &aBoardFile, IDF3::IDF_LAYER aLayer)
Write out text corresponding to the given IDF Layer type.
COMP_TYPE
Whether a component is a mechanical or electrical part.
Definition idf_common.h:167
bool ParseOwner(const std::string &aToken, IDF3::KEY_OWNER &aOwner)
Parse the input string for a valid IDF Owner type.
STL namespace.
#define M_PI