KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_dimension.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Jean-Pierre Charras, [email protected]
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2012 Wayne Stambaugh <[email protected]>
7 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <bitmaps.h>
28#include <pcb_edit_frame.h>
29#include <base_units.h>
31#include <font/font.h>
32#include <pcb_dimension.h>
33#include <pcb_text.h>
39#include <trigo.h>
40
41
42static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
43
44
46 PCB_TEXT( aParent, aType ),
47 m_overrideTextEnabled( false ),
48 m_units( EDA_UNITS::INCHES ),
49 m_autoUnits( false ),
50 m_unitsFormat( DIM_UNITS_FORMAT::BARE_SUFFIX ),
51 m_precision( DIM_PRECISION::X_XXXX ),
52 m_suppressZeroes( false ),
53 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
54 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
55 m_extensionOffset( 0 ),
56 m_textPosition( DIM_TEXT_POSITION::OUTSIDE ),
57 m_keepTextAligned( true ),
58 m_measuredValue( 0 ),
59 m_inClearRenderCache( false )
60{
62}
63
64
66{
68
69 switch( m_unitsFormat )
70 {
71 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
72 break;
73
74 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
76 break;
77
78 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
79 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
80 break;
81 }
82
83 text.Prepend( m_prefix );
84 text.Append( m_suffix );
85
86 SetText( text );
87}
88
89
91{
93
94 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
95 // have changed and we may need to update the dimension text
96
98 {
100 updateText();
101 m_inClearRenderCache = false;
102 }
103}
104
105
106template<typename ShapeType>
107void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
108{
109 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
110}
111
112
114{
115 struct lconv* lc = localeconv();
116 wxChar sep = lc->decimal_point[0];
117
118 int val = GetMeasuredValue();
119 int precision = static_cast<int>( m_precision );
120 wxString text;
121
122 if( precision >= 6 )
123 {
124 switch( m_units )
125 {
126 case EDA_UNITS::INCHES: precision = precision - 4; break;
127 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
128 case EDA_UNITS::MILLIMETRES: precision = precision - 5; break;
129 default: precision = precision - 4; break;
130 }
131 }
132
133 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
134
135 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
136
137 if( m_suppressZeroes )
138 {
139 while( text.Last() == '0' )
140 {
141 text.RemoveLast();
142
143 if( text.Last() == '.' || text.Last() == sep )
144 {
145 text.RemoveLast();
146 break;
147 }
148 }
149 }
150
151 return text;
152}
153
154
155void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
156{
157 m_prefix = aPrefix;
158}
159
160
161void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
162{
163 m_suffix = aSuffix;
164}
165
166
168{
169 m_units = aUnits;
170}
171
172
174{
175 if( m_autoUnits )
176 {
177 return DIM_UNITS_MODE::AUTOMATIC;
178 }
179 else
180 {
181 switch( m_units )
182 {
183 default:
184 case EDA_UNITS::INCHES: return DIM_UNITS_MODE::INCHES;
185 case EDA_UNITS::MILLIMETRES: return DIM_UNITS_MODE::MILLIMETRES;
186 case EDA_UNITS::MILS: return DIM_UNITS_MODE::MILS;
187 }
188 }
189}
190
191
193{
194 switch( aMode )
195 {
196 case DIM_UNITS_MODE::INCHES:
197 m_autoUnits = false;
198 m_units = EDA_UNITS::INCHES;
199 break;
200
201 case DIM_UNITS_MODE::MILS:
202 m_autoUnits = false;
203 m_units = EDA_UNITS::MILS;
204 break;
205
206 case DIM_UNITS_MODE::MILLIMETRES:
207 m_autoUnits = false;
208 m_units = EDA_UNITS::MILLIMETRES;
209 break;
210
211 case DIM_UNITS_MODE::AUTOMATIC:
212 m_autoUnits = true;
213 m_units = GetBoard() ? GetBoard()->GetUserUnits() : EDA_UNITS::MILLIMETRES;
214 break;
215 }
216}
217
218
220{
221 PCB_TEXT::Offset( offset );
222
223 m_start += offset;
224 m_end += offset;
225
226 Update();
227}
228
229
230void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
231{
232 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
233
234 newAngle.Normalize();
235
236 SetTextAngle( newAngle );
237
238 VECTOR2I pt = GetTextPos();
239 RotatePoint( pt, aRotCentre, aAngle );
240 SetTextPos( pt );
241
242 RotatePoint( m_start, aRotCentre, aAngle );
243 RotatePoint( m_end, aRotCentre, aAngle );
244
245 Update();
246}
247
248
249void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
250{
251 Mirror( aCentre );
252
253 SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
254}
255
256
257void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight )
258{
259 int axis = aMirrorLeftRight ? axis_pos.x : axis_pos.y;
260 VECTOR2I newPos = GetTextPos();
261
262#define INVERT( pos ) ( ( pos ) = axis - ( ( pos ) - axis ) )
263 if( aMirrorLeftRight )
264 INVERT( newPos.x );
265 else
266 INVERT( newPos.y );
267
268 SetTextPos( newPos );
269
270 // invert angle
272
273 if( aMirrorLeftRight )
274 {
275 INVERT( m_start.x );
276 INVERT( m_end.x );
277 }
278 else
279 {
280 INVERT( m_start.y );
281 INVERT( m_end.y );
282 }
283
284 if( ( GetLayerSet() & LSET::SideSpecificMask() ).any() )
286
287 Update();
288}
289
290
292 std::vector<MSG_PANEL_ITEM>& aList )
293{
294 // for now, display only the text within the DIMENSION using class PCB_TEXT.
295 wxString msg;
296
297 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
298
299 // Don't use GetShownText(); we want to see the variable references here
300 aList.emplace_back( _( "Dimension" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
301
302 aList.emplace_back( _( "Prefix" ), GetPrefix() );
303
305 {
306 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
307 }
308 else
309 {
310 aList.emplace_back( _( "Value" ), GetValueText() );
311
312 switch( GetPrecision() )
313 {
314 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
315 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
316 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
317 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
318 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
319 }
320
321 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
322 }
323
324 aList.emplace_back( _( "Suffix" ), GetSuffix() );
325
326 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
327 // in frame's units.
328 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MILLIMETRES );
329 unitsProvider.SetUserUnits( GetUnits() );
330
331 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
332
333 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
334 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
335 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
336 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
337
338 ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
339
340 if( Type() == PCB_DIM_CENTER_T )
341 {
342 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
343 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
344 aFrame->MessageTextFromValue( startCoord.x ),
345 aFrame->MessageTextFromValue( startCoord.y ) );
346
347 aList.emplace_back( start, wxEmptyString );
348 }
349 else
350 {
351 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
352 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
353 aFrame->MessageTextFromValue( startCoord.x ),
354 aFrame->MessageTextFromValue( startCoord.y ) );
355 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
356 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
357 aFrame->MessageTextFromValue( endCoord.x ),
358 aFrame->MessageTextFromValue( endCoord.y ) );
359
360 aList.emplace_back( start, end );
361 }
362
363 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
364 aList.emplace_back( _( "Status" ), _( "Locked" ) );
365
366 aList.emplace_back( _( "Layer" ), GetLayerName() );
367}
368
369
370std::shared_ptr<SHAPE> PCB_DIMENSION_BASE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
371{
372 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
373
374 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
375
376 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
377 effectiveShape->AddShape( shape->Clone() );
378
379 return effectiveShape;
380}
381
382
383bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
384{
385 if( TextHitTest( aPosition ) )
386 return true;
387
388 int dist_max = aAccuracy + ( m_lineThickness / 2 );
389
390 // Locate SEGMENTS
391
392 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
393 {
394 if( shape->Collide( aPosition, dist_max ) )
395 return true;
396 }
397
398 return false;
399}
400
401
402bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
403{
404 BOX2I arect = aRect;
405 arect.Inflate( aAccuracy );
406
407 BOX2I rect = GetBoundingBox();
408
409 if( aAccuracy )
410 rect.Inflate( aAccuracy );
411
412 if( aContained )
413 return arect.Contains( rect );
414
415 return arect.Intersects( rect );
416}
417
418
420{
421 BOX2I bBox;
422 int xmin, xmax, ymin, ymax;
423
424 bBox = GetTextBox();
425 xmin = bBox.GetX();
426 xmax = bBox.GetRight();
427 ymin = bBox.GetY();
428 ymax = bBox.GetBottom();
429
430 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
431 {
432 BOX2I shapeBox = shape->BBox();
433 shapeBox.Inflate( m_lineThickness / 2 );
434
435 xmin = std::min( xmin, shapeBox.GetOrigin().x );
436 xmax = std::max( xmax, shapeBox.GetEnd().x );
437 ymin = std::min( ymin, shapeBox.GetOrigin().y );
438 ymax = std::max( ymax, shapeBox.GetEnd().y );
439 }
440
441 bBox.SetX( xmin );
442 bBox.SetY( ymin );
443 bBox.SetWidth( xmax - xmin + 1 );
444 bBox.SetHeight( ymax - ymin + 1 );
445
446 bBox.Normalize();
447
448 return bBox;
449}
450
451
453{
454 return wxString::Format( _( "Dimension '%s' on %s" ),
456 GetLayerName() );
457}
458
459
460
462{
464 VECTOR2I( GetBoundingBox().GetSize() ) );
465 dimBBox.Merge( PCB_TEXT::ViewBBox() );
466
467 return dimBBox;
468}
469
470
472 bool aStart )
473{
474 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
475 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
476
477 if( aPoly.Contains( start ) )
478 return std::nullopt;
479
480 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
481 {
482 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
483 {
484 if( ( *intersection - start ).SquaredEuclideanNorm() <
485 ( endpoint - start ).SquaredEuclideanNorm() )
486 endpoint = *intersection;
487 }
488 }
489
490 if( start == endpoint )
491 return std::nullopt;
492
493 return OPT_VECTOR2I( endpoint );
494}
495
496
498{
499 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
500 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
501
502 if( aCircle.Contains( start ) )
503 return std::nullopt;
504
505 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
506
507 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
508 {
509 if( ( intersection - start ).SquaredEuclideanNorm() <
510 ( endpoint - start ).SquaredEuclideanNorm() )
511 endpoint = intersection;
512 }
513
514 if( start == endpoint )
515 return std::nullopt;
516
517 return OPT_VECTOR2I( endpoint );
518}
519
520
522 int aClearance, int aError, ERROR_LOC aErrorLoc,
523 bool aIgnoreLineWidth ) const
524{
525 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
526
527 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
528 {
529 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
530 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
531
532 if( circle )
533 {
534 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
535 circle->GetRadius() + m_lineThickness / 2 + aClearance,
536 aError, aErrorLoc );
537 }
538 else if( seg )
539 {
540 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
541 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
542 }
543 else
544 {
545 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
546 }
547 }
548}
549
550
552 PCB_DIMENSION_BASE( aParent, aType ),
553 m_height( 0 )
554{
555 // To preserve look of old dimensions, initialize extension height based on default arrow length
556 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
557}
558
559
561{
562 return new PCB_DIM_ALIGNED( *this );
563}
564
565
567{
568 wxASSERT( aImage->Type() == Type() );
569
570 m_shapes.clear();
571 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
572
573 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
574
575 Update();
576}
577
578
579void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight )
580{
581 PCB_DIMENSION_BASE::Mirror( axis_pos, aMirrorLeftRight );
582
584}
585
586
588{
589 return BITMAPS::add_aligned_dimension;
590}
591
592
593void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
594{
595 VECTOR2D height( aCrossbarStart - GetStart() );
596 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
597
598 if( height.Cross( crossBar ) > 0 )
599 m_height = -height.EuclideanNorm();
600 else
601 m_height = height.EuclideanNorm();
602
603 Update();
604}
605
606
608{
609 m_shapes.clear();
610
611 VECTOR2I dimension( m_end - m_start );
612
613 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
614
615 VECTOR2I extension;
616
617 if( m_height > 0 )
618 extension = VECTOR2I( -dimension.y, dimension.x );
619 else
620 extension = VECTOR2I( dimension.y, -dimension.x );
621
622 // Add extension lines
623 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
624
625 VECTOR2I extStart( m_start );
626 extStart += extension.Resize( m_extensionOffset );
627
628 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
629
630 extStart = VECTOR2I( m_end );
631 extStart += extension.Resize( m_extensionOffset );
632
633 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
634
635 // Add crossbar
636 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
637 m_crossBarStart = m_start + crossBarDistance;
638 m_crossBarEnd = m_end + crossBarDistance;
639
640 // Update text after calculating crossbar position but before adding crossbar lines
641 updateText();
642
643 // Now that we have the text updated, we can determine how to draw the crossbar.
644 // First we need to create an appropriate bounding polygon to collide with
646
647 SHAPE_POLY_SET polyBox;
648 polyBox.NewOutline();
649 polyBox.Append( textBox.GetOrigin() );
650 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
651 polyBox.Append( textBox.GetEnd() );
652 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
653 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
654
655 // The ideal crossbar, if the text doesn't collide
656 SEG crossbar( m_crossBarStart, m_crossBarEnd );
657
658 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
659 bool containsA = polyBox.Contains( crossbar.A );
660 bool containsB = polyBox.Contains( crossbar.B );
661
662 OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
663 OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
664
665 if( endpointA )
666 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
667
668 if( endpointB )
669 m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
670
671 if( !containsA && !containsB && !endpointA && !endpointB )
672 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
673
674 // Add arrows
675 VECTOR2I arrowEndPos( m_arrowLength, 0 );
676 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
677 RotatePoint( arrowEndPos, -EDA_ANGLE( dimension ) + s_arrowAngle );
678 RotatePoint( arrowEndNeg, -EDA_ANGLE( dimension ) - s_arrowAngle );
679
680 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndPos ) );
681 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndNeg ) );
682 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndPos ) );
683 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) );
684}
685
686
688{
689 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
690
691 if( m_textPosition == DIM_TEXT_POSITION::OUTSIDE )
692 {
693 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
694 EDA_ANGLE rotation;
695
696 if( crossbarCenter.x == 0 )
697 rotation = ANGLE_90 * sign( -crossbarCenter.y );
698 else if( crossbarCenter.x < 0 )
699 rotation = -ANGLE_90;
700 else
701 rotation = ANGLE_90;
702
703 VECTOR2I textOffset = crossbarCenter;
704 RotatePoint( textOffset, rotation );
705 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
706
707 SetTextPos( m_crossBarStart + textOffset );
708 }
709 else if( m_textPosition == DIM_TEXT_POSITION::INLINE )
710 {
711 SetTextPos( m_crossBarStart + crossbarCenter );
712 }
713
715 {
716 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
717 textAngle.Normalize();
718
719 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
720 textAngle -= ANGLE_180;
721
722 SetTextAngle( textAngle );
723 }
724
726}
727
728
729void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
730{
732
733 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
734 // in frame's units.
735 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MILLIMETRES );
736 unitsProvider.SetUserUnits( GetUnits() );
737
738 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
739}
740
741
744{
745 // To preserve look of old dimensions, initialize extension height based on default arrow length
746 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
748}
749
750
752{
753 return new PCB_DIM_ORTHOGONAL( *this );
754}
755
756
758{
759 wxASSERT( aImage->Type() == Type() );
760
761 m_shapes.clear();
762 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
763
764 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
765 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
766
767 Update();
768}
769
770
772{
773 return BITMAPS::add_orthogonal_dimension;
774}
775
776
778{
779 m_shapes.clear();
780
782 m_end.y - m_start.y );
784
785 VECTOR2I extension;
786
788 extension = VECTOR2I( 0, m_height );
789 else
790 extension = VECTOR2I( m_height, 0 );
791
792 // Add first extension line
793 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
794
795 VECTOR2I extStart( m_start );
796 extStart += extension.Resize( m_extensionOffset );
797
798 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
799
800 // Add crossbar
801 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
802 m_crossBarStart = m_start + crossBarDistance;
803
806 else
808
809 // Add second extension line (m_end to crossbar end)
811 extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y );
812 else
813 extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 );
814
815 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
816
817 extStart = VECTOR2I( m_crossBarEnd );
818 extStart -= extension.Resize( m_extensionHeight );
819
820 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
821
822 // Update text after calculating crossbar position but before adding crossbar lines
823 updateText();
824
825 // Now that we have the text updated, we can determine how to draw the crossbar.
826 // First we need to create an appropriate bounding polygon to collide with
828
829 SHAPE_POLY_SET polyBox;
830 polyBox.NewOutline();
831 polyBox.Append( textBox.GetOrigin() );
832 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
833 polyBox.Append( textBox.GetEnd() );
834 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
835 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
836
837 // The ideal crossbar, if the text doesn't collide
838 SEG crossbar( m_crossBarStart, m_crossBarEnd );
839
840 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
841 bool containsA = polyBox.Contains( crossbar.A );
842 bool containsB = polyBox.Contains( crossbar.B );
843
844 OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
845 OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
846
847 if( endpointA )
848 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
849
850 if( endpointB )
851 m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
852
853 if( !containsA && !containsB && !endpointA && !endpointB )
854 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
855
856 // Add arrows
857 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
858 VECTOR2I arrowEndPos( m_arrowLength, 0 );
859 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
860 RotatePoint( arrowEndPos, -crossBarAngle + s_arrowAngle );
861 RotatePoint( arrowEndNeg, -crossBarAngle - s_arrowAngle );
862
863 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndPos ) );
864 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndNeg ) );
865 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndPos ) );
866 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) );
867}
868
869
871{
872 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
873
874 if( m_textPosition == DIM_TEXT_POSITION::OUTSIDE )
875 {
876 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
877
878 VECTOR2I textOffset;
879
881 textOffset.y = -textOffsetDistance;
882 else
883 textOffset.x = -textOffsetDistance;
884
885 textOffset += crossbarCenter;
886
887 SetTextPos( m_crossBarStart + textOffset );
888 }
889 else if( m_textPosition == DIM_TEXT_POSITION::INLINE )
890 {
891 SetTextPos( m_crossBarStart + crossbarCenter );
892 }
893
895 {
896 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
898 else
900 }
901
903}
904
905
906void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
907{
908 EDA_ANGLE angle( aAngle );
909
910 // restrict angle to -179.9 to 180.0 degrees
911 angle.Normalize180();
912
913 // adjust orientation and height to new angle
914 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
915 // in the other cases we will use the nearest 90 degree angle to
916 // choose at least an approximate axis for the target orientation
917 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
918 if( angle > ANGLE_45 && angle <= ANGLE_135 )
919 {
920 // about 90 degree
922 {
924 }
925 else
926 {
929 }
930 }
931 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
932 {
933 // about -90 degree
935 {
938 }
939 else
940 {
942 }
943 }
944 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
945 {
946 // about 180 degree
948 }
949
950 // this will update m_crossBarStart and m_crossbarEnd
951 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
952}
953
954
957 m_textBorder( DIM_TEXT_BORDER::NONE )
958{
959 m_unitsFormat = DIM_UNITS_FORMAT::NO_SUFFIX;
961 m_keepTextAligned = false;
962
963 SetOverrideText( _( "Leader" ) );
964}
965
966
968{
969 return new PCB_DIM_LEADER( *this );
970}
971
972
974{
975 wxASSERT( aImage->Type() == Type() );
976
977 m_shapes.clear();
978 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
979
980 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
981
982 Update();
983}
984
985
987{
988 return BITMAPS::add_leader;
989}
990
991
993{
994 // Our geometry is dependent on the size of the text, so just update the whole shebang
996}
997
998
1000{
1001 m_shapes.clear();
1002
1004
1005 // Now that we have the text updated, we can determine how to draw the second line
1006 // First we need to create an appropriate bounding polygon to collide with
1007 BOX2I textBox = GetTextBox().Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1008
1009 SHAPE_POLY_SET polyBox;
1010 polyBox.NewOutline();
1011 polyBox.Append( textBox.GetOrigin() );
1012 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1013 polyBox.Append( textBox.GetEnd() );
1014 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1015 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1016
1017 VECTOR2I firstLine( m_end - m_start );
1018 VECTOR2I start( m_start );
1019 start += firstLine.Resize( m_extensionOffset );
1020
1021 SEG arrowSeg( m_start, m_end );
1022 SEG textSeg( m_end, GetTextPos() );
1023 OPT_VECTOR2I arrowSegEnd;
1024 OPT_VECTOR2I textSegEnd;
1025
1026 if( m_textBorder == DIM_TEXT_BORDER::CIRCLE )
1027 {
1028 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1029 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1030 CIRCLE circle( textBox.GetCenter(), radius );
1031
1032 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1033 textSegEnd = segCircleIntersection( circle, textSeg );
1034 }
1035 else
1036 {
1037 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1038 textSegEnd = segPolyIntersection( polyBox, textSeg );
1039 }
1040
1041 if( !arrowSegEnd )
1042 arrowSegEnd = m_end;
1043
1044 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1045
1046 // Add arrows
1047 VECTOR2I arrowEndPos( m_arrowLength, 0 );
1048 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
1049 RotatePoint( arrowEndPos, -EDA_ANGLE( firstLine ) + s_arrowAngle );
1050 RotatePoint( arrowEndNeg, -EDA_ANGLE( firstLine ) - s_arrowAngle );
1051
1052 m_shapes.emplace_back( new SHAPE_SEGMENT( start, start + arrowEndPos ) );
1053 m_shapes.emplace_back( new SHAPE_SEGMENT( start, start + arrowEndNeg ) );
1054
1055
1056 if( !GetText().IsEmpty() )
1057 {
1058 switch( m_textBorder )
1059 {
1060 case DIM_TEXT_BORDER::RECTANGLE:
1061 {
1062 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1063 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1064
1065 break;
1066 }
1067
1068 case DIM_TEXT_BORDER::CIRCLE:
1069 {
1070 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1071 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1072 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1073
1074 break;
1075 }
1076
1077 default:
1078 break;
1079 }
1080 }
1081
1082 if( textSegEnd && *arrowSegEnd == m_end )
1083 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, *textSegEnd ) );
1084}
1085
1086
1087void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1088{
1089 // Don't use GetShownText(); we want to see the variable references here
1090 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1091
1092 ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
1093
1094 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1095 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1096 aFrame->MessageTextFromValue( startCoord.x ),
1097 aFrame->MessageTextFromValue( startCoord.y ) );
1098
1099 aList.emplace_back( start, wxEmptyString );
1100
1101 aList.emplace_back( _( "Layer" ), GetLayerName() );
1102}
1103
1104
1107{
1108 m_unitsFormat = DIM_UNITS_FORMAT::NO_SUFFIX;
1109 m_overrideTextEnabled = false;
1110 m_keepTextAligned = true;
1111 m_isDiameter = false;
1112 m_prefix = "R ";
1114}
1115
1116
1118{
1119 return new PCB_DIM_RADIAL( *this );
1120}
1121
1122
1124{
1125 wxASSERT( aImage->Type() == Type() );
1126
1127 m_shapes.clear();
1128 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1129
1130 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1131
1132 Update();
1133}
1134
1135
1137{
1138 return BITMAPS::add_radial_dimension;
1139}
1140
1141
1143{
1144 VECTOR2I radial( m_end - m_start );
1145
1146 return m_end + radial.Resize( m_leaderLength );
1147}
1148
1149
1151{
1152 if( m_keepTextAligned )
1153 {
1154 VECTOR2I textLine( GetTextPos() - GetKnee() );
1155 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1156
1157 textAngle.Normalize();
1158
1159 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1160 textAngle -= ANGLE_180;
1161
1162 // Round to nearest degree
1163 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1164
1165 SetTextAngle( textAngle );
1166 }
1167
1169}
1170
1171
1173{
1174 m_shapes.clear();
1175
1176 VECTOR2I center( m_start );
1177 VECTOR2I centerArm( 0, m_arrowLength );
1178
1179 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1180
1181 RotatePoint( centerArm, -ANGLE_90 );
1182
1183 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1184
1185 VECTOR2I radius( m_end - m_start );
1186
1187 if( m_isDiameter )
1188 m_measuredValue = KiROUND( radius.EuclideanNorm() * 2 );
1189 else
1191
1192 updateText();
1193
1194 // Now that we have the text updated, we can determine how to draw the second line
1195 // First we need to create an appropriate bounding polygon to collide with
1197
1198 SHAPE_POLY_SET polyBox;
1199 polyBox.NewOutline();
1200 polyBox.Append( textBox.GetOrigin() );
1201 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1202 polyBox.Append( textBox.GetEnd() );
1203 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1204 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1205
1206 VECTOR2I radial( m_end - m_start );
1207 radial = radial.Resize( m_leaderLength );
1208
1209 SEG arrowSeg( m_end, m_end + radial );
1210 SEG textSeg( arrowSeg.B, GetTextPos() );
1211
1212 OPT_VECTOR2I arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1213 OPT_VECTOR2I textSegEnd = segPolyIntersection( polyBox, textSeg );
1214
1215 if( arrowSegEnd )
1216 arrowSeg.B = *arrowSegEnd;
1217
1218 if( textSegEnd )
1219 textSeg.B = *textSegEnd;
1220
1221 m_shapes.emplace_back( new SHAPE_SEGMENT( arrowSeg ) );
1222
1223 // Add arrows
1224 VECTOR2I arrowEndPos( m_arrowLength, 0 );
1225 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
1226 RotatePoint( arrowEndPos, -EDA_ANGLE( radial ) + s_arrowAngle );
1227 RotatePoint( arrowEndNeg, -EDA_ANGLE( radial ) - s_arrowAngle );
1228
1229 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndPos ) );
1230 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndNeg ) );
1231
1232 m_shapes.emplace_back( new SHAPE_SEGMENT( textSeg ) );
1233}
1234
1235
1238{
1239 m_unitsFormat = DIM_UNITS_FORMAT::NO_SUFFIX;
1240 m_overrideTextEnabled = true;
1241}
1242
1243
1245{
1246 return new PCB_DIM_CENTER( *this );
1247}
1248
1249
1251{
1252 wxASSERT( aImage->Type() == Type() );
1253
1254 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1255}
1256
1257
1259{
1260 return BITMAPS::add_center_dimension;
1261}
1262
1263
1265{
1266 int halfWidth = VECTOR2I( m_end - m_start ).x + ( m_lineThickness / 2.0 );
1267
1268 BOX2I bBox;
1269
1270 bBox.SetX( m_start.x - halfWidth );
1271 bBox.SetY( m_start.y - halfWidth );
1272 bBox.SetWidth( halfWidth * 2 );
1273 bBox.SetHeight( halfWidth * 2 );
1274
1275 bBox.Normalize();
1276
1277 return bBox;
1278}
1279
1280
1282{
1284 VECTOR2I( GetBoundingBox().GetSize() ) );
1285}
1286
1287
1289{
1290 m_shapes.clear();
1291
1292 VECTOR2I center( m_start );
1293 VECTOR2I arm( m_end - m_start );
1294
1295 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1296
1297 RotatePoint( arm, -ANGLE_90 );
1298
1299 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1300}
1301
1302
1303static struct DIMENSION_DESC
1304{
1306 {
1308 .Map( DIM_PRECISION::X, _HKI( "0" ) )
1309 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
1310 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
1311 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
1312 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
1313 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
1314 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
1315 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
1316 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
1317 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
1318
1320 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
1321 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
1322 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
1323
1325 .Map( DIM_UNITS_MODE::INCHES, _HKI( "Inches" ) )
1326 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
1327 .Map( DIM_UNITS_MODE::MILLIMETRES, _HKI( "Millimeters" ) )
1328 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
1329
1338
1339 const wxString groupDimension = _HKI( "Dimension Properties" );
1340
1341 auto isLeader =
1342 []( INSPECTABLE* aItem ) -> bool
1343 {
1344 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
1345 };
1346
1347 auto isNotLeader =
1348 []( INSPECTABLE* aItem ) -> bool
1349 {
1350 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
1351 };
1352
1355 groupDimension )
1356 .SetAvailableFunc( isNotLeader );
1359 groupDimension )
1360 .SetAvailableFunc( isNotLeader );
1361 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
1363 groupDimension )
1364 .SetAvailableFunc( isNotLeader );
1365
1368 groupDimension )
1369 .SetAvailableFunc( isLeader );
1370
1373 groupDimension )
1374 .SetAvailableFunc( isNotLeader );
1377 groupDimension )
1378 .SetAvailableFunc( isNotLeader );
1381 groupDimension )
1382 .SetAvailableFunc( isNotLeader );
1383 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
1385 groupDimension )
1386 .SetAvailableFunc( isNotLeader );
1387 }
1389
1393
1394
1396{
1398 {
1409
1410 const wxString groupDimension = _HKI( "Dimension Properties" );
1411
1412 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
1415 groupDimension );
1416 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
1419 groupDimension );
1420
1422 _HKI( "Visible" ),
1423 []( INSPECTABLE* aItem ) { return false; } );
1425 _HKI( "Text" ),
1426 []( INSPECTABLE* aItem ) { return false; } );
1428 _HKI( "Vertical Justification" ),
1429 []( INSPECTABLE* aItem ) { return false; } );
1431 _HKI( "Hyperlink" ),
1432 []( INSPECTABLE* aItem ) { return false; } );
1434 _HKI( "Knockout" ),
1435 []( INSPECTABLE* aItem ) { return false; } );
1436 }
1438
1439
1441{
1443 {
1456
1458 _HKI( "Visible" ),
1459 []( INSPECTABLE* aItem ) { return false; } );
1461 _HKI( "Text" ),
1462 []( INSPECTABLE* aItem ) { return false; } );
1464 _HKI( "Vertical Justification" ),
1465 []( INSPECTABLE* aItem ) { return false; } );
1467 _HKI( "Hyperlink" ),
1468 []( INSPECTABLE* aItem ) { return false; } );
1470 _HKI( "Knockout" ),
1471 []( INSPECTABLE* aItem ) { return false; } );
1472 }
1474
1475
1477{
1479 {
1490
1491 const wxString groupDimension = _HKI( "Dimension Properties" );
1492
1493 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
1495 PROPERTY_DISPLAY::PT_SIZE ),
1496 groupDimension );
1497
1499 _HKI( "Visible" ),
1500 []( INSPECTABLE* aItem ) { return false; } );
1502 _HKI( "Text" ),
1503 []( INSPECTABLE* aItem ) { return false; } );
1505 _HKI( "Vertical Justification" ),
1506 []( INSPECTABLE* aItem ) { return false; } );
1508 _HKI( "Hyperlink" ),
1509 []( INSPECTABLE* aItem ) { return false; } );
1511 _HKI( "Knockout" ),
1512 []( INSPECTABLE* aItem ) { return false; } );
1513 }
1515
1516
1518{
1520 {
1522 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
1523 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
1524 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
1525
1536
1537 const wxString groupDimension = _HKI( "Dimension Properties" );
1538
1541 groupDimension );
1542
1544 _HKI( "Visible" ),
1545 []( INSPECTABLE* aItem ) { return false; } );
1547 _HKI( "Text" ),
1548 []( INSPECTABLE* aItem ) { return false; } );
1550 _HKI( "Vertical Justification" ),
1551 []( INSPECTABLE* aItem ) { return false; } );
1553 _HKI( "Hyperlink" ),
1554 []( INSPECTABLE* aItem ) { return false; } );
1556 _HKI( "Knockout" ),
1557 []( INSPECTABLE* aItem ) { return false; } );
1558 }
1560
1562
1563
1565{
1567 {
1578
1579
1581 _HKI( "Visible" ),
1582 []( INSPECTABLE* aItem ) { return false; } );
1584 _HKI( "Text" ),
1585 []( INSPECTABLE* aItem ) { return false; } );
1587 _HKI( "Vertical Justification" ),
1588 []( INSPECTABLE* aItem ) { return false; } );
1590 _HKI( "Hyperlink" ),
1591 []( INSPECTABLE* aItem ) { return false; } );
1593 _HKI( "Knockout" ),
1594 []( INSPECTABLE* aItem ) { return false; } );
1595 }
1597
1598
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
BOX2< VECTOR2I > BOX2I
Definition: box2.h:853
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:204
PCB_LAYER_ID m_layer
Definition: board_item.h:361
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:238
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:45
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:209
virtual bool IsLocked() const
Definition: board_item.cpp:73
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:102
EDA_UNITS GetUserUnits()
Definition: board.h:653
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:120
const Vec & GetOrigin() const
Definition: box2.h:184
void SetX(coord_type val)
Definition: box2.h:236
const Vec GetCenter() const
Definition: box2.h:196
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:270
void SetY(coord_type val)
Definition: box2.h:241
coord_type GetY() const
Definition: box2.h:182
coord_type GetWidth() const
Definition: box2.h:188
void SetWidth(coord_type val)
Definition: box2.h:246
const Vec GetEnd() const
Definition: box2.h:186
bool Contains(const Vec &aPoint) const
Definition: box2.h:142
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:507
coord_type GetX() const
Definition: box2.h:181
coord_type GetRight() const
Definition: box2.h:190
void SetHeight(coord_type val)
Definition: box2.h:251
coord_type GetBottom() const
Definition: box2.h:191
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:589
Represent basic circle geometry with utility geometry functions.
Definition: circle.h:33
std::vector< VECTOR2I > Intersect(const CIRCLE &aCircle) const
Compute the intersection points between this circle and aCircle.
Definition: circle.cpp:209
bool Contains(const VECTOR2I &aP) const
Return true if aP is on the circumference of this circle.
Definition: circle.cpp:188
EDA_ANGLE Normalize()
Definition: eda_angle.h:249
double Sin() const
Definition: eda_angle.h:206
double AsDegrees() const
Definition: eda_angle.h:149
EDA_ANGLE Normalize180()
Definition: eda_angle.h:288
ORIGIN_TRANSFORMS & GetOriginTransforms() override
Return a reference to the default ORIGIN_TRANSFORMS object.
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
EDA_ITEM * m_parent
Linked list: Link (parent struct)
Definition: eda_item.h:485
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:80
int GetTextHeight() const
Definition: eda_text.h:213
BOX2I GetTextBox(int aLine=-1, bool aInvertY=false) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition: eda_text.cpp:546
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:219
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:131
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:95
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:398
KIFONT::FONT * GetFont() const
Definition: eda_text.h:199
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:233
int GetTextWidth() const
Definition: eda_text.h:210
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:416
virtual void ClearRenderCache()
Definition: eda_text.cpp:478
bool IsMirrored() const
Definition: eda_text.h:150
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition: eda_text.cpp:305
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, bool aUseTextRotation=true) const
build a list of segments (SHAPE_SEGMENT) to describe a text shape.
Definition: eda_text.cpp:908
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:180
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:202
int GetTextThickness() const
Definition: eda_text.h:123
static ENUM_MAP< T > & Instance()
Definition: property.h:640
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:36
static LSET SideSpecificMask()
Definition: lset.cpp:908
A class to perform either relative or absolute display origin transforms for a single axis of a point...
T ToDisplayAbs(const T &aValue) const
Abstract dimension API.
EDA_UNITS GetUnits() const
bool m_autoUnits
If true, follow the currently selected UI units.
void Update()
Update the dimension's cached text and geometry.
void ChangeSuffix(const wxString &aSuffix)
wxString GetOverrideText() const
wxString GetSuffix() const
std::vector< std::shared_ptr< SHAPE > > m_shapes
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth=false) const override
Convert the item shape to a closed polygon.
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
void ClearRenderCache() override
int m_lineThickness
Thickness used for all graphics in the dimension.
void Move(const VECTOR2I &offset) override
Move this object.
bool m_suppressZeroes
Suppress trailing zeroes.
void SetUnits(EDA_UNITS aUnits)
DIM_PRECISION m_precision
Number of digits to display after decimal.
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
static OPT_VECTOR2I segCircleIntersection(CIRCLE &aCircle, SEG &aSeg, bool aStart=true)
void addShape(const ShapeType &aShape)
void SetPrefix(const wxString &aPrefix)
wxString m_suffix
String appended to the value.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void ChangeOverrideText(const wxString &aValue)
bool m_inClearRenderCache
re-entrancy guard
PCB_DIMENSION_BASE(BOARD_ITEM *aParent, KICAD_T aType=PCB_DIMENSION_T)
int m_extensionOffset
Distance from feature points to extension line start.
bool m_keepTextAligned
Calculate text orientation to match dimension.
DIM_PRECISION GetPrecision() const
wxString GetPrefix() const
void SetSuffix(const wxString &aSuffix)
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
DIM_UNITS_MODE GetUnitsMode() const
virtual void updateText()
Update the text field value from the current geometry (called by updateGeometry normally).
bool HitTest(const VECTOR2I &aPosition, int aAccuracy) const override
Test if aPosition is inside or on the boundary of this item.
EDA_UNITS m_units
0 = inches, 1 = mm
int m_measuredValue
value of PCB dimensions
DIM_UNITS_FORMAT GetUnitsFormat() const
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
wxString m_valueString
Displayed value when m_overrideValue = true.
void ChangePrecision(DIM_PRECISION aPrecision)
bool m_overrideTextEnabled
Manually specify the displayed measurement value.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
DIM_UNITS_FORMAT m_unitsFormat
How to render the units suffix.
int GetMeasuredValue() const
bool GetSuppressZeroes() const
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
DIM_TEXT_POSITION m_textPosition
How to position the text.
static OPT_VECTOR2I segPolyIntersection(const SHAPE_POLY_SET &aPoly, const SEG &aSeg, bool aStart=true)
Find the intersection between a given segment and polygon outline.
void SetOverrideText(const wxString &aValue)
wxString GetValueText() const
void ChangePrefix(const wxString &aPrefix)
wxString m_prefix
String prepended to the value.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void ChangeUnitsFormat(const DIM_UNITS_FORMAT aFormat)
void ChangeSuppressZeroes(bool aSuppress)
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
virtual void Mirror(const VECTOR2I &axis_pos, bool aMirrorLeftRight=false)
Mirror the dimension relative to a given horizontal axis.
bool GetOverrideTextEnabled() const
void SetUnitsMode(DIM_UNITS_MODE aMode)
int m_arrowLength
Length of arrow shapes.
virtual const VECTOR2I & GetEnd() const
VECTOR2I m_end
Internal cache of drawn shapes.
void ChangeUnitsMode(DIM_UNITS_MODE aMode)
VECTOR2I GetPosition() const override
For better understanding of the points that make a dimension:
int GetHeight() const
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
int m_height
Perpendicular distance from features to crossbar.
void ChangeExtensionHeight(int aHeight)
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
VECTOR2I m_crossBarStart
Crossbar start control point.
void UpdateHeight(const VECTOR2I &aCrossbarStart, const VECTOR2I &aCrossbarEnd)
Update the stored height basing on points coordinates.
virtual void swapData(BOARD_ITEM *aImage) override
int m_extensionHeight
Length of extension lines past the crossbar.
VECTOR2I m_crossBarEnd
Crossbar end control point.
void Mirror(const VECTOR2I &axis_pos, bool aMirrorLeftRight=false) override
Mirror the dimension relative to a given horizontal axis.
PCB_DIM_ALIGNED(BOARD_ITEM *aParent, KICAD_T aType=PCB_DIM_ALIGNED_T)
void ChangeHeight(int aHeight)
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
int GetExtensionHeight() const
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Mark the center of a circle or arc with a cross shape.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
virtual void swapData(BOARD_ITEM *aImage) override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
PCB_DIM_CENTER(BOARD_ITEM *aParent)
A leader is a dimension-like object pointing to a specific point.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
DIM_TEXT_BORDER m_textBorder
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
DIM_TEXT_BORDER GetTextBorder() const
virtual void swapData(BOARD_ITEM *aImage) override
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
PCB_DIM_LEADER(BOARD_ITEM *aParent)
void ChangeTextBorder(DIM_TEXT_BORDER aBorder)
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
void swapData(BOARD_ITEM *aImage) override
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
DIR m_orientation
What axis to lock the dimension line to.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
PCB_DIM_ORTHOGONAL(BOARD_ITEM *aParent)
A radial dimension indicates either the radius or diameter of an arc or circle.
int GetLeaderLength() const
PCB_DIM_RADIAL(BOARD_ITEM *aParent)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
virtual void swapData(BOARD_ITEM *aImage) override
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void ChangeLeaderLength(int aLength)
VECTOR2I GetKnee() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pcb_text.cpp:141
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition: pcb_text.cpp:299
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_text.cpp:402
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:249
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:74
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:76
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void OverrideAvailability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override availability functor for a base class property of a given derived class.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
int GetRadius() const
Definition: shape_circle.h:108
const VECTOR2I GetCenter() const
Definition: shape_circle.h:113
Base class for iterating over all segments in a given SHAPE_POLY_SET.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
SEGMENT_ITERATOR IterateSegments(int aFirst, int aLast, bool aIterateHoles=false)
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
CONST_SEGMENT_ITERATOR CIterateSegments(int aFirst, int aLast, bool aIterateHoles=false) const
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
const SEG & GetSeg() const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A lower-precision version of StringFromValue().
void SetUserUnits(EDA_UNITS aUnits)
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:265
extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition: vector2d.h:457
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:350
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
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.
#define _HKI(x)
#define _(s)
static constexpr EDA_ANGLE & ANGLE_180
Definition: eda_angle.h:441
static constexpr EDA_ANGLE & ANGLE_HORIZONTAL
Definition: eda_angle.h:433
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_VERTICAL
Definition: eda_angle.h:434
static constexpr EDA_ANGLE & ANGLE_45
Definition: eda_angle.h:438
static constexpr EDA_ANGLE & FULL_CIRCLE
Definition: eda_angle.h:435
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:439
static constexpr EDA_ANGLE & ANGLE_270
Definition: eda_angle.h:442
static constexpr EDA_ANGLE & ANGLE_135
Definition: eda_angle.h:440
#define PCB_EDIT_FRAME_NAME
EDA_UNITS
Definition: eda_units.h:44
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ NONE
Definition: kibis.h:54
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:148
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ Dwgs_User
Definition: layer_ids.h:110
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:544
KICOMMON_API double ToUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Function To_User_Unit convert aValue in internal units to the appropriate user units defined by aUnit...
Definition: eda_units.cpp:190
KICOMMON_API wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:101
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:128
wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
Definition: ui_common.cpp:219
wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
Definition: ui_common.cpp:201
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:426
static const EDA_ANGLE s_arrowAngle(27.5, DEGREES_T)
static struct DIMENSION_DESC _DIMENSION_DESC
#define INVERT(pos)
DIM_TEXT_POSITION
Where to place the text on a dimension.
Definition: pcb_dimension.h:62
@ OUTSIDE
Text appears outside the dimension line (default)
DIM_UNITS_FORMAT
How to display the units in a dimension's text.
Definition: pcb_dimension.h:40
DIM_UNITS_MODE
Used for storing the units selection in the file because EDA_UNITS alone doesn't cut it.
Definition: pcb_dimension.h:72
DIM_TEXT_BORDER
Frame to show around dimension text.
Definition: pcb_dimension.h:83
DIM_PRECISION
Definition: pcb_dimension.h:47
#define TYPE_HASH(x)
Definition: property.h:64
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:742
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition: property.h:57
#define REGISTER_TYPE(x)
Definition: property_mgr.h:356
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:102
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:99
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:100
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:101
int sign(T val)
Definition: util.h:124
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588