KiCad PCB EDA Suite
Loading...
Searching...
No Matches
easypc_pcb_items.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 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
25
28#include <font/font.h>
29#include <footprint.h>
30#include <ki_exception.h>
31#include <geometry/shape_arc.h>
34#include <lib_id.h>
35#include <pad.h>
36#include <pcb_field.h>
37#include <pcb_shape.h>
38#include <pcb_text.h>
39#include <stroke_params.h>
40
41#include <algorithm>
42#include <cmath>
43#include <limits>
44#include <optional>
45#include <set>
46
47
48using namespace EASYPC;
49
51
52
53namespace EASYPC_PCB
54{
55
56namespace
57{
58
59 constexpr int IU_PER_UNIT = NM_PER_DSU;
60
62 constexpr int OPENING_MAX_ERROR = 1000;
63
64
66 int lengthOf( int64_t aLength )
67 {
68 if( std::abs( aLength ) > COORD_LIMIT / IU_PER_UNIT )
69 {
70 THROW_IO_ERROR( wxString::Format( _( "Easy-PC length %lld is outside KiCad's range" ),
71 static_cast<long long>( aLength ) ) );
72 }
73
74 return static_cast<int>( aLength * IU_PER_UNIT );
75 }
76
77
79 PCB_LAYER_ID vendorTechLayer( const SOURCE_LAYER* aLayer )
80 {
81 wxString name = ( aLayer->Type ? aLayer->Type->Name : aLayer->TypeName ).Upper();
82 bool back = aLayer->Side == LAYER_SIDE::BOTTOM;
83
84 if( name.Contains( wxS( "PASTE" ) ) )
85 return back ? B_Paste : F_Paste;
86
87 if( name.Contains( wxS( "SILK" ) ) )
88 return back ? B_SilkS : F_SilkS;
89
90 if( name.Contains( wxS( "RESIST" ) ) || name.Contains( wxS( "SOLDER MASK" ) ) )
91 return back ? B_Mask : F_Mask;
92
93 return UNDEFINED_LAYER;
94 }
95
96
98 VECTOR2D ArcCentre( const POINT32& aStart, const POINT32& aEnd, int32_t aArcAngle, bool aAnticlockwise )
99 {
100 double hx = ( aEnd.X - aStart.X ) * 0.5;
101 double hy = ( aEnd.Y - aStart.Y ) * 0.5;
102 double cx = aStart.X + hx;
103 double cy = aStart.Y + hy;
104 double t = std::tan( ( aArcAngle * M_PI / 180000.0 ) * ( aAnticlockwise ? 1 : -1 ) * 0.5 );
105
106 if( t != 0.0 )
107 {
108 cx = cx - hy / t;
109 cy = hx / t + cy;
110 }
111
112 auto closeTo = []( int32_t aA, double aB )
113 {
114 return std::abs( aA - static_cast<int32_t>( aB < 0.0 ? aB - 0.5 : aB + 0.5 ) ) < 3;
115 };
116
117 if( closeTo( aStart.X, cx ) && closeTo( aEnd.Y, cy ) )
118 return VECTOR2D( aStart.X, aEnd.Y );
119
120 if( closeTo( aEnd.X, cx ) && closeTo( aStart.Y, cy ) )
121 return VECTOR2D( aEnd.X, aStart.Y );
122
123 return VECTOR2D( cx, cy );
124 }
125
126
127 VECTOR2D arcPoint( const POINT32& aStart, const VECTOR2D& aCentre, int32_t aArcAngle, bool aAnticlockwise,
128 double aFraction )
129 {
130 double a0 = std::atan2( aStart.Y - aCentre.y, aStart.X - aCentre.x );
131 double sweep = aArcAngle / 1000.0 * M_PI / 180.0 * ( aAnticlockwise ? 1.0 : -1.0 );
132 double r = std::hypot( aStart.X - aCentre.x, aStart.Y - aCentre.y );
133 double a = a0 + sweep * aFraction;
134 return VECTOR2D( aCentre.x + r * std::cos( a ), aCentre.y + r * std::sin( a ) );
135 }
136
137
138 struct SPAN
139 {
140 POINT32 Start;
141 POINT32 End;
142 int32_t ArcAngle = 0;
143 bool Anticlockwise = true;
144 };
145
146
148 std::vector<SPAN> spansOf( const SOURCE_SHAPE& aShape )
149 {
150 std::vector<const SOURCE_SEGMENT*> verts;
151
152 for( const OBJECT* obj : aShape.Segments )
153 {
154 if( const SOURCE_SEGMENT* seg = dynamic_cast<const SOURCE_SEGMENT*>( obj ) )
155 verts.push_back( seg );
156 }
157
158 std::vector<SPAN> spans;
159 size_t n = verts.size();
160
161 for( size_t i = 0; n > 0 && i < ( aShape.IsClosed() ? n : n - 1 ); ++i )
162 {
163 const SOURCE_SEGMENT* s = verts[i];
164 const SOURCE_SEGMENT* e = verts[( i + 1 ) % n];
165 spans.push_back( { POINT32{ s->X, s->Y }, POINT32{ e->X, e->Y }, s->ArcAngle, s->Anticlockwise } );
166 }
167
168 return spans;
169 }
170
171
172 SHAPE_LINE_CHAIN shapeToChain( const SOURCE_SHAPE& aShape, const FRAME& aFrame )
173 {
175 std::vector<SPAN> spans = spansOf( aShape );
176
177 for( size_t i = 0; i < spans.size(); ++i )
178 {
179 ARC_FORM form = ArcForm( spans[i].Start, spans[i].End, spans[i].ArcAngle, spans[i].Anticlockwise, aFrame );
180
181 if( form.IsArc() )
182 {
183 chain.Append( SHAPE_ARC( form.Start, form.Mid, form.End, 0 ) );
184 continue;
185 }
186
187 for( size_t k = i == 0 ? 0 : 1; k < form.Points.size(); ++k )
188 chain.Append( form.Points[k] );
189 }
190
191 chain.SetClosed( aShape.IsClosed() );
192 return chain;
193 }
194
195
197 SHAPE_POLY_SET bulletOutline( int32_t aSize, int32_t aLength )
198 {
199 double radius = ( aSize + 1 ) / 2;
200 double h = std::max( radius / 2, double( ( aLength + 1 ) / 2 ) );
201 double k = h - radius;
202
203 auto pt = [&]( double aX, double aY )
204 {
205 return VECTOR2I( KiROUND( aX * IU_PER_UNIT ), KiROUND( -aY * IU_PER_UNIT ) );
206 };
207
209 chain.Append( pt( -radius, -h ) );
210 chain.Append( pt( radius, -h ) );
211 chain.Append( pt( radius, k ) );
212 chain.Append( SHAPE_ARC( pt( radius, k ), pt( 0, k + radius ), pt( -radius, k ), 0 ) );
213 chain.SetClosed( true );
214
215 SHAPE_POLY_SET poly;
216 poly.AddOutline( chain );
217 poly.Fracture();
218 return poly;
219 }
220
221
223 void setPadShape( PAD& aPad, PCB_LAYER_ID aLayer, EASYPC::PAD_SHAPE aShape, int32_t aSize, int32_t aLength,
224 int32_t aD3 )
225 {
226 VECTOR2I square( lengthOf( aSize ), lengthOf( aSize ) );
227 VECTOR2I sized( lengthOf( aSize ), lengthOf( aLength ) );
228
229 switch( aShape )
230 {
232 aPad.SetShape( aLayer, KI_PAD_SHAPE::CIRCLE );
233 aPad.SetSize( aLayer, square );
234 break;
235
237 aPad.SetShape( aLayer, KI_PAD_SHAPE::RECTANGLE );
238 aPad.SetSize( aLayer, square );
239 break;
240
242 aPad.SetShape( aLayer, KI_PAD_SHAPE::RECTANGLE );
243 aPad.SetSize( aLayer, sized );
244 break;
245
247 aPad.SetShape( aLayer, KI_PAD_SHAPE::OVAL );
248 aPad.SetSize( aLayer, sized );
249 break;
250
252 aPad.SetShape( aLayer, KI_PAD_SHAPE::ROUNDRECT );
253 aPad.SetSize( aLayer, sized );
254 aPad.SetRoundRectRadiusRatio( aLayer, std::clamp<double>( aD3, 0.0, std::min( aSize, aLength ) / 2.0 )
255 / std::min( aSize, aLength ) );
256 break;
257
259 // Regular, flats on the axes, chamfer leg round(S / (2 + sqrt 2))
260 aPad.SetShape( aLayer, KI_PAD_SHAPE::CHAMFERED_RECT );
261 aPad.SetSize( aLayer, square );
262 aPad.SetChamferRectRatio( aLayer, std::round( aSize / ( 2.0 + std::sqrt( 2.0 ) ) ) / aSize );
264 break;
265
267 {
268 int anchor = std::max( 1, lengthOf( std::min( aSize, aLength ) ) / 4 );
269
270 aPad.SetShape( aLayer, KI_PAD_SHAPE::CUSTOM );
271 aPad.SetAnchorPadShape( aLayer, KI_PAD_SHAPE::CIRCLE );
272 aPad.SetSize( aLayer, VECTOR2I( anchor, anchor ) );
273 aPad.AddPrimitivePoly( aLayer, bulletOutline( aSize, aLength ), 0, true );
274 break;
275 }
276
277 default:
278 // A guessed outline would be wrong copper, so a shape no known file uses is refused
279 THROW_IO_ERROR( wxString::Format( _( "Unsupported Easy-PC pad shape %d." ), static_cast<int>( aShape ) ) );
280 }
281 }
282
283
285 struct LAYER_OUTLINE
286 {
287 EASYPC::PAD_SHAPE Shape;
288 int32_t Size;
289 int32_t Length;
290 int32_t Dimension3;
291 };
292
293
294 LAYER_OUTLINE exceptionOutline( const SOURCE_PAD_STYLE& aStyle, const SOURCE_PAD_STYLE_EXCEPTION& aException )
295 {
296 LAYER_OUTLINE out{ aException.Shape, aException.Size, aException.Length ? aException.Length : aException.Size,
297 aException.Dimension3 };
298 int32_t holeX = aStyle.Drill;
299 int32_t holeY =
300 aStyle.DrillShape != EASYPC::PAD_SHAPE::ROUND && aStyle.Drill ? aStyle.DrillLength : aStyle.Drill;
301
302 if( holeX > out.Size && holeY > out.Length )
303 out = { aStyle.DrillShape, holeX, holeY, aStyle.DrillCornerRadius };
304
305 return out;
306 }
307
308
310 void applyPadStyleExceptions( FOOTPRINT* aParent, PAD& aPad, const SOURCE_PAD_STYLE& aStyle,
311 const LAYER_MAPPER& aLayers )
312 {
313 std::vector<const SOURCE_PAD_STYLE_EXCEPTION*> exceptions =
315 LSET layers = aPad.GetLayerSet();
316
317 for( PCB_LAYER_ID layer :
318 LSET( layers & ( LSET::AllCuMask() | LSET( { F_Mask, B_Mask, F_Paste, B_Paste } ) ) ) )
319 {
320 const SOURCE_LAYER* native = aLayers.Native( layer );
321 auto it = std::find_if( exceptions.begin(), exceptions.end(),
322 [&]( const SOURCE_PAD_STYLE_EXCEPTION* aEx )
323 {
324 return aEx->Layer == native;
325 } );
326
327 if( !native || it == exceptions.end() )
328 continue;
329
330 LAYER_OUTLINE outline = exceptionOutline( aStyle, **it );
331 bool present = ( ( int64_t( outline.Size ) + 1 ) >> 1 ) >= 1;
332
333 if( IsCopperLayer( layer ) )
334 {
335 if( !present )
336 {
337 layers.reset( layer );
338 continue;
339 }
340
342 setPadShape( aPad, layer, outline.Shape, outline.Size, outline.Length, outline.Dimension3 );
343 continue;
344 }
345
346 // A KiCad pad has one opening per side, so the exception's opening is drawn on its own
347 layers.reset( layer );
348
349 if( !present || !aParent )
350 continue;
351
352 PAD opening( aPad );
354 setPadShape( opening, PADSTACK::ALL_LAYERS, outline.Shape, aLayers.GrowByLayer( native, outline.Size ),
355 aLayers.GrowByLayer( native, outline.Length ), outline.Dimension3 );
356
357 SHAPE_POLY_SET poly;
358 opening.TransformShapeToPolygon( poly, F_Cu, 0, OPENING_MAX_ERROR, ERROR_INSIDE );
359
360 PCB_SHAPE* shape = new PCB_SHAPE( aParent, SHAPE_T::POLY );
361 shape->SetPolyShape( poly );
362 shape->SetFilled( true );
364 shape->SetLayer( layer );
365 aParent->Add( shape );
366 }
367
368 aPad.SetLayerSet( layers );
369 }
370
371
373 BOX2I strokeBox( const PCB_TEXT& aText )
374 {
375 BOX2I box;
376 std::shared_ptr<SHAPE_COMPOUND> shapes = aText.GetEffectiveTextShape( false );
377
378 for( SHAPE* shape : shapes->Shapes() )
379 {
380 if( shape->Type() == SH_SEGMENT )
381 {
382 box.Merge( static_cast<SHAPE_SEGMENT*>( shape )->GetSeg().A );
383 box.Merge( static_cast<SHAPE_SEGMENT*>( shape )->GetSeg().B );
384 }
385 else
386 {
387 box.Merge( shape->BBox() );
388 }
389 }
390
391 return box;
392 }
393
394
396 wxString PcbPadNumber( const SOURCE_PCB_COMPONENT& aComponent, int aPadNumber )
397 {
398 const wxString pad = wxString::Format( wxS( "%d" ), aPadNumber );
399 std::set<wxString> used;
400
401 // A pad named by a gate pin takes that pin's component pin number
402 for( const SOURCE_GATE_MAP* map : TypedItems<const SOURCE_GATE_MAP>( aComponent.GateMaps ) )
403 {
404 for( const SOURCE_GATE_PIN* pin : TypedItems<const SOURCE_GATE_PIN>( map->Pins ) )
405 {
406 if( pin->PcbSymbolPin == pad )
407 return pin->PinNumber;
408 }
409 }
410
411 for( const SOURCE_GATE_MAP* map : TypedItems<const SOURCE_GATE_MAP>( aComponent.GateMaps ) )
412 {
413 for( const SOURCE_GATE_PIN* pin : TypedItems<const SOURCE_GATE_PIN>( map->Pins ) )
414 {
415 for( const wxString& n : ExpandPinNumberList( pin->PinNumber ) )
416 used.insert( n );
417 }
418
419 // Before format 9000 a gate map is a pad number list, read as gate pins numbered alike
420 for( int32_t number : map->PcbSymbolPins )
421 {
422 if( number == -1 )
423 continue;
424
425 if( number == aPadNumber )
426 return pad;
427
428 used.insert( wxString::Format( wxS( "%d" ), number ) );
429 }
430 }
431
432 // Any other pad keeps its number unless a pin number has it, then takes the lowest free number
433 wxString number = pad;
434
435 for( int n = 1; used.count( number ); ++n )
436 number = wxString::Format( wxS( "%d" ), n );
437
438 return number;
439 }
440
441
443 void placeField( FOOTPRINT& aFootprint, PCB_FIELD& aField, const SOURCE_VALUE_POSITION& aPos, const FRAME& aFrame,
444 const LAYER_MAPPER& aLayers )
445 {
446 if( PCB_TEXT* text = AddText( aFootprint, aPos, aField.GetText(), aFrame, aLayers ) )
447 {
448 aField.SetAttributes( *text );
449 aField.SetPosition( text->GetPosition() );
450 aField.SetLayer( text->GetLayer() );
451 aFootprint.Remove( text );
452 delete text;
453 }
454
455 aField.SetVisible( aPos.Displayed );
456 }
457
458} // namespace
459
460
461VECTOR2I FRAME::ToKiCad( const VECTOR2D& aPoint ) const
462{
463 double x = Offset.x + ( aPoint.x - Origin.X ) * IU_PER_UNIT;
464 double y = Offset.y - ( aPoint.y - Origin.Y ) * IU_PER_UNIT;
465
466 if( std::abs( x ) > COORD_LIMIT || std::abs( y ) > COORD_LIMIT )
467 {
468 wxString msg = _( "Easy-PC coordinate (%.0f, %.0f) is outside KiCad's range" ); //format:allow
469 THROW_IO_ERROR( wxString::Format( msg, aPoint.x, aPoint.y ) );
470 }
471
472 return VECTOR2I( KiROUND( x ), KiROUND( y ) );
473}
474
475
476int FRAME::Length( int64_t aLength ) const
477{
478 return lengthOf( aLength );
479}
480
481
482EDA_ANGLE FRAME::Angle( int32_t aMilliDegrees )
483{
484 return EDA_ANGLE( AngleToDegrees( aMilliDegrees ), DEGREES_T ).Normalize();
485}
486
487
488LAYER_MAPPER::LAYER_MAPPER( const std::vector<const SOURCE_LAYER*>& aLayers ) :
489 m_layers( aLayers )
490{
491 // Copper in list order; KiCad has no room past In30.Cu
492 constexpr int maxInner = MAX_CU_LAYERS - 2;
493 int inner = 0;
494
495 for( const SOURCE_LAYER* layer : m_layers )
496 {
497 if( layer->Usage != LAYER_USAGE_ELECTRICAL )
498 continue;
499
500 if( layer->Side == LAYER_SIDE::TOP )
501 m_map[layer] = F_Cu;
502 else if( layer->Side == LAYER_SIDE::BOTTOM )
503 m_map[layer] = B_Cu;
504 else
505 m_map[layer] = static_cast<PCB_LAYER_ID>( In1_Cu + 2 * ( std::min( ++inner, maxInner ) - 1 ) );
506 }
507
508 // KiCad stacks copper in pairs
509 m_copperCount = std::min( ( inner + 3 ) / 2 * 2, MAX_CU_LAYERS );
510
511 int user = 0;
512
513 for( const SOURCE_LAYER* layer : m_layers )
514 {
515 if( layer->Usage != LAYER_USAGE_NON_ELECTRICAL )
516 continue;
517
518 PCB_LAYER_ID id = vendorTechLayer( layer );
519
520 if( id == UNDEFINED_LAYER && user <= ( User_45 - User_1 ) / 2 )
521 id = static_cast<PCB_LAYER_ID>( User_1 + 2 * user++ );
522
523 if( id != UNDEFINED_LAYER )
524 m_map[layer] = id;
525 }
526}
527
528
529std::vector<INPUT_LAYER_DESC> LAYER_MAPPER::Describe() const
530{
531 std::vector<INPUT_LAYER_DESC> descs;
532
533 for( const SOURCE_LAYER* layer : m_layers )
534 {
535 auto it = m_map.find( layer );
536
537 if( it == m_map.end() )
538 continue;
539
540 INPUT_LAYER_DESC desc;
541 desc.Name = layer->Name;
542 desc.AutoMapLayer = it->second;
543 desc.Required = layer->Usage == LAYER_USAGE_ELECTRICAL;
545 descs.push_back( desc );
546 }
547
548 return descs;
549}
550
551
552void LAYER_MAPPER::ApplyUserMapping( const std::map<wxString, PCB_LAYER_ID>& aMapping )
553{
554 for( auto& [layer, id] : m_map )
555 {
556 if( auto it = aMapping.find( layer->Name ); it != aMapping.end() )
557 id = it->second;
558 }
559}
560
561
563{
564 auto it = m_map.find( dynamic_cast<const SOURCE_LAYER*>( aLayer ) );
565 return it == m_map.end() ? UNDEFINED_LAYER : it->second;
566}
567
568
569LSET LAYER_MAPPER::PadLayers( const OBJECT* aLayer, bool aComponentPad ) const
570{
571 const SOURCE_LAYER* ref = dynamic_cast<const SOURCE_LAYER*>( aLayer );
572 bool all = !ref || ( ref->Usage == LAYER_USAGE_SET && ref->Side == LAYER_SIDE::ALL );
573 LSET set;
574
575 // No known file puts a pad on a layer span, and treating one as a single layer would drop its copper
576 if( ref && ref->Usage == LAYER_USAGE_SPAN )
577 THROW_IO_ERROR( wxString::Format( _( "Unsupported Easy-PC pad on layer span '%s'." ), ref->Name ) );
578
579 for( const SOURCE_LAYER* layer : m_layers )
580 {
581 if( layer->Usage != LAYER_USAGE_ELECTRICAL )
582 continue;
583
584 if( all || ( ref->Usage == LAYER_USAGE_SET ? layer->Side == ref->Side : layer == ref ) )
585 set.set( Map( layer ) );
586 }
587
588 // Mask and paste by the layer type flags, on the side the pad reaches
589 for( const SOURCE_LAYER* layer : m_layers )
590 {
591 const SOURCE_LAYER_TYPE* type = layer->Type;
592 PCB_LAYER_ID id = Map( layer );
593
594 if( layer->Usage != LAYER_USAGE_NON_ELECTRICAL || !type
595 || ( id != F_Mask && id != B_Mask && id != F_Paste && id != B_Paste ) )
596 {
597 continue;
598 }
599
600 bool enabled = aComponentPad ? ( all ? type->AllLayerPadInstancesEnabled : type->SurfacePadInstancesEnabled )
601 : ( all ? type->AllLayerPadsEnabled : type->SurfacePadsEnabled );
602
603 if( enabled && ( all || ref->Side == layer->Side ) )
604 set.set( id );
605 }
606
607 return set;
608}
609
610
612{
613 for( const SOURCE_LAYER* layer : m_layers )
614 {
615 if( Map( layer ) == aLayer )
616 return layer;
617 }
618
619 return nullptr;
620}
621
622
623int32_t LAYER_MAPPER::GrowByLayer( const SOURCE_LAYER* aLayer, int32_t aSize ) const
624{
625 const SOURCE_LAYER_TYPE* type = aLayer ? aLayer->Type : nullptr;
626
627 if( !type || type->OversizeType == LAYER_OVERSIZE_TYPE::NONE )
628 return aSize;
629
630 int64_t grow = type->Oversize;
631
633 grow = grow * aSize / 100;
634
635 // The caller's lengthOf refuses what KiCad cannot hold
636 return static_cast<int32_t>( std::clamp<int64_t>( aSize + grow * 2, 0, std::numeric_limits<int32_t>::max() ) );
637}
638
639
640ARC_FORM ArcForm( const POINT32& aStart, const POINT32& aEnd, int32_t aArcAngle, bool aAnticlockwise,
641 const FRAME& aFrame )
642{
643 ARC_FORM form{ aFrame.ToKiCad( aStart ), {}, aFrame.ToKiCad( aEnd ), {} };
644
645 if( aArcAngle == 0 )
646 {
647 form.Points = { form.Start, form.End };
648 return form;
649 }
650
651 VECTOR2D c = ArcCentre( aStart, aEnd, aArcAngle, aAnticlockwise );
652 double r = std::hypot( aStart.X - c.x, aStart.Y - c.y ) * IU_PER_UNIT;
653 double cx = aFrame.Offset.x + ( c.x - aFrame.Origin.X ) * IU_PER_UNIT;
654 double cy = aFrame.Offset.y - ( c.y - aFrame.Origin.Y ) * IU_PER_UNIT;
655
656 if( r <= COORD_LIMIT && std::abs( cx ) <= COORD_LIMIT && std::abs( cy ) <= COORD_LIMIT )
657 {
658 form.Mid = aFrame.ToKiCad( arcPoint( aStart, c, aArcAngle, aAnticlockwise, 0.5 ) );
659 return form;
660 }
661
662 // A nearly straight arc of huge radius is kept as points on the true arc
663 double sweep = std::abs( aArcAngle / 1000.0 * M_PI / 180.0 );
664 int count = 1;
665
666 if( r * ( 1.0 - std::cos( sweep / 2.0 ) ) >= 1.0 )
667 {
668 double step = 2.0 * std::acos( std::max( 0.0, 1.0 - ARC_HIGH_DEF / r ) );
669 count = std::max( 1, static_cast<int>( std::ceil( sweep / std::max( step, 1e-12 ) ) ) );
670 }
671
672 form.Points.push_back( form.Start );
673
674 for( int i = 1; i < count; ++i )
675 {
676 VECTOR2D p = arcPoint( aStart, c, aArcAngle, aAnticlockwise, double( i ) / count );
677 form.Points.push_back( aFrame.ToKiCad( p ) );
678 }
679
680 form.Points.push_back( form.End );
681 return form;
682}
683
684
686{
687 SHAPE_POLY_SET poly;
688 poly.AddOutline( shapeToChain( aShape, aFrame ) );
689
690 for( const OBJECT* obj : aShape.Cutouts )
691 {
692 if( const SOURCE_SHAPE* cutout = dynamic_cast<const SOURCE_SHAPE*>( obj ) )
693 poly.AddHole( shapeToChain( *cutout, aFrame ) );
694 }
695
696 return poly;
697}
698
699
700SHAPE_POLY_SET ShapeItemArea( const SOURCE_SHAPE_ITEM& aItem, const FRAME& aFrame, int aMaxError )
701{
702 SHAPE_POLY_SET area;
703 const SOURCE_DESIGN_SHAPE* shape = dynamic_cast<const SOURCE_DESIGN_SHAPE*>( aItem.Shape );
704
705 if( !shape )
706 return area;
707
708 if( shape->IsClosed() && aItem.Filled )
709 {
710 area = ShapeToPolySet( *shape, aFrame );
711
712 // Boolean operations need straight segments
713 area.ClearArcs();
714 }
715
716 const SOURCE_LINE_STYLE* style = dynamic_cast<const SOURCE_LINE_STYLE*>( aItem.Style );
717 int width = style ? lengthOf( style->Width ) : 0;
718
719 std::vector<const SOURCE_SHAPE*> contours{ shape };
720
721 for( const OBJECT* obj : shape->Cutouts )
722 contours.push_back( dynamic_cast<const SOURCE_SHAPE*>( obj ) );
723
724 for( const SOURCE_SHAPE* contour : contours )
725 {
726 for( const SPAN& span : contour&& width > 0 ? spansOf( *contour ) : std::vector<SPAN>() )
727 {
728 ARC_FORM f = ArcForm( span.Start, span.End, span.ArcAngle, span.Anticlockwise, aFrame );
729
730 // Approximate inside the source outline to preserve clearance.
731 if( f.IsArc() )
732 TransformArcToPolygon( area, f.Start, f.Mid, f.End, width, aMaxError, ERROR_INSIDE );
733
734 for( size_t i = 1; i < f.Points.size(); ++i )
735 TransformOvalToPolygon( area, f.Points[i - 1], f.Points[i], width, aMaxError, ERROR_INSIDE );
736 }
737 }
738
739 area.Simplify();
740 return area;
741}
742
743
744std::vector<PCB_SHAPE*> AddShapeItem( BOARD_ITEM_CONTAINER& aContainer, const SOURCE_SHAPE_ITEM& aItem,
745 const FRAME& aFrame, const LAYER_MAPPER& aLayers, PCB_LAYER_ID aLayer )
746{
747 std::vector<PCB_SHAPE*> out;
748 const SOURCE_DESIGN_SHAPE* shape = dynamic_cast<const SOURCE_DESIGN_SHAPE*>( aItem.Shape );
749 const SOURCE_LAYERED_SHAPE_ITEM* layered = dynamic_cast<const SOURCE_LAYERED_SHAPE_ITEM*>( &aItem );
750 PCB_LAYER_ID layer = aLayer == UNDEFINED_LAYER && layered ? aLayers.Map( layered->Layer ) : aLayer;
751
752 if( !shape || layer == UNDEFINED_LAYER )
753 return out;
754
755 const SOURCE_LINE_STYLE* style = dynamic_cast<const SOURCE_LINE_STYLE*>( aItem.Style );
756 STROKE_PARAMS stroke( style ? lengthOf( style->Width ) : 0, LINE_STYLE::SOLID );
757 std::vector<SPAN> spans = spansOf( *shape );
758 BOARD_ITEM* parent = dynamic_cast<BOARD_ITEM*>( &aContainer );
759
760 auto add = [&]( SHAPE_T aType ) -> PCB_SHAPE*
761 {
762 PCB_SHAPE* s = new PCB_SHAPE( parent, aType );
763 s->SetLayer( layer );
764 s->SetStroke( stroke );
765 aContainer.Add( s );
766 out.push_back( s );
767 return s;
768 };
769
770 if( shape->IsClosed() && aItem.Filled )
771 {
772 PCB_SHAPE* poly = add( SHAPE_T::POLY );
773 poly->SetPolyShape( ShapeToPolySet( *shape, aFrame ) );
774 poly->SetFilled( true );
775 return out;
776 }
777
778 // Two half arcs in the same direction are a circle
779 if( shape->IsClosed() && spans.size() == 2 && spans[0].ArcAngle == 180000 && spans[1].ArcAngle == 180000
780 && spans[0].Anticlockwise == spans[1].Anticlockwise )
781 {
782 VECTOR2I a = aFrame.ToKiCad( spans[0].Start );
784 circle->SetCenter( ( a + aFrame.ToKiCad( spans[1].Start ) ) / 2 );
785 circle->SetEnd( a );
786 return out;
787 }
788
789 for( const SPAN& span : spans )
790 {
791 ARC_FORM form = ArcForm( span.Start, span.End, span.ArcAngle, span.Anticlockwise, aFrame );
792
793 if( form.IsArc() )
794 add( SHAPE_T::ARC )->SetArcGeometry( form.Start, form.Mid, form.End );
795
796 for( size_t i = 1; i < form.Points.size(); ++i )
797 {
798 PCB_SHAPE* seg = add( SHAPE_T::SEGMENT );
799 seg->SetStart( form.Points[i - 1] );
800 seg->SetEnd( form.Points[i] );
801 }
802 }
803
804 return out;
805}
806
807
808std::unique_ptr<PAD> CreatePad( FOOTPRINT* aParent, const SOURCE_FREE_PAD& aPad, const SOURCE_PAD_STYLE& aStyle,
809 const FRAME& aFrame, const LAYER_MAPPER& aLayers )
810{
811 std::unique_ptr<PAD> pad = std::make_unique<PAD>( aParent );
812 int32_t size = aStyle.Size;
813 int32_t length = aStyle.Length ? aStyle.Length : aStyle.Size;
814 EASYPC::PAD_SHAPE shape = aStyle.Shape;
815 bool slot = aStyle.Drill != 0 && aStyle.DrillShape != EASYPC::PAD_SHAPE::ROUND;
816 int32_t drillX = aStyle.Drill;
817 int32_t drillY = slot ? aStyle.DrillLength : aStyle.Drill;
818
819 pad->SetNumber( aPad.Number ? wxString::Format( wxS( "%d" ), aPad.Number ) : wxString() );
820 pad->SetPosition( aFrame.ToKiCad( aPad.Position ) );
821 pad->SetOrientation( FRAME::Angle( aPad.Angle ) );
822
823 // Unplated holes use the hole for mask; plated holes use the land.
824 bool holeOnly = aStyle.Drill != 0 && drillX > size && drillY > length;
825
826 // A plated hole with no land plots on no layer; KiCad needs a land, so it gets one inside the hole and no mask
827 bool barePlatedHole = holeOnly && aStyle.Plated && aStyle.Size == 0;
828
829 if( holeOnly && ( !aStyle.Plated || barePlatedHole ) )
830 {
831 size = drillX;
832 length = drillY;
834 }
835
836 setPadShape( *pad, PADSTACK::ALL_LAYERS, shape, size, length, aStyle.Dimension3 );
837
838 LSET layers = aLayers.PadLayers( aPad.Layer, aParent != nullptr );
839
840 if( aStyle.Drill != 0 )
841 {
842 pad->SetAttribute( aStyle.Plated ? PAD_ATTRIB::PTH : PAD_ATTRIB::NPTH );
843 pad->SetDrillShape( slot ? PAD_DRILL_SHAPE::OBLONG : PAD_DRILL_SHAPE::CIRCLE );
844 pad->SetDrillSize( VECTOR2I( lengthOf( drillX ), lengthOf( drillY ) ) );
845 }
846 else
847 {
848 pad->SetAttribute( PAD_ATTRIB::SMD );
849 }
850
851 if( barePlatedHole )
852 layers &= LSET::AllCuMask();
853
854 pad->SetLayerSet( layers );
855
856 if( aStyle.Exceptions )
857 applyPadStyleExceptions( aParent, *pad, aStyle, aLayers );
858
859 return pad;
860}
861
862
863bool ApplyTextPosition( PCB_TEXT& aText, const SOURCE_TEXT_POSITION& aPosition, const FRAME& aFrame,
864 const LAYER_MAPPER& aLayers )
865{
866 PCB_LAYER_ID layer = aLayers.Map( aPosition.Layer );
867
868 if( layer == UNDEFINED_LAYER )
869 return false;
870
871 const SOURCE_TEXT_STYLE* style = dynamic_cast<const SOURCE_TEXT_STYLE*>( aPosition.TextStyle );
872 int height = lengthOf( style ? style->Height : 0 );
873 EDA_ANGLE angle = FRAME::Angle( NormalizeAngle( aPosition.Rotation ) );
874 wxString text = aText.GetText();
875 std::optional<TEXT_METRICS> metrics;
876
877 if( style )
878 metrics.emplace( *style );
879
880 bool measurable = metrics && metrics->CanMeasure();
881
882 text.Replace( wxS( "\r" ), wxEmptyString );
883
884 // Stored text marks overbars with __; KiCad draws and measures its own markup
885 wxString shown = ToKiCadMarkup( text );
886 aText.SetText( shown );
887
888 int glyph = static_cast<int>( int64_t( height ) * 3 / 4 );
889 int glyphWidth = glyph;
890
891 aText.SetLayer( layer );
892 aText.SetTextThickness( style ? lengthOf( style->LineWidth ) : 0 );
893 aText.SetKeepUpright( false );
894
895 // Easy-PC advances every character by its pitch while KiCad's font is proportional, so the glyphs are
896 // widened until KiCad's advance over the longest line equals the Easy-PC line width
897 if( measurable )
898 {
899 int32_t widest = 0;
900 wxString widestLine;
901
902 for( const wxString& line : wxSplit( text, '\n', '\0' ) )
903 {
904 std::string bytes = TEXT_METRICS::Encode( line );
905 int32_t width = bytes.empty() ? 0 : metrics->RunWidth( bytes, 0, bytes.size() );
906
907 if( width > widest )
908 {
909 widest = width;
910 widestLine = line;
911 }
912 }
913
914 int advance = widest > 0 ? KIFONT::FONT::GetFont()
915 ->StringBoundaryLimits( ToKiCadMarkup( widestLine ),
916 VECTOR2I( glyph, glyph ), aText.GetTextThickness(),
917 false, false, KIFONT::METRICS::Default() )
918 .x
919 : 0;
920
921 if( advance > 0 )
922 glyphWidth = KiROUND( static_cast<double>( glyph ) * lengthOf( widest ) / advance );
923 }
924
925 aText.SetTextSize( VECTOR2I( glyphWidth, glyph ) );
926
927 switch( aPosition.Alignment )
928 {
931 default: aText.SetHorizJustify( GR_TEXT_H_ALIGN_LEFT ); break;
932 }
933
934 // The first line hangs from a top-justified anchor, as the stored anchor is the first baseline
936
937 // Lay the text out unrotated at the origin to measure where KiCad's own font puts it
938 PCB_TEXT probe( static_cast<BOARD_ITEM*>( nullptr ) );
939 probe.SetTextSize( aText.GetTextSize() );
940 probe.SetTextThickness( aText.GetTextThickness() );
941 probe.SetHorizJustify( aText.GetHorizJustify() );
943 probe.SetTextPos( VECTOR2I( 0, 0 ) );
944
945 wxString firstLine = text.BeforeFirst( '\n' );
946
947 if( text.Contains( wxS( "\n" ) ) && style )
948 {
949 probe.SetText( shown );
950 probe.SetLineSpacing( 1.0 );
951 aText.SetLineSpacing( height * style->InterlineHeightPercent / 100.0 / probe.GetInterline( nullptr ) );
952 }
953
954 // Capital baseline of the first line, from a capital without descenders
955 probe.SetText( wxS( "H" ) );
956 int baseline = strokeBox( probe ).GetBottom();
957
958 probe.SetText( firstLine.IsEmpty() ? wxString( wxS( " " ) ) : ToKiCadMarkup( firstLine ) );
959 BOX2I ink = strokeBox( probe );
960 int dx = 0;
961
962 // The first glyph starts at its line cell's left edge; KiCad's font adds its own side bearing.
963 // Without the Easy-PC width, KiCad's own justification stands and only the ink's bearing is removed
964 if( measurable )
965 {
966 std::string bytes = TEXT_METRICS::Encode( firstLine );
967 int32_t width = metrics->RunWidth( bytes, 0, bytes.size() );
968 int cellLeft = 0;
969
970 if( aPosition.Alignment == TEXT_ALIGN_RIGHT )
971 cellLeft = -lengthOf( width );
972 else if( aPosition.Alignment == TEXT_ALIGN_CENTRE )
973 cellLeft = -lengthOf( width / 2 );
974
975 dx = cellLeft - ink.GetLeft();
976 }
977 else if( aPosition.Alignment == TEXT_ALIGN_RIGHT )
978 {
979 dx = -ink.GetRight();
980 }
981 else if( aPosition.Alignment == TEXT_ALIGN_CENTRE )
982 {
983 dx = -ink.Centre().x;
984 }
985 else
986 {
987 dx = -ink.GetLeft();
988 }
989
990 // Capitals sit 3/16 of the height above the anchor
991 VECTOR2I shift( aPosition.Mirrored ? -dx : dx, static_cast<int>( -int64_t( height ) * 3 / 16 ) - baseline );
992
993 RotatePoint( shift, angle );
994
995 aText.SetTextAngle( angle );
996 aText.SetMirrored( aPosition.Mirrored );
997 aText.SetPosition( aFrame.ToKiCad( aPosition.Position ) + shift );
998 return true;
999}
1000
1001
1002PCB_TEXT* AddText( BOARD_ITEM_CONTAINER& aContainer, const SOURCE_TEXT_POSITION& aPosition, const wxString& aText,
1003 const FRAME& aFrame, const LAYER_MAPPER& aLayers )
1004{
1005 std::unique_ptr<PCB_TEXT> text = std::make_unique<PCB_TEXT>( dynamic_cast<BOARD_ITEM*>( &aContainer ) );
1006 text->SetText( aText );
1007
1008 if( !ApplyTextPosition( *text, aPosition, aFrame, aLayers ) )
1009 return nullptr;
1010
1011 aContainer.Add( text.get() );
1012 return text.release();
1013}
1014
1015
1016std::unique_ptr<FOOTPRINT> ConvertFootprint( const SOURCE_SYMBOL& aSymbol, const LAYER_MAPPER& aLayers,
1017 const LIB_ID& aId, const SOURCE_PCB_COMPONENT* aComponent,
1018 std::map<const SOURCE_FREE_PAD*, PAD*>* aPadMap )
1019{
1020 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( nullptr );
1021 const FRAME frame{ POINT32{ aSymbol.OriginX, aSymbol.OriginY } };
1022
1023 footprint->SetFPID( aId );
1024 footprint->Reference().SetText( wxS( "REF**" ) );
1025 footprint->Value().SetText( aComponent ? aComponent->Package : aSymbol.Name );
1026
1027 for( const SOURCE_SHAPE_ITEM* item : TypedItems<const SOURCE_SHAPE_ITEM>( aSymbol.Shapes ) )
1028 AddShapeItem( *footprint, *item, frame, aLayers );
1029
1031 AddText( *footprint, *text, text->Text, frame, aLayers );
1032
1034 {
1035 const SOURCE_PAD_STYLE* style = dynamic_cast<const SOURCE_PAD_STYLE*>( pad->Style );
1036
1037 if( !style )
1038 {
1040 wxString::Format( _( "Easy-PC symbol '%s' pad %d has no pad style" ), aSymbol.Name, pad->Number ) );
1041 }
1042
1043 std::unique_ptr<PAD> kpad = CreatePad( footprint.get(), *pad, *style, frame, aLayers );
1044 wxString number =
1045 aComponent ? PcbPadNumber( *aComponent, pad->Number ) : wxString::Format( wxS( "%d" ), pad->Number );
1046
1047 kpad->SetNumber( number );
1048
1049 for( const SOURCE_VALUE_POSITION* pos : TypedItems<const SOURCE_VALUE_POSITION>( pad->ValuePositions ) )
1050 {
1051 if( pos->Displayed && ( pos->Types & VALUE_PIN_NUMBER ) )
1052 AddText( *footprint, *pos, number, frame, aLayers );
1053 }
1054
1055 if( aPadMap )
1056 ( *aPadMap )[pad] = kpad.get();
1057
1058 footprint->Add( kpad.release(), ADD_MODE::APPEND );
1059 }
1060
1061 const SOURCE_VALUE_POSITION* refPos = nullptr;
1062 const SOURCE_VALUE_POSITION* valuePos = nullptr;
1063
1065 {
1066 if( !pos->Displayed )
1067 continue;
1068
1069 if( !refPos && ( pos->Types & VALUE_REFERENCE_NAME ) )
1070 refPos = pos;
1071 else if( !valuePos && ( pos->Types & ( VALUE_COMPONENT_NAME | VALUE_VALUES ) ) )
1072 valuePos = pos;
1073 }
1074
1075 if( refPos )
1076 placeField( *footprint, footprint->Reference(), *refPos, frame, aLayers );
1077
1078 if( valuePos )
1079 placeField( *footprint, footprint->Value(), *valuePos, frame, aLayers );
1080 else
1081 footprint->Value().SetVisible( false );
1082
1083 return footprint;
1084}
1085
1086} // namespace EASYPC_PCB
const char * name
@ ERROR_INSIDE
constexpr int ARC_HIGH_DEF
Definition base_units.h:144
double square(double x)
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
BASE_SET & reset(size_t pos)
Definition base_set.h:153
BASE_SET & set(size_t pos)
Definition base_set.h:126
Abstract interface for BOARD_ITEMs capable of storing other items inside.
virtual void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false)=0
Adds an item to the container.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:374
constexpr Vec Centre() const
Definition box2.h:94
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr coord_type GetRight() const
Definition box2.h:214
static std::string Encode(const wxString &aText)
The CP1252 bytes of aText; characters CP1252 lacks become 0.
Layer mapping for one layer table, copper in stack order and other layers by their type.
LSET PadLayers(const EASYPC::OBJECT *aLayer, bool aComponentPad) const
The copper aLayer (a layer or a set) covers, with the mask and paste layers whose type plots such pad...
std::map< const EASYPC::SOURCE_LAYER *, PCB_LAYER_ID > m_map
int32_t GrowByLayer(const EASYPC::SOURCE_LAYER *aLayer, int32_t aSize) const
aSize grown on each side by aLayer's type oversize, fixed or a percentage of the size
std::vector< INPUT_LAYER_DESC > Describe() const
std::vector< const EASYPC::SOURCE_LAYER * > m_layers
PCB_LAYER_ID Map(const EASYPC::OBJECT *aLayer) const
UNDEFINED_LAYER when the native layer has no KiCad layer.
const EASYPC::SOURCE_LAYER * Native(PCB_LAYER_ID aLayer) const
void ApplyUserMapping(const std::map< wxString, PCB_LAYER_ID > &aMapping)
LAYER_MAPPER(const std::vector< const EASYPC::SOURCE_LAYER * > &aLayers)
EDA_ANGLE Normalize()
Definition eda_angle.h:228
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:142
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:556
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:394
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:354
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:378
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:239
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
void SetLineSpacing(double aLineSpacing)
Definition eda_text.cpp:504
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, const BOX2I &aBBox=BOX2I(), const EDA_ANGLE &aAngle=ANGLE_0) const
Build a list of segments (SHAPE_SEGMENT) to describe a text shape.
void SetKeepUpright(bool aKeepUpright)
Definition eda_text.cpp:386
int GetInterline(const RENDER_SETTINGS *aSettings) const
Return the distance between two lines of text.
Definition eda_text.cpp:747
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:370
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Adds an item to the container.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:143
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic, const METRICS &aFontMetrics) const
Compute the boundary limits of aText (the bounding box of all shapes).
Definition font.cpp:439
static const METRICS & Default()
Definition font.cpp:48
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
static LSET AllNonCuMask()
Return a mask holding all layer minus CU layers.
Definition lset.cpp:623
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
void SetMode(MODE aMode)
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
@ CUSTOM
Shapes can be defined on arbitrary layers.
Definition padstack.h:172
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
Definition pad.h:61
void SetAnchorPadShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the shape of the anchor pad for custom shaped pads.
Definition pad.h:249
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:557
void AddPrimitivePoly(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPoly, int aThickness, bool aFilled)
Has meaning only for custom shape pads.
Definition pad.cpp:3645
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool aIgnoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition pad.cpp:3046
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:196
void SetChamferRectRatio(PCB_LAYER_ID aLayer, double aChamferScale)
Has meaning only for chamfered rectangular pads.
Definition pad.cpp:1232
const PADSTACK & Padstack() const
Definition pad.h:331
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.cpp:265
void SetChamferPositions(PCB_LAYER_ID aLayer, int aPositions)
Has meaning only for chamfered rectangular pads.
Definition pad.h:847
void SetLayerSet(const LSET &aLayers) override
Definition pad.cpp:1968
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition pad.cpp:1194
void SetEnd(const VECTOR2I &aEnd) override
void SetPolyShape(const SHAPE_POLY_SET &aShape) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
void SetStroke(const STROKE_PARAMS &aStroke) override
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
Definition pcb_text.cpp:512
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
Definition pcb_text.cpp:484
void SetPosition(const VECTOR2I &aPos) override
Definition pcb_text.h:102
int GetTextThickness() const override
Definition pcb_text.cpp:497
void SetTextAngle(const EDA_ANGLE &aAngle) override
Definition pcb_text.cpp:572
VECTOR2I GetTextSize() const override
Definition pcb_text.cpp:470
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
An abstract shape on 2D plane.
Definition shape.h:124
Simple container to manage line stroke parameters.
void TransformArcToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc)
Convert arc to multiple straight segments.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
Placed instances and connectivity: component, symbol and pad instances, nets, nodes,...
Symbols, components and gates, embedded in designs or the single object of a library item stream.
::PAD_SHAPE KI_PAD_SHAPE
Easy-PC / DesignSpark items to KiCad board items, shared by the board builder and the ....
Easy-PC's text measurement, so text lands where Easy-PC draws it.
#define _(s)
@ DEGREES_T
Definition eda_angle.h:30
SHAPE_T
Definition eda_shape.h:54
@ SEGMENT
Definition eda_shape.h:56
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define MAX_CU_LAYERS
Definition layer_ids.h:172
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
@ User_45
Definition layer_ids.h:164
@ F_Paste
Definition layer_ids.h:100
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_SilkS
Definition layer_ids.h:96
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ In1_Cu
Definition layer_ids.h:62
@ User_1
Definition layer_ids.h:120
@ B_SilkS
Definition layer_ids.h:97
@ F_Cu
Definition layer_ids.h:60
bool ApplyTextPosition(PCB_TEXT &aText, const SOURCE_TEXT_POSITION &aPosition, const FRAME &aFrame, const LAYER_MAPPER &aLayers)
Place and size a text from its stored position and style; false when its layer has no KiCad layer.
std::unique_ptr< FOOTPRINT > ConvertFootprint(const SOURCE_SYMBOL &aSymbol, const LAYER_MAPPER &aLayers, const LIB_ID &aId, const SOURCE_PCB_COMPONENT *aComponent, std::map< const SOURCE_FREE_PAD *, PAD * > *aPadMap)
A footprint in symbol coordinates.
SHAPE_POLY_SET ShapeToPolySet(const SOURCE_DESIGN_SHAPE &aShape, const FRAME &aFrame)
A closed shape and its cutouts as an outline with holes.
std::unique_ptr< PAD > CreatePad(FOOTPRINT *aParent, const SOURCE_FREE_PAD &aPad, const SOURCE_PAD_STYLE &aStyle, const FRAME &aFrame, const LAYER_MAPPER &aLayers)
A pad with its style's per-layer exceptions; a mask or paste exception becomes a separate opening on ...
PCB_TEXT * AddText(BOARD_ITEM_CONTAINER &aContainer, const SOURCE_TEXT_POSITION &aPosition, const wxString &aText, const FRAME &aFrame, const LAYER_MAPPER &aLayers)
ARC_FORM ArcForm(const POINT32 &aStart, const POINT32 &aEnd, int32_t aArcAngle, bool aAnticlockwise, const FRAME &aFrame)
std::vector< PCB_SHAPE * > AddShapeItem(BOARD_ITEM_CONTAINER &aContainer, const SOURCE_SHAPE_ITEM &aItem, const FRAME &aFrame, const LAYER_MAPPER &aLayers, PCB_LAYER_ID aLayer)
Add a shape item as one filled polygon, a circle, or one shape per span; aLayer overrides the item's ...
SHAPE_POLY_SET ShapeItemArea(const SOURCE_SHAPE_ITEM &aItem, const FRAME &aFrame, int aMaxError)
The copper a shape item plots: its filled region and every span stroked at the line width with round ...
std::vector< wxString > ExpandPinNumberList(const wxString &aList, wxString *aDisplay)
Expand a gate pin's component pin list by Easy-PC's pin list syntax: items separated by ,...
constexpr double COORD_LIMIT
Half of KiCad's integer range, so shape code rotating or adding coordinates cannot overflow.
@ LAYER_USAGE_SET
pseudo layer [All], [Top] or [Bottom]
std::vector< T * > TypedItems(const OBJECT *aList)
The items of ListItems that are a T, in order.
constexpr int32_t NormalizeAngle(int32_t aAngle)
Wrap an angle into [0, ANGLE_FULL_TURN)
wxString ToKiCadMarkup(const wxString &aText)
A displayed string in KiCad's markup.
constexpr double AngleToDegrees(int32_t aAngle)
PAD_SHAPE
Pad style shape, also the drill and exception shape.
constexpr int64_t NM_PER_DSU
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ SH_SEGMENT
line segment
Definition shape.h:44
Root of every deserialized object.
A point read as two int32 values.
A pad of a symbol definition.
One gate's terminals to footprint pads.
Layer type names determine silk, mask and paste roles.
SOURCE_LAYER_TYPE * Type
null for the layer sets
wxString TypeName
below v3000 the type is stored by name
OBJECT * Exceptions
pad style exception list
int32_t Length
Y extent for shapes that have one.
The package half of a component.
OBJECT * GateMaps
one per schematic gate in order
int32_t ArcAngle
swept angle, 0 for a straight span
bool IsClosed() const
The last vertex links back to the first (formats 1 and 2) or the closed byte is set (format 3)
std::vector< OBJECT * > Segments
the vertex list as read
Footprints and schematic symbols alike.
OBJECT * Shapes
free copper list
OBJECT * Texts
free text list
OBJECT * Pads
free pad list
int32_t Height
the accessor is GetWidth but it is the text height
A span as KiCad can hold it: a true arc, or a polyline that is the two ends of a straight span or poi...
std::vector< VECTOR2I > Points
Native to KiCad coordinates: scale by 100 nm, flip Y and move the native origin to the KiCad offset.
static EDA_ANGLE Angle(int32_t aMilliDegrees)
VECTOR2I ToKiCad(int32_t aX, int32_t aY) const
int Length(int64_t aLength) const
EASYPC::POINT32 Origin
Describes an imported layer and how it could be mapped to KiCad Layers.
PCB_LAYER_ID AutoMapLayer
Best guess as to what the equivalent KiCad layer might be.
bool Required
Should we require the layer to be assigned?
LSET PermittedLayers
KiCad layers that the imported layer can be mapped onto.
wxString Name
Imported layer name as displayed in original application.
KIBIS_PIN * pin
const SHAPE_LINE_CHAIN chain
int radius
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_TOP
#define M_PI
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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707