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