KiCad PCB EDA Suite
Loading...
Searching...
No Matches
odb_feature.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 * Author: SYSUEric <[email protected]>.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include "odb_feature.h"
22
23#include <sstream>
24#include <map>
25
26#include <wx/log.h>
27
28#include "footprint.h"
29#include "pad.h"
30#include "pcb_shape.h"
31#include "odb_defines.h"
32#include "pcb_track.h"
33#include "pcb_textbox.h"
34#include "pcb_table.h"
35#include "pcb_barcode.h"
36#include "pcb_dimension.h"
37#include "zone.h"
38#include "board.h"
42#include "geometry/eda_angle.h"
48#include "odb_eda_data.h"
53#include "pcb_io_odbpp.h"
54#include <callback_gal.h>
55#include <string_utils.h>
56#include <trace_helpers.h>
57
58
59void FEATURES_MANAGER::AddFeatureLine( const VECTOR2I& aStart, const VECTOR2I& aEnd,
60 uint64_t aWidth )
61{
62 AddFeature<ODB_LINE>( ODB::AddXY( m_plugin->GetFormat(), aStart ), ODB::AddXY( m_plugin->GetFormat(), aEnd ),
63 AddCircleSymbol( ODB::SymDouble2String( m_plugin->GetFormat(), aWidth ) ) );
64}
65
66
67void FEATURES_MANAGER::AddFeatureArc( const VECTOR2I& aStart, const VECTOR2I& aEnd,
68 const VECTOR2I& aCenter, uint64_t aWidth,
69 ODB_DIRECTION aDirection )
70{
71 const ODB_FORMAT& fmt = m_plugin->GetFormat();
72
73 AddFeature<ODB_ARC>( ODB::AddXY( fmt, aStart ),
74 ODB::AddXY( fmt, aEnd ),
75 ODB::AddXY( fmt, aCenter ),
76 AddCircleSymbol( ODB::SymDouble2String( fmt, aWidth ) ),
77 aDirection );
78}
79
80
81void FEATURES_MANAGER::AddRoutContour( const SHAPE_LINE_CHAIN& aContour, int aChain, bool aPlated )
82{
83 size_t first = FeatureCount();
84 int at = 0;
85
86 if( aContour.PointCount() < 2 )
87 return;
88
89 do
90 {
91 int next = aContour.NextShape( at );
92
93 if( next < 0 )
94 next = 0;
95
96 if( aContour.IsArcStart( at ) )
97 {
98 const SHAPE_ARC& arc = aContour.Arc( aContour.ArcIndex( at ) );
99 AddFeatureArc( arc.GetP0(), arc.GetP1(), arc.GetCenter(), 0,
101 }
102 else if( aContour.CPoint( at ) != aContour.CPoint( next ) )
103 {
104 AddFeatureLine( aContour.CPoint( at ), aContour.CPoint( next ), 0 );
105 }
106
107 at = next;
108 } while( at != 0 );
109
110 tagRoutFeatures( first, aChain, aPlated );
111}
112
113
114void FEATURES_MANAGER::AddRoutSlot( const PAD& aPad, int aChain )
115{
116 std::shared_ptr<SHAPE_SEGMENT> hole = aPad.GetEffectiveHoleShape();
117
118 if( !hole || hole->GetSeg().A == hole->GetSeg().B )
119 return;
120
121 size_t first = FeatureCount();
122 AddFeatureLine( hole->GetSeg().A, hole->GetSeg().B, hole->GetWidth() );
123
124 tagRoutFeatures( first, aChain, aPad.GetAttribute() == PAD_ATTRIB::PTH );
125}
126
127
128void FEATURES_MANAGER::tagRoutFeatures( size_t aFirst, int aChain, bool aPlated )
129{
130 forEachNewFeature( aFirst,
131 [&]( ODB_FEATURE& aFeature, size_t )
132 {
133 AddSystemAttribute( aFeature, ODB_ATTR::ROUT_CHAIN{ aChain } );
134
135 if( aPlated )
136 AddSystemAttribute( aFeature, ODB_ATTR::ROUT_PLATED{ true } );
137 } );
138}
139
140
141void FEATURES_MANAGER::AddPadCircle( const VECTOR2I& aCenter, uint64_t aDiameter )
142{
143 AddFeature<ODB_PAD>( ODB::AddXY( m_plugin->GetFormat(), aCenter ),
144 AddCircleSymbol( ODB::SymDouble2String( m_plugin->GetFormat(), aDiameter ) ) );
145}
146
147
148bool FEATURES_MANAGER::AddContour( const SHAPE_POLY_SET& aPolySet, int aOutline /*= 0*/,
149 FILL_T aFillType /*= FILL_T::FILLED_SHAPE*/ )
150{
151 // todo: args modify aPolySet.Polygon( aOutline ) instead of aPolySet
152
153 if( aPolySet.OutlineCount() < ( aOutline + 1 ) )
154 return false;
155
156 return AddFeatureSurface( aPolySet.Polygon( aOutline ), aFillType );
157}
158
159
161{
162 const ODB_FORMAT& fmt = m_plugin->GetFormat();
163
164 int stroke_width = aShape.GetWidth();
165
166 switch( aShape.GetShape() )
167 {
168 case SHAPE_T::CIRCLE:
169 {
170 // GetRadius() can reach INT_MAX / 2 rounded up, which overflows a signed int when doubled
171 int64_t diameter = static_cast<int64_t>( aShape.GetRadius() ) * 2;
173
174 // The stroke straddles the radius, so in diameter terms the whole width comes off the
175 // inner edge and goes onto the outer
176 int64_t innerDiameter = diameter - stroke_width;
177 wxString outerDim = ODB::SymDouble2String( fmt, diameter + stroke_width );
178
179 // donut_r has no spelling for a hole closed by its own stroke
180 if( aShape.IsSolidFill() || innerDiameter <= 0 )
181 {
183 }
184 else
185 {
187 AddRoundDonutSymbol( outerDim,
188 ODB::SymDouble2String( fmt, innerDiameter ) ) );
189 }
190
191 break;
192 }
193
195 {
196 // ODB++ donut_rc symbols degenerate when the corner radius is smaller than half the
197 // line width, and some viewers drop the feature entirely. Emit the rectangle as a
198 // filled pad for the fill (if any) plus four line segments for the stroke, matching
199 // how a rectangle drawn with the line tool is exported.
200 if( aShape.IsSolidFill() )
201 {
202 int width = std::abs( aShape.GetRectangleWidth() );
203 int height = std::abs( aShape.GetRectangleHeight() );
205
208 ODB::SymDouble2String( fmt, height ) ) );
209 }
210
211 if( stroke_width > 0 )
212 {
213 std::vector<VECTOR2I> corners = aShape.GetRectCorners();
214
215 for( size_t ii = 0; ii < corners.size(); ++ii )
216 AddFeatureLine( corners[ii], corners[( ii + 1 ) % corners.size()], stroke_width );
217 }
218
219 break;
220 }
221
222 case SHAPE_T::POLY:
223 {
224 int soldermask_min_thickness = 0;
225
226 // TODO: check if soldermask_min_thickness should be Stroke width
227
228 if( aLayer != UNDEFINED_LAYER && LSET( { F_Mask, B_Mask } ).Contains( aLayer ) )
229 soldermask_min_thickness = stroke_width;
230
231 int maxError = m_board->GetDesignSettings().m_MaxError;
232 SHAPE_POLY_SET poly_set;
233
234 if( soldermask_min_thickness == 0 )
235 {
236 poly_set = aShape.GetPolyShape().CloneDropTriangulation();
237 poly_set.Fracture();
238 }
239 else
240 {
241 SHAPE_POLY_SET initialPolys;
242
243 // add shapes inflated by aMinThickness/2 in areas
244 aShape.TransformShapeToPolygon( initialPolys, aLayer, 0, maxError, ERROR_OUTSIDE );
245 aShape.TransformShapeToPolygon( poly_set, aLayer, soldermask_min_thickness / 2 - 1,
246 maxError, ERROR_OUTSIDE );
247
248 poly_set.Simplify();
249 poly_set.Deflate( soldermask_min_thickness / 2 - 1,
251 poly_set.BooleanAdd( initialPolys );
252 poly_set.Fracture();
253 }
254
255 // ODB++ surface features can only represent closed polygons. We add a surface for
256 // the fill of the shape, if present, and add line segments for the outline, if present.
257 if( aShape.IsSolidFill() )
258 {
259 for( int ii = 0; ii < poly_set.OutlineCount(); ++ii )
260 {
261 AddContour( poly_set, ii, FILL_T::FILLED_SHAPE );
262
263 if( stroke_width != 0 )
264 {
265 for( int jj = 0; jj < poly_set.COutline( ii ).SegmentCount(); ++jj )
266 {
267 const SEG& seg = poly_set.COutline( ii ).CSegment( jj );
268 AddFeatureLine( seg.A, seg.B, stroke_width );
269 }
270 }
271 }
272 }
273 else
274 {
275 for( int ii = 0; ii < poly_set.OutlineCount(); ++ii )
276 {
277 for( int jj = 0; jj < poly_set.COutline( ii ).SegmentCount(); ++jj )
278 {
279 const SEG& seg = poly_set.COutline( ii ).CSegment( jj );
280 AddFeatureLine( seg.A, seg.B, stroke_width );
281 }
282 }
283 }
284
285 break;
286 }
287
288 case SHAPE_T::ARC:
289 {
291
292 AddFeatureArc( aShape.GetStart(), aShape.GetEnd(), aShape.GetCenter(), stroke_width, dir );
293 break;
294 }
295
296 case SHAPE_T::BEZIER:
297 {
298 const std::vector<VECTOR2I>& points = aShape.GetBezierPoints();
299
300 for( size_t i = 0; i < points.size() - 1; i++ )
301 AddFeatureLine( points[i], points[i + 1], stroke_width );
302
303 break;
304 }
305
306 case SHAPE_T::SEGMENT:
307 AddFeatureLine( aShape.GetStart(), aShape.GetEnd(), stroke_width );
308 break;
309
310 case SHAPE_T::ELLIPSE:
311 {
312 int maxError = m_board->GetDesignSettings().m_MaxError;
313
315 aShape.GetEllipseRotation() );
316
318 chain.SetClosed( true );
319
320 if( aShape.IsSolidFill() )
321 {
322 SHAPE_POLY_SET poly_set;
323 poly_set.AddOutline( chain );
324 poly_set.Fracture();
325
326 for( int ii = 0; ii < poly_set.OutlineCount(); ++ii )
327 AddContour( poly_set, ii, FILL_T::FILLED_SHAPE );
328 }
329
330 if( stroke_width > 0 )
331 {
332 for( int ii = 0; ii < chain.SegmentCount(); ++ii )
333 {
334 const SEG& seg = chain.CSegment( ii );
335 AddFeatureLine( seg.A, seg.B, stroke_width );
336 }
337 }
338
339 break;
340 }
341
343 {
344 int maxError = m_board->GetDesignSettings().m_MaxError;
345
347 aShape.GetEllipseRotation(), aShape.GetEllipseStartAngle(), aShape.GetEllipseEndAngle() );
348
350
351 for( int ii = 0; ii < chain.SegmentCount(); ++ii )
352 {
353 const SEG& seg = chain.CSegment( ii );
354 AddFeatureLine( seg.A, seg.B, stroke_width );
355 }
356
357 break;
358 }
359
360 default:
361 wxLogTrace( traceOdbppIo, wxT( "Unknown shape when adding ODB++ layer feature" ) );
362 break;
363 }
364
365 if( aShape.IsHatchedFill() )
366 {
367 for( int ii = 0; ii < aShape.GetHatching().OutlineCount(); ++ii )
369 }
370}
371
372
374 FILL_T aFillType /*= FILL_T::FILLED_SHAPE */ )
375{
376 if( aPolygon.empty() || aPolygon[0].PointCount() < 3 || aPolygon[0].Area( false ) == 0.0 )
377 return false;
378
379 AddFeature<ODB_SURFACE>( aPolygon, aFillType );
380 return true;
381}
382
383
385{
386 const ODB_FORMAT& fmt = m_plugin->GetFormat();
387 PAD_LAYER_GEOMETRY geometry = ResolvePadLayer( aPad, aLayer, m_board->GetDesignSettings().m_MaxError );
388
389 if( geometry.IsEmpty() )
390 return;
391
392 const PAD& resolved = geometry.Pad();
393 VECTOR2I plotSize = resolved.GetSize( aLayer );
394 VECTOR2I center = resolved.ShapePos( aLayer );
395
396 wxString width = ODB::SymDouble2String( fmt, std::abs( plotSize.x ) );
397 wxString height = ODB::SymDouble2String( fmt, std::abs( plotSize.y ) );
398
399 switch( aPad.GetShape( aLayer ) )
400 {
402 {
403 wxString diam = ODB::SymDouble2String( fmt, plotSize.x );
404
406 aPad.GetOrientation() );
407
408 break;
409 }
411 {
412 if( geometry.Margin().x > 0 )
413 {
414 wxString rad = ODB::SymDouble2String( fmt, geometry.CornerRadius() );
415
416 AddFeature<ODB_PAD>( ODB::AddXY( fmt, center ), AddRoundRectSymbol( width, height, rad ),
417 aPad.GetOrientation() );
418 }
419 else
420 {
422 AddRectSymbol( width, height ), aPad.GetOrientation() );
423 }
424
425 break;
426 }
427 case PAD_SHAPE::OVAL:
428 {
429 AddFeature<ODB_PAD>( ODB::AddXY( fmt, center ), AddOvalSymbol( width, height ),
430 aPad.GetOrientation() );
431 break;
432 }
434 {
435 wxString rad = ODB::SymDouble2String( fmt, geometry.CornerRadius() );
436
438 AddRoundRectSymbol( width, height, rad ), aPad.GetOrientation() );
439
440 break;
441 }
443 {
444 if( geometry.Margin().x > 0 || resolved.GetRoundRectCornerRadius( aLayer ) > 0 )
445 {
446 SHAPE_POLY_SET outline = geometry.Polygon();
447
448 for( int ii = 0; ii < outline.OutlineCount(); ++ii )
449 AddContour( outline, ii );
450
451 break;
452 }
453
454 int shorterSide = std::min( plotSize.x, plotSize.y );
455 int chamfer = std::max(
456 0, KiROUND( aPad.GetChamferRectRatio( aLayer ) * shorterSide ) );
457 wxString rad = ODB::SymDouble2String( fmt, chamfer );
458 int positions = aPad.GetChamferPositions( aLayer );
459
461 AddChamferRectSymbol( width, height, rad, positions ), aPad.GetOrientation() );
462
463 break;
464 }
466 {
467 SHAPE_POLY_SET outline = geometry.Polygon();
468
469 for( int ii = 0; ii < outline.OutlineCount(); ++ii )
470 AddContour( outline, ii );
471
472 break;
473 }
475 {
476 SHAPE_POLY_SET shape = geometry.Polygon();
477
478 for( int ii = 0; ii < shape.OutlineCount(); ++ii )
479 AddContour( shape, ii );
480
481 break;
482 }
483 default: wxLogTrace( traceOdbppIo, wxT( "Unknown pad type" ) ); break;
484 }
485}
486
487
489 const DRILL_OPERATION& aOperation )
490{
491 const ODB_FORMAT& format = m_plugin->GetFormat();
492 auto addSide = [&]( const DRILL_POST_MACHINING& aPm, auto aCountersink, auto aCounterbore,
493 auto aDiameter, auto aDepth, auto aAngle )
494 {
497 {
498 return;
499 }
500
502 AddUserDefAttribute( aFeature, sink ? aCountersink : aCounterbore );
503 AddUserDefAttribute( aFeature, decltype( aDiameter ){ format.m_symbolScale * aPm.m_Size } );
504
505 if( aPm.m_Depth > 0 )
506 AddUserDefAttribute( aFeature, decltype( aDepth ){ format.m_symbolScale * aPm.m_Depth } );
507
508 if( sink && aPm.m_Angle > 0 )
509 AddUserDefAttribute( aFeature, decltype( aAngle ){ aPm.m_Angle / 10.0 } );
510 };
511
513 ODB_ATTR::post_machining_top::COUNTERBORE, ODB_ATTR::post_machining_top_diameter{ 0.0 },
514 ODB_ATTR::post_machining_top_depth{ 0.0 }, ODB_ATTR::post_machining_top_angle{ 0.0 } );
516 ODB_ATTR::post_machining_bottom::COUNTERBORE, ODB_ATTR::post_machining_bottom_diameter{ 0.0 },
517 ODB_ATTR::post_machining_bottom_depth{ 0.0 }, ODB_ATTR::post_machining_bottom_angle{ 0.0 } );
518}
519
520
522{
524 return;
525
526 const DRILL_OPERATION* op = m_plugin->GetFabDrillModel().Find( *m_drillSpan, aVia );
527
528 if( !op )
529 return;
530
531 int topType = ODB::IpcViaType( *op, true );
532 int bottomType = ODB::IpcViaType( *op, false );
533
534 if( topType )
535 AddSystemAttribute( aFeature, ODB_ATTR::IPC_VIA_TYPE_TOP{ std::to_string( topType ) } );
536
537 if( bottomType )
538 AddSystemAttribute( aFeature, ODB_ATTR::IPC_VIA_TYPE_BOTTOM{ std::to_string( bottomType ) } );
539
540 if( ODB::ViaInPad( *aVia ) )
541 AddSystemAttribute( aFeature, ODB_ATTR::VIA_IN_PAD{ true } );
542
543 addPostMachiningAttributes( aFeature, *op );
544}
545
546
548{
549 auto iter = GetODBPlugin()->GetViaTraceSubnetMap().find( track );
550
551 if( iter == GetODBPlugin()->GetViaTraceSubnetMap().end() )
552 {
553 wxLogTrace( traceOdbppIo, wxT( "Failed to get subnet track data" ) );
554 return;
555 }
556
557 auto subnet = iter->second;
558 size_t first = FeatureCount();
559
560 auto linkCopper = [&]( ODB_FEATURE&, size_t index )
561 {
562 subnet->AddFeatureID( EDA_DATA::FEATURE_ID::TYPE::COPPER, m_layerName, index );
563 };
564
565 if( track->Type() == PCB_TRACE_T )
566 {
567 PCB_SHAPE shape( nullptr, SHAPE_T::SEGMENT );
568 shape.SetStart( track->GetStart() );
569 shape.SetEnd( track->GetEnd() );
570 shape.SetWidth( FabTrackWidth( *track, aLayer ) );
571
572 AddShape( shape );
573
574 if( IsCopperLayer( aLayer ) )
575 forEachNewFeature( first, linkCopper );
576 }
577 else if( track->Type() == PCB_ARC_T )
578 {
579 const PCB_ARC* arc = static_cast<const PCB_ARC*>( track );
580
581 // Too small arcs cannot be really handled: arc center (and arc radius)
582 // cannot be safely computed
583 if( !arc->IsDegenerated( 10 /* in IU */ ) )
584 {
585 PCB_SHAPE shape( nullptr, SHAPE_T::ARC );
586 shape.SetArcGeometry( arc->GetStart(), arc->GetMid(), arc->GetEnd() );
587 shape.SetWidth( FabTrackWidth( *arc, aLayer ) );
588
589 AddShape( shape );
590 }
591 else
592 {
593 // Approximate this very small arc by a segment.
594 AddFeatureLine( track->GetStart(), track->GetEnd(), FabTrackWidth( *track, aLayer ) );
595 }
596
597
598 if( IsCopperLayer( aLayer ) )
599 forEachNewFeature( first, linkCopper );
600 }
601 else
602 {
603 // add via
604 PCB_VIA* via = static_cast<PCB_VIA*>( track );
605
606 bool hole = false;
607
609 {
612 }
613 else
614 {
616 }
617
618 if( hole )
619 {
620 if( !AddViaDrillHole( via, aLayer ) )
621 return;
622
623 // TODO: confirm TOOLING_HOLE
624 // AddSystemAttribute( *m_featuresList.back(), ODB_ATTR::PAD_USAGE::TOOLING_HOLE );
625
627 first,
628 [&]( ODB_FEATURE& feature, size_t index )
629 {
630 subnet->AddFeatureID( EDA_DATA::FEATURE_ID::TYPE::HOLE, m_layerName, index );
633
634 addViaDrillAttributes( feature, via );
635
636 if( via->GetViaType() == VIATYPE::MICROVIA && m_role == ODB_LAYER_ROLE::DRILL )
638
640 feature,
641 ODB_ATTR::GEOMETRY{ "VIA_RoundD" + std::to_string( via->GetWidth( aLayer ) ) } );
642 } );
643 }
644 else
645 {
646 // to draw via copper shape on copper layer
647 AddVia( via, aLayer );
648
649 forEachNewFeature( first,
650 [&]( ODB_FEATURE& feature, size_t index )
651 {
653 subnet->AddFeatureID( EDA_DATA::FEATURE_ID::TYPE::COPPER, m_layerName, index );
654
657 feature, ODB_ATTR::GEOMETRY{ "VIA_RoundD"
658 + std::to_string( via->GetWidth( aLayer ) ) } );
659 } );
660 }
661 }
662}
663
664
666{
667 SHAPE_POLY_SET zone_shape = zone->GetFilledPolysList( aLayer )->CloneDropTriangulation();
668 EDA_DATA::SUB_NET_PLANE* plane = nullptr;
669
670 if( IsCopperLayer( aLayer ) )
671 {
672 auto iter = GetODBPlugin()->GetPlaneSubnetMap().find( std::make_pair( aLayer, zone ) );
673
674 if( iter == GetODBPlugin()->GetPlaneSubnetMap().end() )
675 {
676 wxLogTrace( traceOdbppIo, wxT( "Failed to get subnet plane data" ) );
677 return;
678 }
679
680 plane = iter->second;
681 }
682
683 for( int ii = 0; ii < zone_shape.OutlineCount(); ++ii )
684 {
685 size_t first = FeatureCount();
686 AddContour( zone_shape, ii );
687
688 forEachNewFeature( first,
689 [&]( ODB_FEATURE& feature, size_t index )
690 {
691 if( plane )
692 plane->AddFeatureID( EDA_DATA::FEATURE_ID::TYPE::COPPER, m_layerName, index );
693
694 if( zone->IsTeardropArea() )
695 AddSystemAttribute( feature, ODB_ATTR::TEAR_DROP{ true } );
696 } );
697 }
698};
699
700
702{
703 EDA_TEXT* text_item = nullptr;
704
705 if( PCB_TEXT* tmp_text = dynamic_cast<PCB_TEXT*>( item ) )
706 text_item = static_cast<EDA_TEXT*>( tmp_text );
707 else if( PCB_TEXTBOX* tmp_textbox = dynamic_cast<PCB_TEXTBOX*>( item ) )
708 text_item = static_cast<EDA_TEXT*>( tmp_textbox );
709
710 if( !text_item || !text_item->IsVisible() )
711 return;
712
713 wxString shownText = text_item->GetShownText( aContext );
714
715 if( shownText.empty() )
716 return;
717
718 auto plot_text =
719 [&]( const VECTOR2I& aPos, const wxString& aTextString, const TEXT_ATTRIBUTES& aAttributes,
720 KIFONT::FONT* aFont, const KIFONT::METRICS& aFontMetrics )
721 {
723
724 TEXT_ATTRIBUTES attributes = aAttributes;
725 int penWidth = attributes.m_StrokeWidth;
726
727 if( penWidth == 0 && attributes.m_Bold ) // Use default values if aPenWidth == 0
728 penWidth = GetPenSizeForBold( std::min( attributes.m_Size.x, attributes.m_Size.y ) );
729
730 if( penWidth < 0 )
731 penWidth = -penWidth;
732
733 attributes.m_StrokeWidth = penWidth;
734
735 std::list<VECTOR2I> pts;
736
737 auto tagString = [&]( ODB_FEATURE& aFeature, size_t )
738 {
739 AddSystemAttribute( aFeature, ODB_ATTR::STRING{ aTextString.utf8_string() } );
740 };
741
742 auto push_pts =
743 [&]()
744 {
745 if( pts.size() < 2 )
746 return;
747
748 // Polylines are only allowed for more than 3 points.
749 // Otherwise, we have to use a line
750
751 if( pts.size() < 3 )
752 {
753 size_t first = FeatureCount();
754 PCB_SHAPE shape( nullptr, SHAPE_T::SEGMENT );
755 shape.SetStart( pts.front() );
756 shape.SetEnd( pts.back() );
757 shape.SetWidth( attributes.m_StrokeWidth );
758
759 AddShape( shape );
760 forEachNewFeature( first, tagString );
761 }
762 else
763 {
764 for( auto it = pts.begin(); std::next( it ) != pts.end(); ++it )
765 {
766 size_t first = FeatureCount();
767 auto it2 = std::next( it );
768 PCB_SHAPE shape( nullptr, SHAPE_T::SEGMENT );
769 shape.SetStart( *it );
770 shape.SetEnd( *it2 );
771 shape.SetWidth( attributes.m_StrokeWidth );
772 AddShape( shape );
773
774 forEachNewFeature( first, tagString );
775 }
776 }
777
778 pts.clear();
779 };
780
781 CALLBACK_GAL callback_gal(
782 empty_opts,
783 // Stroke callback
784 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
785 {
786 if( !pts.empty() )
787 {
788 if( aPt1 == pts.back() )
789 pts.push_back( aPt2 );
790 else if( aPt2 == pts.front() )
791 pts.push_front( aPt1 );
792 else if( aPt1 == pts.front() )
793 pts.push_front( aPt2 );
794 else if( aPt2 == pts.back() )
795 pts.push_back( aPt1 );
796 else
797 {
798 push_pts();
799 pts.push_back( aPt1 );
800 pts.push_back( aPt2 );
801 }
802 }
803 else
804 {
805 pts.push_back( aPt1 );
806 pts.push_back( aPt2 );
807 }
808 },
809 // Polygon callback
810 [&]( const SHAPE_LINE_CHAIN& aPoly )
811 {
812 if( aPoly.PointCount() < 3 )
813 return;
814
815 SHAPE_POLY_SET poly_set;
816 poly_set.AddOutline( aPoly );
817
818 for( int ii = 0; ii < poly_set.OutlineCount(); ++ii )
819 {
820 size_t first = FeatureCount();
821 AddContour( poly_set, ii, FILL_T::FILLED_SHAPE );
822
823 forEachNewFeature( first, tagString );
824 }
825 } );
826
827 aFont->Draw( &callback_gal, aTextString, aPos, aAttributes, aFontMetrics );
828
829 if( !pts.empty() )
830 push_pts();
831 };
832
833 PCB_TEXT* text = nullptr;
834 PCB_TEXTBOX* textbox = nullptr;
835 bool isKnockout = false;
836
837 if( item->Type() == PCB_TEXT_T || item->Type() == PCB_FIELD_T )
838 {
839 text = static_cast<PCB_TEXT*>( item );
840 isKnockout = text->IsKnockout();
841 }
842 else if( item->Type() == PCB_TEXTBOX_T )
843 {
844 textbox = static_cast<PCB_TEXTBOX*>( item );
845 isKnockout = textbox->IsKnockout();
846 }
847
848 const KIFONT::METRICS& fontMetrics = item->GetFontMetrics();
849 KIFONT::FONT* font = text_item->GetDrawFont( nullptr );
850
851 VECTOR2I pos = text_item->GetTextPos();
852
853 TEXT_ATTRIBUTES attrs = text_item->GetAttributes();
854 attrs.m_StrokeWidth = text_item->GetEffectiveTextPenWidth();
855 attrs.m_Angle = text_item->GetDrawRotation();
856 attrs.m_Multiline = false;
857
858 if( isKnockout )
859 {
860 SHAPE_POLY_SET finalpolyset;
861 int maxError = m_board->GetDesignSettings().m_MaxError;
862
863 if( text )
864 text->TransformTextToPolySet( finalpolyset, 0, maxError, ERROR_INSIDE );
865 else if( textbox )
866 textbox->TransformTextToPolySet( finalpolyset, 0, maxError, ERROR_INSIDE );
867
868 finalpolyset.Fracture();
869
870 for( int ii = 0; ii < finalpolyset.OutlineCount(); ++ii )
871 {
872 size_t first = FeatureCount();
873 AddContour( finalpolyset, ii, FILL_T::FILLED_SHAPE );
874
875 forEachNewFeature( first,
876 [&]( ODB_FEATURE& feature, size_t )
877 {
878 AddSystemAttribute( feature, ODB_ATTR::STRING{ shownText.utf8_string() } );
879 } );
880 }
881 }
882 else if( text_item->IsMultilineAllowed() )
883 {
884 std::vector<VECTOR2I> positions;
885 wxArrayString strings_list;
886 wxStringSplit( shownText, strings_list, '\n' );
887 positions.reserve( strings_list.Count() );
888
889 text_item->GetLinePositions( nullptr, positions, strings_list.Count() );
890
891 for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
892 {
893 wxString& txt = strings_list.Item( ii );
894 plot_text( positions[ii], txt, attrs, font, fontMetrics );
895 }
896 }
897 else
898 {
899 plot_text( pos, shownText, attrs, font, fontMetrics );
900 }
901};
902
903
905{
906 // FOOTPRINT* fp = shape->GetParentFootprint();
907 AddShape( *shape, aLayer );
908};
909
910
912{
913 // A dimension is a PCB_TEXT subclass, so the value text is plotted via add_text.
914
915 AddText( aLayer, dimension, FOR_CANVAS );
916
917 PCB_SHAPE temp_shape;
918 temp_shape.SetStroke( STROKE_PARAMS( dimension->GetLineThickness(), LINE_STYLE::SOLID ) );
919 temp_shape.SetLayer( dimension->GetLayer() );
920
921 for( const std::shared_ptr<SHAPE>& shape : dimension->GetShapes() )
922 {
923 switch( shape->Type() )
924 {
925 case SH_SEGMENT:
926 {
927 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
928
929 temp_shape.SetShape( SHAPE_T::SEGMENT );
930 temp_shape.SetStart( seg.A );
931 temp_shape.SetEnd( seg.B );
932
933 AddShape( aLayer, &temp_shape );
934 break;
935 }
936
937 case SH_CIRCLE:
938 {
939 VECTOR2I center( shape->Centre() );
940 int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
941
942 temp_shape.SetShape( SHAPE_T::CIRCLE );
943 temp_shape.SetFilled( false );
944 temp_shape.SetStart( center );
945 temp_shape.SetEnd( VECTOR2I( center.x + radius, center.y ) );
946
947 AddShape( aLayer, &temp_shape );
948 break;
949 }
950
951 default:
952 break;
953 }
954 }
955};
956
957
959{
960 auto iter = GetODBPlugin()->GetPadSubnetMap().find( pad );
961
962 if( iter == GetODBPlugin()->GetPadSubnetMap().end() )
963 {
964 wxLogTrace( traceOdbppIo, wxT( "Failed to get subnet top data" ) );
965 return;
966 }
967
968 if( aLayer != PCB_LAYER_ID::UNDEFINED_LAYER )
969 {
970 // FOOTPRINT* fp = pad->GetParentFootprint();
971
972 size_t first = FeatureCount();
973 AddPadShape( *pad, aLayer );
974 FAB_PAD_ROLE role = GetFabPadRole( *pad );
975
976 forEachNewFeature( first,
977 [&]( ODB_FEATURE& feature, size_t index )
978 {
979 if( IsCopperLayer( aLayer ) )
980 iter->second->AddFeatureID( EDA_DATA::FEATURE_ID::TYPE::COPPER, m_layerName,
981 index );
982
983 switch( role )
984 {
987 break;
990 break;
991 default:
993 break;
994 }
995
996 if( role == FAB_PAD_ROLE::TESTPOINT )
997 AddSystemAttribute( feature, ODB_ATTR::TEST_POINT{ true } );
998
999 if( !pad->HasHole() )
1000 AddSystemAttribute( feature, ODB_ATTR::SMD{ true } );
1001 } );
1002 }
1003 else
1004 {
1005 // drill layer round hole or slot hole
1007 {
1008 wxCHECK_RET( m_drillSpan.has_value(), "Drill layer has no span" );
1009
1010 const DRILL_OPERATION* operation = m_plugin->GetFabDrillModel().Find( *m_drillSpan, pad );
1011
1012 if( !operation )
1013 return;
1014
1015 size_t first = FeatureCount();
1016
1017 // Drill layers hold only circular pads and lines, so a slot is the line its tool cuts
1018 if( operation->m_IsSlot )
1019 {
1020 const VECTOR2I& size = operation->m_SizeXY;
1021 int delta = std::abs( size.x - size.y ) / 2;
1022 VECTOR2I half = size.x > size.y ? VECTOR2I( delta, 0 ) : VECTOR2I( 0, delta );
1023
1024 RotatePoint( half, operation->m_Orientation );
1025 AddFeatureLine( operation->m_Position - half, operation->m_Position + half, operation->m_Diameter );
1026 }
1027 else
1028 {
1029 AddPadCircle( operation->m_Position, operation->m_Diameter );
1030 }
1031
1032 if( pad->GetAttribute() == PAD_ATTRIB::PTH && !operation->IsBackdrill() )
1033 {
1034 // only plated holes link to subnet
1035 forEachNewFeature( first,
1036 [&]( ODB_FEATURE& feature, size_t index )
1037 {
1038 iter->second->AddFeatureID( EDA_DATA::FEATURE_ID::TYPE::HOLE, m_layerName,
1039 index );
1041
1044 } );
1045 }
1046 else
1047 {
1048 forEachNewFeature( first,
1049 [&]( ODB_FEATURE& feature, size_t )
1050 {
1052
1055 } );
1056 }
1057
1058 if( !operation->IsBackdrill() )
1059 {
1060 forEachNewFeature( first,
1061 [&]( ODB_FEATURE& feature, size_t )
1062 {
1063 addPostMachiningAttributes( feature, *operation );
1064 } );
1065 }
1066 }
1067 }
1068 // AddSystemAttribute( *m_featuresList.back(),
1069 // ODB_ATTR::GEOMETRY{ "PAD_xxxx" } );
1070};
1071
1072void FEATURES_MANAGER::InitFeatureList( PCB_LAYER_ID aLayer, const std::vector<BOARD_ITEM*>& aItems )
1073{
1074 for( BOARD_ITEM* item : aItems )
1075 {
1076 switch( item->Type() )
1077 {
1078 case PCB_TRACE_T:
1079 case PCB_ARC_T:
1080 case PCB_VIA_T:
1081 AddTrack( aLayer, static_cast<PCB_TRACK*>( item ) );
1082 break;
1083
1084 case PCB_ZONE_T:
1085 AddZone( aLayer, static_cast<ZONE*>( item ) );
1086 break;
1087
1088 case PCB_PAD_T:
1089 AddPad( aLayer, static_cast<PAD*>( item ) );
1090 break;
1091
1092 case PCB_SHAPE_T:
1093 {
1094 size_t first = FeatureCount();
1095 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
1096 PCB_SHAPE adjusted( nullptr );
1097
1098 if( FabMaskShape( *shape, aLayer, adjusted ) )
1099 AddShape( adjusted, aLayer );
1100 else
1101 AddShape( aLayer, shape );
1102
1103 const FOOTPRINT* footprint = item->GetParentFootprint();
1104
1105 if( footprint && footprint->IsNetTie() && IsCopperLayer( aLayer ) )
1106 {
1107 if( FeatureCount() == first + 1 )
1108 GetODBPlugin()->RecordNetTieFeature( item, aLayer, m_layerName, first );
1109 else
1110 wxLogTrace( traceOdbppIo, wxT( "Net tie shape did not produce one copper feature" ) );
1111 }
1112
1113 break;
1114 }
1115
1116 case PCB_TEXT_T:
1117 case PCB_FIELD_T:
1118 AddText( aLayer, item, FOR_CANVAS );
1119 break;
1120
1121 case PCB_TEXTBOX_T:
1122 AddText( aLayer, item, FOR_CANVAS );
1123
1124 if( static_cast<PCB_TEXTBOX*>( item )->IsBorderEnabled() )
1125 AddShape( aLayer, static_cast<PCB_TEXTBOX*>( item ) );
1126
1127 break;
1128
1129 case PCB_TABLE_T:
1130 case PCB_DRILL_CHART_T:
1131 {
1132 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
1133
1134 for( PCB_TABLECELL* cell : table->GetCells() )
1135 AddText( aLayer, cell, FOR_CANVAS );
1136
1137 table->DrawBorders(
1138 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const STROKE_PARAMS& aStroke )
1139 {
1140 int lineWidth = aStroke.GetWidth();
1141
1142 if( lineWidth > 0 )
1143 AddFeatureLine( aPt1, aPt2, lineWidth );
1144 } );
1145
1146 break;
1147 }
1148
1149 case PCB_DIM_ALIGNED_T:
1150 case PCB_DIM_LEADER_T:
1151 case PCB_DIM_CENTER_T:
1152 case PCB_DIM_RADIAL_T:
1154 AddDimension( aLayer, static_cast<PCB_DIMENSION_BASE*>( item ) );
1155 break;
1156
1157 case PCB_TARGET_T:
1158 //TODO: Add support for targets
1159 break;
1160
1161 case PCB_BARCODE_T:
1162 {
1163 const PCB_BARCODE* barcode = static_cast<const PCB_BARCODE*>( item );
1164 SHAPE_POLY_SET poly_set;
1165
1166 barcode->TransformShapeToPolygon( poly_set, aLayer, 0, m_board->GetDesignSettings().m_MaxError,
1167 ERROR_INSIDE );
1168 poly_set.Fracture();
1169
1170 for( int ii = 0; ii < poly_set.OutlineCount(); ++ii )
1171 AddContour( poly_set, ii, FILL_T::FILLED_SHAPE );
1172
1173 break;
1174 }
1175
1176 default:
1177 break;
1178 }
1179 }
1180}
1181
1182
1184{
1185 if( !aVia->FlashLayer( aLayer ) )
1186 return;
1187
1188 PAD dummy( nullptr ); // default pad shape is circle
1189 dummy.SetPadstack( aVia->Padstack() );
1190 dummy.SetPosition( aVia->GetStart() );
1191
1192 AddPadShape( dummy, aLayer );
1193}
1194
1195
1197{
1199 {
1200 wxCHECK_MSG( m_drillSpan.has_value(), false, "Backdrill layer has no span" );
1201
1202 const DRILL_OPERATION* operation = m_plugin->GetFabDrillModel().Find( *m_drillSpan, aVia );
1203
1204 if( !operation )
1205 return false;
1206
1207 AddPadCircle( operation->m_Position, operation->m_Diameter );
1208 return true;
1209 }
1210
1211 DRILL_SPAN span = m_drillSpan.value_or( DRILL_SPAN( aVia->TopLayer(), aVia->BottomLayer(), false, false ) );
1212 const DRILL_OPERATION* operation = m_plugin->GetFabDrillModel().Find( span, aVia );
1213
1214 if( !operation )
1215 return false;
1216
1217 PAD dummy( nullptr );
1218 dummy.SetPadstackMode( PADSTACK::MODE::NORMAL );
1220 dummy.SetPosition( aVia->GetStart() );
1221 dummy.SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( operation->m_Diameter, operation->m_Diameter ) );
1222
1223 AddPadShape( dummy, aLayer );
1224 return true;
1225}
1226
1227
1228void FEATURES_MANAGER::GenerateProfileFeatures( std::ostream& ost ) const
1229{
1230 const ODB_FORMAT& format = m_plugin->GetFormat();
1231 ost << "UNITS=" << format.m_unitsStr << std::endl;
1232 ost << "#\n#Num Features\n#" << std::endl;
1233 ost << "F " << m_featuresList.size() << std::endl;
1234
1235 if( m_featuresList.empty() )
1236 return;
1237
1238 ost << "#\n#Layer features\n#" << std::endl;
1239
1240 for( const auto& feat : m_featuresList )
1241 {
1242 feat->WriteFeatures( ost, format );
1243 }
1244}
1245
1246
1247void FEATURES_MANAGER::GenerateFeatureFile( std::ostream& ost ) const
1248{
1249 const ODB_FORMAT& format = m_plugin->GetFormat();
1250 ost << "UNITS=" << format.m_unitsStr << std::endl;
1251 ost << "#\n#Num Features\n#" << std::endl;
1252 ost << "F " << m_featuresList.size() << std::endl << std::endl;
1253
1254 if( m_featuresList.empty() )
1255 return;
1256
1257 ost << "#\n#Feature symbol names\n#" << std::endl;
1258
1259 for( const auto& [n, name] : m_allSymMap )
1260 {
1261 ost << "$" << n << " " << name << std::endl;
1262 }
1263
1264 WriteAttributes( ost );
1265
1266 ost << "#\n#Layer features\n#" << std::endl;
1267
1268 for( const auto& feat : m_featuresList )
1269 {
1270 feat->WriteFeatures( ost, format );
1271 }
1272}
1273
1274
1275void ODB_FEATURE::WriteFeatures( std::ostream& ost, const ODB_FORMAT& aFormat )
1276{
1277 switch( GetFeatureType() )
1278 {
1279 case FEATURE_TYPE::LINE: ost << "L "; break;
1280
1281 case FEATURE_TYPE::ARC: ost << "A "; break;
1282
1283 case FEATURE_TYPE::PAD: ost << "P "; break;
1284
1285 case FEATURE_TYPE::SURFACE: ost << "S "; break;
1286 default: return;
1287 }
1288
1289 WriteRecordContent( ost, aFormat );
1290 ost << std::endl;
1291}
1292
1293
1294void ODB_LINE::WriteRecordContent( std::ostream& ost, const ODB_FORMAT& )
1295{
1296 ost << m_start.first << " " << m_start.second << " " << m_end.first << " " << m_end.second
1297 << " " << m_symIndex << " P 0";
1298
1299 WriteAttributes( ost );
1300}
1301
1302
1303void ODB_ARC::WriteRecordContent( std::ostream& ost, const ODB_FORMAT& )
1304{
1305 ost << m_start.first << " " << m_start.second << " " << m_end.first << " " << m_end.second
1306 << " " << m_center.first << " " << m_center.second << " " << m_symIndex << " P 0 "
1307 << ( m_direction == ODB_DIRECTION::CW ? "Y" : "N" );
1308
1309 WriteAttributes( ost );
1310}
1311
1312
1313void ODB_PAD::WriteRecordContent( std::ostream& ost, const ODB_FORMAT& aFormat )
1314{
1315 ost << m_center.first << " " << m_center.second << " ";
1316
1317 // TODO: support resize symbol
1318 // ost << "-1" << " " << m_symIndex << " "
1319 // << m_resize << " P 0 ";
1320
1321 ost << m_symIndex << " P 0 ";
1322
1323 ost << "8 " << ODB::Double2String( aFormat, ( ANGLE_360 - m_angle ).Normalize().AsDegrees() );
1324
1325 WriteAttributes( ost );
1326}
1327
1328
1329ODB_SURFACE::ODB_SURFACE( uint32_t aIndex, const SHAPE_POLY_SET::POLYGON& aPolygon,
1330 FILL_T aFillType /*= FILL_T::FILLED_SHAPE*/ ) : ODB_FEATURE( aIndex )
1331{
1332 m_surfaces = std::make_unique<ODB_SURFACE_DATA>( aPolygon );
1333
1334 if( aFillType != FILL_T::NO_FILL )
1335 m_surfaces->AddPolygonHoles( aPolygon );
1336}
1337
1338
1339void ODB_SURFACE::WriteRecordContent( std::ostream& ost, const ODB_FORMAT& aFormat )
1340{
1341 ost << "P 0";
1342 WriteAttributes( ost );
1343 ost << std::endl;
1344 m_surfaces->WriteData( ost, aFormat );
1345 ost << "SE";
1346}
1347
1348
1350{
1351 AddContour( aPolygon[0], false );
1352}
1353
1354
1356{
1357 for( size_t ii = 1; ii < aPolygon.size(); ++ii )
1358 AddContour( aPolygon[ii], true );
1359}
1360
1361
1362void ODB_SURFACE_DATA::AddContour( const SHAPE_LINE_CHAIN& aChain, bool aHole )
1363{
1364 if( aChain.PointCount() < 3 )
1365 return;
1366
1367 double area = aChain.Area( false );
1368
1369 if( area == 0.0 )
1370 return;
1371
1372 const std::vector<VECTOR2I>& pts = aChain.CPoints();
1373 bool reverse = aHole ? area > 0 : area < 0;
1374 auto& contour = m_polygons.emplace_back();
1375 contour.reserve( pts.size() + 1 );
1376
1377 if( reverse )
1378 {
1379 contour.emplace_back( pts.front() );
1380
1381 for( auto it = pts.rbegin(); it != pts.rend(); ++it )
1382 contour.emplace_back( *it );
1383 }
1384 else
1385 {
1386 contour.emplace_back( pts.back() );
1387
1388 for( const VECTOR2I& pt : pts )
1389 contour.emplace_back( pt );
1390 }
1391}
1392
1393
1394void ODB_SURFACE_DATA::WriteData( std::ostream& ost, const ODB_FORMAT& aFormat ) const
1395{
1396 ODB::CHECK_ONCE is_island;
1397
1398 for( const auto& contour : m_polygons )
1399 {
1400 if( contour.empty() )
1401 continue;
1402
1403 ost << "OB " << ODB::AddXY( aFormat, contour.back().m_end ).first << " "
1404 << ODB::AddXY( aFormat, contour.back().m_end ).second << " ";
1405
1406 if( is_island() )
1407 ost << "I";
1408 else
1409 ost << "H";
1410 ost << std::endl;
1411
1412 for( const auto& line : contour )
1413 {
1414 if( SURFACE_LINE::LINE_TYPE::SEGMENT == line.m_type )
1415 ost << "OS " << ODB::AddXY( aFormat, line.m_end ).first << " "
1416 << ODB::AddXY( aFormat, line.m_end ).second << std::endl;
1417 else
1418 ost << "OC " << ODB::AddXY( aFormat, line.m_end ).first << " "
1419 << ODB::AddXY( aFormat, line.m_end ).second << " " << ODB::AddXY( aFormat, line.m_center ).first
1420 << " " << ODB::AddXY( aFormat, line.m_center ).second << " "
1421 << ( line.m_direction == ODB_DIRECTION::CW ? "Y" : "N" ) << std::endl;
1422 }
1423 ost << "OE" << std::endl;
1424 }
1425}
int index
const char * name
@ ERROR_OUTSIDE
@ ERROR_INSIDE
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
void WriteAttributes(std::ostream &ost, const std::string &prefix="") const
void AddUserDefAttribute(Tr &r, Ta v)
void AddSystemAttribute(Tr &r, Ta v)
void WriteAttributes(std::ostream &ost) const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual bool IsKnockout() const
Definition board_item.h:414
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
FOOTPRINT * GetParentFootprint() const
const KIFONT::METRICS & GetFontMetrics() const
void AddFeatureID(FEATURE_ID::TYPE type, const wxString &layer, size_t feature_id)
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
int GetEllipseMinorRadius() const
Definition eda_shape.h:395
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:377
const SHAPE_POLY_SET & GetHatching() const
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:423
int GetEllipseMajorRadius() const
Definition eda_shape.h:386
int GetRectangleWidth() const
SHAPE_POLY_SET & GetPolyShape()
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:404
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:175
bool IsHatchedFill() const
Definition eda_shape.h:130
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:142
bool IsSolidFill() const
Definition eda_shape.h:123
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
std::vector< VECTOR2I > GetRectCorners() const
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:414
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition eda_shape.h:491
int GetRectangleHeight() const
bool IsClockwiseArc() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:313
bool IsMultilineAllowed() const
Definition eda_text.h:236
virtual bool IsVisible() const
Definition eda_text.h:226
virtual EDA_ANGLE GetDrawRotation() const
Definition eda_text.h:425
virtual wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const
Return the string actually shown after processing of the base text.
Definition eda_text.h:128
virtual KIFONT::FONT * GetDrawFont(const RENDER_SETTINGS *aSettings) const
Definition eda_text.cpp:647
const TEXT_ATTRIBUTES & GetAttributes() const
Definition eda_text.h:270
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:427
void GetLinePositions(const RENDER_SETTINGS *aSettings, std::vector< VECTOR2I > &aPositions, int aLineCount) const
Populate aPositions with the position of each line of a multiline text, according to the vertical jus...
Definition eda_text.cpp:931
void AddPadShape(const PAD &aPad, PCB_LAYER_ID aLayer)
uint32_t AddRectSymbol(const wxString &aWidth, const wxString &aHeight)
void AddRoutSlot(const PAD &aPad, int aChain)
void AddPad(PCB_LAYER_ID aLayer, PAD *pad)
size_t FeatureCount() const
Definition odb_feature.h:92
void addPostMachiningAttributes(ODB_FEATURE &aFeature, const DRILL_OPERATION &aOperation)
void AddVia(const PCB_VIA *aVia, PCB_LAYER_ID aLayer)
void AddDimension(PCB_LAYER_ID aLayer, PCB_DIMENSION_BASE *dimension)
void tagRoutFeatures(size_t aFirst, int aChain, bool aPlated)
PCB_IO_ODBPP * GetODBPlugin()
void AddShape(PCB_LAYER_ID aLayer, PCB_SHAPE *shape)
void AddFeatureLine(const VECTOR2I &aStart, const VECTOR2I &aEnd, uint64_t aWidth)
PCB_IO_ODBPP * m_plugin
void AddFeatureArc(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, uint64_t aWidth, ODB_DIRECTION aDirection)
std::map< uint32_t, wxString > m_allSymMap
void GenerateFeatureFile(std::ostream &ost) const
void addViaDrillAttributes(ODB_FEATURE &aFeature, const PCB_VIA *aVia)
ODB_LAYER_ROLE m_role
void AddTrack(PCB_LAYER_ID aLayer, PCB_TRACK *track)
void AddZone(PCB_LAYER_ID aLayer, ZONE *zone)
bool AddViaDrillHole(const PCB_VIA *aVia, PCB_LAYER_ID aLayer)
void AddText(PCB_LAYER_ID aLayer, BOARD_ITEM *item, RESOLUTION_CONTEXT aContext)
std::optional< DRILL_SPAN > m_drillSpan
std::optional< ODB_AUX_LAYER_TYPE > m_auxType
void InitFeatureList(PCB_LAYER_ID aLayer, const std::vector< BOARD_ITEM * > &aItems)
uint32_t AddRoundRectSymbol(const wxString &aWidth, const wxString &aHeight, const wxString &aRadius)
wxString m_layerName
void AddPadCircle(const VECTOR2I &aCenter, uint64_t aDiameter)
void forEachNewFeature(size_t aFirst, F &&aFunc)
void AddRoutContour(const SHAPE_LINE_CHAIN &aContour, int aChain, bool aPlated)
bool AddFeatureSurface(const SHAPE_POLY_SET::POLYGON &aPolygon, FILL_T aFillType=FILL_T::FILLED_SHAPE)
uint32_t AddOvalSymbol(const wxString &aWidth, const wxString &aHeight)
void GenerateProfileFeatures(std::ostream &ost) const
std::list< std::unique_ptr< ODB_FEATURE > > m_featuresList
void AddFeature(Args &&... args)
uint32_t AddCircleSymbol(const wxString &aDiameter)
uint32_t AddChamferRectSymbol(const wxString &aWidth, const wxString &aHeight, const wxString &aRadius, int aPositions)
uint32_t AddRoundDonutSymbol(const wxString &aOuterDim, const wxString &aInnerDim)
bool AddContour(const SHAPE_POLY_SET &aPolySet, int aOutline=0, FILL_T aFillType=FILL_T::FILLED_SHAPE)
bool IsNetTie() const
Definition footprint.h:567
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:94
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
std::pair< wxString, wxString > m_end
std::pair< wxString, wxString > m_start
uint32_t m_symIndex
virtual void WriteRecordContent(std::ostream &ost, const ODB_FORMAT &aFormat) override
ODB_DIRECTION m_direction
std::pair< wxString, wxString > m_center
virtual FEATURE_TYPE GetFeatureType()=0
virtual void WriteRecordContent(std::ostream &ost, const ODB_FORMAT &aFormat)=0
virtual void WriteFeatures(std::ostream &ost, const ODB_FORMAT &aFormat)
ODB_FEATURE(uint32_t aIndex)
virtual void WriteRecordContent(std::ostream &ost, const ODB_FORMAT &aFormat) override
std::pair< wxString, wxString > m_start
std::pair< wxString, wxString > m_end
uint32_t m_symIndex
uint32_t m_symIndex
virtual void WriteRecordContent(std::ostream &ost, const ODB_FORMAT &aFormat) override
EDA_ANGLE m_angle
std::pair< wxString, wxString > m_center
std::vector< std::vector< SURFACE_LINE > > m_polygons
void AddContour(const SHAPE_LINE_CHAIN &aChain, bool aHole)
void WriteData(std::ostream &ost, const ODB_FORMAT &aFormat) const
ODB_SURFACE_DATA(const SHAPE_POLY_SET::POLYGON &aPolygon)
void AddPolygonHoles(const SHAPE_POLY_SET::POLYGON &aPolygon)
std::unique_ptr< ODB_SURFACE_DATA > m_surfaces
virtual void WriteRecordContent(std::ostream &ost, const ODB_FORMAT &aFormat) override
ODB_SURFACE(uint32_t aIndex, const SHAPE_POLY_SET::POLYGON &aPolygon, FILL_T aFillType=FILL_T::FILLED_SHAPE)
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
A pad's resolved artwork on one fabrication layer.
SHAPE_POLY_SET Polygon() const
VECTOR2I Margin() const
const PAD & Pad() const
Definition pad.h:61
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1182
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1328
PAD_ATTRIB GetAttribute() const
Definition pad.h:560
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:298
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1757
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:852
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:834
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1868
bool IsDegenerated(int aThreshold=5) const
const VECTOR2I & GetMid() const
Definition pcb_track.h:295
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the barcode (text + symbol shapes) to polygonal geometry suitable for filling/collision tests...
Abstract dimension API.
int GetLineThickness() const
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
std::map< std::pair< PCB_LAYER_ID, ZONE * >, EDA_DATA::SUB_NET_PLANE * > & GetPlaneSubnetMap()
std::map< PCB_TRACK *, EDA_DATA::SUB_NET * > & GetViaTraceSubnetMap()
void RecordNetTieFeature(const BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, const wxString &aLayerName, size_t aIndex)
std::map< const PAD *, EDA_DATA::SUB_NET_TOEPRINT * > & GetPadSubnetMap()
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:78
void SetWidth(int aWidth) override
int GetWidth() const override
void SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:209
void SetEnd(const VECTOR2I &aEnd) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
void SetStart(const VECTOR2I &aStart) override
void SetStroke(const STROKE_PARAMS &aStroke) override
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd) override
Set the three controlling points for an arc.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Convert the text to a polygonSet describing the actual character strokes (one per segment).
const VECTOR2I & GetStart() const
Definition pcb_track.h:98
const VECTOR2I & GetEnd() const
Definition pcb_track.h:95
PCB_LAYER_ID BottomLayer() const
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
const PADSTACK & Padstack() const
Definition pcb_track.h:427
PCB_LAYER_ID TopLayer() const
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
bool IsClockwise() const
Definition shape_arc.h:323
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
const VECTOR2I & GetCenter() const
int GetRadius() const
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
int NextShape(int aPointIndex) const
Return the vertex index of the next shape in the chain, or -1 if aPointIndex is the last shape.
double Area(bool aAbsolute=true) const
Return the area of this chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
bool IsArcStart(size_t aIndex) const
const std::vector< VECTOR2I > & CPoints() const
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
SHAPE_POLY_SET CloneDropTriangulation() const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const SEG & GetSeg() const
Simple container to manage line stroke parameters.
int GetWidth() const
EDA_ORIENTATION m_Angle
Handle a list of polygons defining a copper zone.
Definition zone.h:70
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition zone.h:699
bool IsTeardropArea() const
Definition zone.h:807
RESOLUTION_CONTEXT
Definition common.h:89
@ FOR_CANVAS
Definition common.h:90
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:454
FILL_T
Definition eda_fill.h:29
@ NO_FILL
Definition eda_fill.h:30
@ FILLED_SHAPE
Fill with object color.
Definition eda_fill.h:31
@ ELLIPSE
Definition eda_shape.h:62
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
@ ELLIPSE_ARC
Definition eda_shape.h:63
int FabTrackWidth(const PCB_TRACK &aTrack, PCB_LAYER_ID aLayer)
Use only for traces and arcs; vias require a layer-specific width.
bool FabMaskShape(const PCB_SHAPE &aShape, PCB_LAYER_ID aLayer, PCB_SHAPE &aResult)
Build an expanded mask copy of an exposed copper shape when needed.
PAD_LAYER_GEOMETRY ResolvePadLayer(const PAD &aPad, PCB_LAYER_ID aLayer, int aMaxError)
Artwork on one layer as plotted by PlotStandardLayer; keep the plotter independent as the parity orac...
FAB_PAD_ROLE GetFabPadRole(const PAD &aPad)
Explicit fabrication properties take precedence over the unnumbered NPTH fallback.
Definition fab_pin.cpp:26
FAB_PAD_ROLE
Definition fab_pin.h:28
@ FIDUCIAL_LOCAL
Definition fab_pin.h:32
@ FIDUCIAL_GLOBAL
Definition fab_pin.h:31
int GetPenSizeForBold(int aTextSize)
Definition gr_text.cpp:33
const wxChar *const traceOdbppIo
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Mask
Definition layer_ids.h:94
@ F_Mask
Definition layer_ids.h:93
@ UNDEFINED_LAYER
Definition layer_ids.h:57
std::pair< wxString, wxString > AddXY(const ODB_FORMAT &aFormat, const VECTOR2I &aVec)
Definition odb_util.cpp:412
int IpcViaType(const DRILL_OPERATION &aOperation, bool aTop)
Definition odb_util.cpp:43
bool ViaInPad(const PCB_VIA &aVia)
Definition odb_util.cpp:68
VECTOR2I GetShapePosition(const PCB_SHAPE &aShape)
Definition odb_util.cpp:426
wxString SymDouble2String(const ODB_FORMAT &aFormat, double aVal)
Definition odb_util.cpp:400
wxString Double2String(const ODB_FORMAT &aFormat, double aVal)
Definition odb_util.cpp:382
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
ODB_DIRECTION
Definition odb_feature.h:37
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ CHAMFERED_RECT
Definition padstack.h:59
@ ROUNDRECT
Definition padstack.h:56
@ TRAPEZOID
Definition padstack.h:55
@ RECTANGLE
Definition padstack.h:53
BARCODE class definition.
CITER next(CITER it)
Definition ptree.cpp:120
@ SH_CIRCLE
circle
Definition shape.h:46
@ SH_SEGMENT
line segment
Definition shape.h:44
std::vector< FAB_LAYER_COLOR > dummy
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
One machining action, which is also one NC hit and one tool assignment.
bool IsBackdrill() const
DRILL_POST_MACHINING m_BackPostMachining
VECTOR2I m_SizeXY
Source axes, never normalized to (width, length).
EDA_ANGLE m_Orientation
DRILL_POST_MACHINING m_FrontPostMachining
int m_Size
int m_Depth
int m_Angle
PAD_DRILL_POST_MACHINING_MODE m_Mode
double m_symbolScale
Definition odb_util.h:71
std::string m_unitsStr
Definition odb_util.h:73
VECTOR2I center
const SHAPE_LINE_CHAIN chain
int radius
VECTOR2I end
int delta
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:99
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708