KiCad PCB EDA Suite
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-2022 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 <pcb_dimension.h>
32#include <pcb_text.h>
38#include <trigo.h>
39
40
41static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
42
43
45 BOARD_ITEM( aParent, aType ),
46 m_overrideTextEnabled( false ),
47 m_units( EDA_UNITS::INCHES ),
48 m_autoUnits( false ),
49 m_unitsFormat( DIM_UNITS_FORMAT::BARE_SUFFIX ),
50 m_precision( 4 ),
51 m_suppressZeroes( false ),
52 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
53 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
54 m_extensionOffset( 0 ),
55 m_textPosition( DIM_TEXT_POSITION::OUTSIDE ),
56 m_keepTextAligned( true ),
57 m_text( aParent ),
58 m_measuredValue( 0 )
59{
61}
62
63
65{
66 BOARD_ITEM::SetParent( aParent );
67 m_text.SetParent( aParent );
68}
69
70
72{
74
75 switch( m_unitsFormat )
76 {
77 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
78 break;
79
80 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
82 break;
83
84 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
85 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
86 break;
87 }
88
89 text.Prepend( m_prefix );
90 text.Append( m_suffix );
91
93}
94
95
96template<typename ShapeType>
97void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
98{
99 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
100}
101
102
104{
105 struct lconv* lc = localeconv();
106 wxChar sep = lc->decimal_point[0];
107
108 int val = GetMeasuredValue();
109 int precision = m_precision;
110 wxString text;
111
112 if( precision >= 6 )
113 {
114 switch( m_units )
115 {
116 case EDA_UNITS::INCHES: precision = precision - 4; break;
117 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
118 case EDA_UNITS::MILLIMETRES: precision = precision - 5; break;
119 default: precision = precision - 4; break;
120 }
121 }
122
123 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
124
125 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
126
127 if( m_suppressZeroes )
128 {
129 while( text.Last() == '0' )
130 {
131 text.RemoveLast();
132
133 if( text.Last() == '.' || text.Last() == sep )
134 {
135 text.RemoveLast();
136 break;
137 }
138 }
139 }
140
141 return text;
142}
143
144
145void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
146{
147 m_prefix = aPrefix;
148}
149
150
151void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
152{
153 m_suffix = aSuffix;
154}
155
156
158{
159 m_units = aUnits;
160}
161
162
164{
165 if( m_autoUnits )
166 {
168 }
169 else
170 {
171 switch( m_units )
172 {
173 default:
177 }
178 }
179}
180
181
183{
184 m_autoUnits = false;
185
186 switch( aMode )
187 {
191 case DIM_UNITS_MODE::AUTOMATIC: m_autoUnits = true; break;
192 }
193}
194
195
196void PCB_DIMENSION_BASE::SetText( const wxString& aNewText )
197{
198 m_valueString = aNewText;
199 updateText();
200}
201
202
203const wxString PCB_DIMENSION_BASE::GetText() const
204{
205 return m_text.GetText();
206}
207
208
210{
211 m_layer = aLayer;
212 m_text.SetLayer( aLayer );
213}
214
215
217{
218 m_text.Offset( offset );
219
220 m_start += offset;
221 m_end += offset;
222
223 Update();
224}
225
226
227void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
228{
229 EDA_ANGLE newAngle = m_text.GetTextAngle() + aAngle;
230
231 newAngle.Normalize();
232
233 m_text.SetTextAngle( newAngle );
234
236 RotatePoint( pt, aRotCentre, aAngle );
237 m_text.SetTextPos( pt );
238
239 RotatePoint( m_start, aRotCentre, aAngle );
240 RotatePoint( m_end, aRotCentre, aAngle );
241
242 Update();
243}
244
245
246void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
247{
248 Mirror( aCentre );
249
250 SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
251}
252
253
254void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight )
255{
256 int axis = aMirrorLeftRight ? axis_pos.x : axis_pos.y;
257 VECTOR2I newPos = m_text.GetTextPos();
258
259#define INVERT( pos ) ( ( pos ) = axis - ( ( pos ) - axis ) )
260 if( aMirrorLeftRight )
261 INVERT( newPos.x );
262 else
263 INVERT( newPos.y );
264
265 m_text.SetTextPos( newPos );
266
267 // invert angle
269
270 if( aMirrorLeftRight )
271 {
272 INVERT( m_start.x );
273 INVERT( m_end.x );
274 }
275 else
276 {
277 INVERT( m_start.y );
278 INVERT( m_end.y );
279 }
280
281 if( ( GetLayerSet() & LSET::SideSpecificMask() ).any() )
283
284 Update();
285}
286
287
289 std::vector<MSG_PANEL_ITEM>& aList )
290{
291 // for now, display only the text within the DIMENSION using class PCB_TEXT.
292 wxString msg;
293
294 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
295
296 aList.emplace_back( _( "Dimension" ), m_text.GetShownText() );
297
298 aList.emplace_back( _( "Prefix" ), GetPrefix() );
299
301 {
302 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
303 }
304 else
305 {
306 aList.emplace_back( _( "Value" ), GetValueText() );
307
308 switch( GetPrecision() )
309 {
310 case 6: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
311 case 7: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
312 case 8: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
313 case 9: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
314 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
315 }
316
317 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
318 }
319
320 aList.emplace_back( _( "Suffix" ), GetSuffix() );
321
322 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
323 // in frame's units.
325 unitsProvider.SetUserUnits( GetUnits() );
326
327 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
328
329 aList.emplace_back( _( "Font" ), m_text.GetFont() ? m_text.GetFont()->GetName() : _( "Default" ) );
330 aList.emplace_back( _( "Text Thickness" ),
331 unitsProvider.MessageTextFromValue( m_text.GetTextThickness() ) );
332 aList.emplace_back( _( "Text Width" ),
333 unitsProvider.MessageTextFromValue( m_text.GetTextWidth() ) );
334 aList.emplace_back( _( "Text Height" ),
335 unitsProvider.MessageTextFromValue( m_text.GetTextHeight() ) );
336
337 ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
338
340 {
341 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
342 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
343 aFrame->MessageTextFromValue( startCoord.x ),
344 aFrame->MessageTextFromValue( startCoord.y ) );
345
346 aList.emplace_back( start, wxEmptyString );
347 }
348 else
349 {
350 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
351 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
352 aFrame->MessageTextFromValue( startCoord.x ),
353 aFrame->MessageTextFromValue( startCoord.y ) );
354 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
355 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
356 aFrame->MessageTextFromValue( endCoord.x ),
357 aFrame->MessageTextFromValue( endCoord.y ) );
358
359 aList.emplace_back( start, end );
360 }
361
362 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
363 aList.emplace_back( _( "Status" ), _( "Locked" ) );
364
365 aList.emplace_back( _( "Layer" ), GetLayerName() );
366}
367
368
369std::shared_ptr<SHAPE> PCB_DIMENSION_BASE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
370{
371 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
372
373 effectiveShape->AddShape( Text().GetEffectiveTextShape()->Clone() );
374
375 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
376 effectiveShape->AddShape( shape->Clone() );
377
378 return effectiveShape;
379}
380
381
382bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
383{
384 if( m_text.TextHitTest( aPosition ) )
385 return true;
386
387 int dist_max = aAccuracy + ( m_lineThickness / 2 );
388
389 // Locate SEGMENTS
390
391 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
392 {
393 if( shape->Collide( aPosition, dist_max ) )
394 return true;
395 }
396
397 return false;
398}
399
400
401bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
402{
403 BOX2I arect = aRect;
404 arect.Inflate( aAccuracy );
405
406 BOX2I rect = GetBoundingBox();
407
408 if( aAccuracy )
409 rect.Inflate( aAccuracy );
410
411 if( aContained )
412 return arect.Contains( rect );
413
414 return arect.Intersects( rect );
415}
416
417
419{
420 BOX2I bBox;
421 int xmin, xmax, ymin, ymax;
422
423 bBox = m_text.GetTextBox();
424 xmin = bBox.GetX();
425 xmax = bBox.GetRight();
426 ymin = bBox.GetY();
427 ymax = bBox.GetBottom();
428
429 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
430 {
431 BOX2I shapeBox = shape->BBox();
432 shapeBox.Inflate( m_lineThickness / 2 );
433
434 xmin = std::min( xmin, shapeBox.GetOrigin().x );
435 xmax = std::max( xmax, shapeBox.GetEnd().x );
436 ymin = std::min( ymin, shapeBox.GetOrigin().y );
437 ymax = std::max( ymax, shapeBox.GetEnd().y );
438 }
439
440 bBox.SetX( xmin );
441 bBox.SetY( ymin );
442 bBox.SetWidth( xmax - xmin + 1 );
443 bBox.SetHeight( ymax - ymin + 1 );
444
445 bBox.Normalize();
446
447 return bBox;
448}
449
450
452{
453 return wxString::Format( _( "Dimension '%s' on %s" ), GetText(), GetLayerName() );
454}
455
456
457
459{
461 VECTOR2I( GetBoundingBox().GetSize() ) );
462 dimBBox.Merge( m_text.ViewBBox() );
463
464 return dimBBox;
465}
466
467
469 bool aStart )
470{
471 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
472 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
473
474 if( aPoly.Contains( start ) )
475 return std::nullopt;
476
477 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
478 {
479 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
480 {
481 if( ( *intersection - start ).SquaredEuclideanNorm() <
482 ( endpoint - start ).SquaredEuclideanNorm() )
483 endpoint = *intersection;
484 }
485 }
486
487 if( start == endpoint )
488 return std::nullopt;
489
490 return OPT_VECTOR2I( endpoint );
491}
492
493
495{
496 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
497 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
498
499 if( aCircle.Contains( start ) )
500 return std::nullopt;
501
502 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
503
504 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
505 {
506 if( ( intersection - start ).SquaredEuclideanNorm() <
507 ( endpoint - start ).SquaredEuclideanNorm() )
508 endpoint = intersection;
509 }
510
511 if( start == endpoint )
512 return std::nullopt;
513
514 return OPT_VECTOR2I( endpoint );
515}
516
517
519 int aClearance, int aError, ERROR_LOC aErrorLoc,
520 bool aIgnoreLineWidth ) const
521{
522 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
523
524 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
525 {
526 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
527 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
528
529 if( circle )
530 {
531 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
532 circle->GetRadius() + m_lineThickness / 2 + aClearance,
533 aError, aErrorLoc );
534 }
535 else if( seg )
536 {
537 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
538 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
539 }
540 else
541 {
542 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
543 }
544 }
545}
546
547
549 PCB_DIMENSION_BASE( aParent, aType ),
550 m_height( 0 )
551{
552 // To preserve look of old dimensions, initialize extension height based on default arrow length
553 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
554}
555
556
558{
559 return new PCB_DIM_ALIGNED( *this );
560}
561
562
564{
565 wxASSERT( aImage->Type() == Type() );
566
567 m_shapes.clear();
568 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
569
570 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
571
572 Update();
573}
574
575
576void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight )
577{
578 PCB_DIMENSION_BASE::Mirror( axis_pos, aMirrorLeftRight );
579
581}
582
583
585{
587}
588
589
590void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
591{
592 VECTOR2D height( aCrossbarStart - GetStart() );
593 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
594
595 if( height.Cross( crossBar ) > 0 )
596 m_height = -height.EuclideanNorm();
597 else
598 m_height = height.EuclideanNorm();
599
600 Update();
601}
602
603
605{
606 m_shapes.clear();
607
608 VECTOR2I dimension( m_end - m_start );
609
610 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
611
612 VECTOR2I extension;
613
614 if( m_height > 0 )
615 extension = VECTOR2I( -dimension.y, dimension.x );
616 else
617 extension = VECTOR2I( dimension.y, -dimension.x );
618
619 // Add extension lines
620 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
621
622 VECTOR2I extStart( m_start );
623 extStart += extension.Resize( m_extensionOffset );
624
625 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
626
627 extStart = VECTOR2I( m_end );
628 extStart += extension.Resize( m_extensionOffset );
629
630 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
631
632 // Add crossbar
633 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
634 m_crossBarStart = m_start + crossBarDistance;
635 m_crossBarEnd = m_end + crossBarDistance;
636
637 // Update text after calculating crossbar position but before adding crossbar lines
638 updateText();
639
640 // Now that we have the text updated, we can determine how to draw the crossbar.
641 // First we need to create an appropriate bounding polygon to collide with
644
645 SHAPE_POLY_SET polyBox;
646 polyBox.NewOutline();
647 polyBox.Append( textBox.GetOrigin() );
648 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
649 polyBox.Append( textBox.GetEnd() );
650 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
651 polyBox.Rotate( m_text.GetTextAngle(), textBox.GetCenter() );
652
653 // The ideal crossbar, if the text doesn't collide
654 SEG crossbar( m_crossBarStart, m_crossBarEnd );
655
656 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
657 bool containsA = polyBox.Contains( crossbar.A );
658 bool containsB = polyBox.Contains( crossbar.B );
659
660 OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
661 OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
662
663 if( endpointA )
664 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
665
666 if( endpointB )
667 m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
668
669 if( !containsA && !containsB && !endpointA && !endpointB )
670 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
671
672 // Add arrows
673 VECTOR2I arrowEndPos( m_arrowLength, 0 );
674 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
675 RotatePoint( arrowEndPos, -EDA_ANGLE( dimension ) + s_arrowAngle );
676 RotatePoint( arrowEndNeg, -EDA_ANGLE( dimension ) - s_arrowAngle );
677
678 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndPos ) );
679 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndNeg ) );
680 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndPos ) );
681 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) );
682}
683
684
686{
687 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
688
690 {
691 int textOffsetDistance = m_text.GetEffectiveTextPenWidth() + m_text.GetTextHeight();
692 EDA_ANGLE rotation;
693
694 if( crossbarCenter.x == 0 )
695 rotation = ANGLE_90 * sign( -crossbarCenter.y );
696 else if( crossbarCenter.x < 0 )
697 rotation = -ANGLE_90;
698 else
699 rotation = ANGLE_90;
700
701 VECTOR2I textOffset = crossbarCenter;
702 RotatePoint( textOffset, rotation );
703 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
704
705 m_text.SetTextPos( m_crossBarStart + textOffset );
706 }
708 {
709 m_text.SetTextPos( m_crossBarStart + crossbarCenter );
710 }
711
713 {
714 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
715 textAngle.Normalize();
716
717 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
718 textAngle -= ANGLE_180;
719
720 m_text.SetTextAngle( textAngle );
721 }
722
724}
725
726
727void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
728{
730
731 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
732 // in frame's units.
734 unitsProvider.SetUserUnits( GetUnits() );
735
736 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
737}
738
739
742{
743 // To preserve look of old dimensions, initialize extension height based on default arrow length
744 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
746}
747
748
750{
751 return new PCB_DIM_ORTHOGONAL( *this );
752}
753
754
756{
757 wxASSERT( aImage->Type() == Type() );
758
759 m_shapes.clear();
760 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
761
762 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
763 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
764
765 Update();
766}
767
768
770{
772}
773
774
776{
777 m_shapes.clear();
778
780 m_end.y - m_start.y );
782
783 VECTOR2I extension;
784
786 extension = VECTOR2I( 0, m_height );
787 else
788 extension = VECTOR2I( m_height, 0 );
789
790 // Add first extension line
791 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
792
793 VECTOR2I extStart( m_start );
794 extStart += extension.Resize( m_extensionOffset );
795
796 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
797
798 // Add crossbar
799 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
800 m_crossBarStart = m_start + crossBarDistance;
801
804 else
806
807 // Add second extension line (m_end to crossbar end)
809 extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y );
810 else
811 extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 );
812
813 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
814
815 extStart = VECTOR2I( m_crossBarEnd );
816 extStart -= extension.Resize( m_extensionHeight );
817
818 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
819
820 // Update text after calculating crossbar position but before adding crossbar lines
821 updateText();
822
823 // Now that we have the text updated, we can determine how to draw the crossbar.
824 // First we need to create an appropriate bounding polygon to collide with
827
828 SHAPE_POLY_SET polyBox;
829 polyBox.NewOutline();
830 polyBox.Append( textBox.GetOrigin() );
831 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
832 polyBox.Append( textBox.GetEnd() );
833 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
834 polyBox.Rotate( m_text.GetTextAngle(), textBox.GetCenter() );
835
836 // The ideal crossbar, if the text doesn't collide
837 SEG crossbar( m_crossBarStart, m_crossBarEnd );
838
839 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
840 bool containsA = polyBox.Contains( crossbar.A );
841 bool containsB = polyBox.Contains( crossbar.B );
842
843 OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
844 OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
845
846 if( endpointA )
847 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
848
849 if( endpointB )
850 m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
851
852 if( !containsA && !containsB && !endpointA && !endpointB )
853 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
854
855 // Add arrows
856 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
857 VECTOR2I arrowEndPos( m_arrowLength, 0 );
858 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
859 RotatePoint( arrowEndPos, -crossBarAngle + s_arrowAngle );
860 RotatePoint( arrowEndNeg, -crossBarAngle - s_arrowAngle );
861
862 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndPos ) );
863 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndNeg ) );
864 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndPos ) );
865 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) );
866}
867
868
870{
871 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
872
874 {
875 int textOffsetDistance = m_text.GetEffectiveTextPenWidth() + m_text.GetTextHeight();
876
877 VECTOR2I textOffset;
878
880 textOffset.y = -textOffsetDistance;
881 else
882 textOffset.x = -textOffsetDistance;
883
884 textOffset += crossbarCenter;
885
886 m_text.SetTextPos( m_crossBarStart + textOffset );
887 }
889 {
890 m_text.SetTextPos( m_crossBarStart + crossbarCenter );
891 }
892
894 {
895 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
897 else
899 }
900
902}
903
904
905void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
906{
907 EDA_ANGLE angle( aAngle );
908
909 // restrict angle to -179.9 to 180.0 degrees
910 angle.Normalize180();
911
912 // adjust orientation and height to new angle
913 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
914 // in the other cases we will use the nearest 90 degree angle to
915 // choose at least an approximate axis for the target orientation
916 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
917 if( angle > ANGLE_45 && angle <= ANGLE_135 )
918 {
919 // about 90 degree
921 {
923 }
924 else
925 {
928 }
929 }
930 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
931 {
932 // about -90 degree
934 {
937 }
938 else
939 {
941 }
942 }
943 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
944 {
945 // about 180 degree
947 }
948
949 // this will update m_crossBarStart and m_crossbarEnd
950 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
951}
952
953
956 m_textBorder( DIM_TEXT_BORDER::NONE )
957{
960 m_keepTextAligned = false;
961
962 SetText( _( "Leader" ) );
963}
964
965
967{
968 return new PCB_DIM_LEADER( *this );
969}
970
971
973{
974 wxASSERT( aImage->Type() == Type() );
975
976 m_shapes.clear();
977 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
978
979 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
980
981 Update();
982}
983
984
986{
987 return BITMAPS::add_leader;
988}
989
990
992{
993 m_shapes.clear();
994
995 updateText();
996
997 // Now that we have the text updated, we can determine how to draw the second line
998 // First we need to create an appropriate bounding polygon to collide with
1001
1002 SHAPE_POLY_SET polyBox;
1003 polyBox.NewOutline();
1004 polyBox.Append( textBox.GetOrigin() );
1005 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1006 polyBox.Append( textBox.GetEnd() );
1007 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1008 polyBox.Rotate( m_text.GetTextAngle(), textBox.GetCenter() );
1009
1010 VECTOR2I firstLine( m_end - m_start );
1011 VECTOR2I start( m_start );
1012 start += firstLine.Resize( m_extensionOffset );
1013
1014 SEG arrowSeg( m_start, m_end );
1015 SEG textSeg( m_end, m_text.GetPosition() );
1016 OPT_VECTOR2I arrowSegEnd;
1017 OPT_VECTOR2I textSegEnd;
1018
1020 {
1021 double penWidth = m_text.GetEffectiveTextPenWidth() / 2.0;
1022 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1023 CIRCLE circle( textBox.GetCenter(), radius );
1024
1025 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1026 textSegEnd = segCircleIntersection( circle, textSeg );
1027 }
1028 else
1029 {
1030 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1031 textSegEnd = segPolyIntersection( polyBox, textSeg );
1032 }
1033
1034 if( !arrowSegEnd )
1035 arrowSegEnd = m_end;
1036
1037 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1038
1039 // Add arrows
1040 VECTOR2I arrowEndPos( m_arrowLength, 0 );
1041 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
1042 RotatePoint( arrowEndPos, -EDA_ANGLE( firstLine ) + s_arrowAngle );
1043 RotatePoint( arrowEndNeg, -EDA_ANGLE( firstLine ) - s_arrowAngle );
1044
1045 m_shapes.emplace_back( new SHAPE_SEGMENT( start, start + arrowEndPos ) );
1046 m_shapes.emplace_back( new SHAPE_SEGMENT( start, start + arrowEndNeg ) );
1047
1048
1049 if( !GetText().IsEmpty() )
1050 {
1051 switch( m_textBorder )
1052 {
1054 {
1055 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1056 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1057
1058 break;
1059 }
1060
1062 {
1063 double penWidth = m_text.GetEffectiveTextPenWidth() / 2.0;
1064 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1065 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1066
1067 break;
1068 }
1069
1070 default:
1071 break;
1072 }
1073 }
1074
1075 if( textSegEnd && *arrowSegEnd == m_end )
1076 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, *textSegEnd ) );
1077}
1078
1079
1080void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1081{
1082 aList.emplace_back( _( "Leader" ), m_text.GetShownText() );
1083
1084 ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
1085
1086 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1087 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1088 aFrame->MessageTextFromValue( startCoord.x ),
1089 aFrame->MessageTextFromValue( startCoord.y ) );
1090
1091 aList.emplace_back( start, wxEmptyString );
1092
1093 aList.emplace_back( _( "Layer" ), GetLayerName() );
1094}
1095
1096
1099{
1101 m_overrideTextEnabled = false;
1102 m_keepTextAligned = true;
1103 m_isDiameter = false;
1104 m_prefix = "R ";
1106}
1107
1108
1110{
1111 return new PCB_DIM_RADIAL( *this );
1112}
1113
1114
1116{
1117 wxASSERT( aImage->Type() == Type() );
1118
1119 m_shapes.clear();
1120 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1121
1122 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1123
1124 Update();
1125}
1126
1127
1129{
1131}
1132
1133
1135{
1136 VECTOR2I radial( m_end - m_start );
1137
1138 return m_end + radial.Resize( m_leaderLength );
1139}
1140
1141
1143{
1144 if( m_keepTextAligned )
1145 {
1146 VECTOR2I textLine( Text().GetPosition() - GetKnee() );
1147 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1148
1149 textAngle.Normalize();
1150
1151 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1152 textAngle -= ANGLE_180;
1153
1154 // Round to nearest degree
1155 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1156
1157 m_text.SetTextAngle( textAngle );
1158 }
1159
1161}
1162
1163
1165{
1166 m_shapes.clear();
1167
1168 VECTOR2I center( m_start );
1169 VECTOR2I centerArm( 0, m_arrowLength );
1170
1171 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1172
1173 RotatePoint( centerArm, -ANGLE_90 );
1174
1175 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1176
1177 VECTOR2I radius( m_end - m_start );
1178
1179 if( m_isDiameter )
1180 m_measuredValue = KiROUND( radius.EuclideanNorm() * 2 );
1181 else
1183
1184 updateText();
1185
1186 // Now that we have the text updated, we can determine how to draw the second line
1187 // First we need to create an appropriate bounding polygon to collide with
1188 BOX2I textBox = m_text.GetTextBox().Inflate( m_text.GetTextWidth() / 2,
1190
1191 SHAPE_POLY_SET polyBox;
1192 polyBox.NewOutline();
1193 polyBox.Append( textBox.GetOrigin() );
1194 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1195 polyBox.Append( textBox.GetEnd() );
1196 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1197 polyBox.Rotate( m_text.GetTextAngle(), textBox.GetCenter() );
1198
1199 VECTOR2I radial( m_end - m_start );
1200 radial = radial.Resize( m_leaderLength );
1201
1202 SEG arrowSeg( m_end, m_end + radial );
1203 SEG textSeg( arrowSeg.B, m_text.GetPosition() );
1204
1205 OPT_VECTOR2I arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1206 OPT_VECTOR2I textSegEnd = segPolyIntersection( polyBox, textSeg );
1207
1208 if( arrowSegEnd )
1209 arrowSeg.B = *arrowSegEnd;
1210
1211 if( textSegEnd )
1212 textSeg.B = *textSegEnd;
1213
1214 m_shapes.emplace_back( new SHAPE_SEGMENT( arrowSeg ) );
1215
1216 // Add arrows
1217 VECTOR2I arrowEndPos( m_arrowLength, 0 );
1218 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
1219 RotatePoint( arrowEndPos, -EDA_ANGLE( radial ) + s_arrowAngle );
1220 RotatePoint( arrowEndNeg, -EDA_ANGLE( radial ) - s_arrowAngle );
1221
1222 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndPos ) );
1223 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndNeg ) );
1224
1225 m_shapes.emplace_back( new SHAPE_SEGMENT( textSeg ) );
1226}
1227
1228
1231{
1233 m_overrideTextEnabled = true;
1234}
1235
1236
1238{
1239 return new PCB_DIM_CENTER( *this );
1240}
1241
1242
1244{
1245 wxASSERT( aImage->Type() == Type() );
1246
1247 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1248}
1249
1250
1252{
1254}
1255
1256
1258{
1259 int halfWidth = VECTOR2I( m_end - m_start ).x + ( m_lineThickness / 2.0 );
1260
1261 BOX2I bBox;
1262
1263 bBox.SetX( m_start.x - halfWidth );
1264 bBox.SetY( m_start.y - halfWidth );
1265 bBox.SetWidth( halfWidth * 2 );
1266 bBox.SetHeight( halfWidth * 2 );
1267
1268 bBox.Normalize();
1269
1270 return bBox;
1271}
1272
1273
1275{
1277 VECTOR2I( GetBoundingBox().GetSize() ) );
1278}
1279
1280
1282{
1283 m_shapes.clear();
1284
1285 VECTOR2I center( m_start );
1286 VECTOR2I arm( m_end - m_start );
1287
1288 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1289
1290 RotatePoint( arm, -ANGLE_90 );
1291
1292 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1293}
1294
1295
1296static struct DIMENSION_DESC
1297{
1299 {
1303 // TODO: add dimension properties:
1304 //propMgr.AddProperty( new PROPERTY<DIMENSION, int>( _HKI( "Height" ),
1305 //&DIMENSION::SetHeight, &DIMENSION::GetHeight, PROPERTY_DISPLAY::SIZE ) );
1306 }
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
@ add_radial_dimension
@ add_aligned_dimension
@ add_center_dimension
@ add_orthogonal_dimension
BOX2< VECTOR2I > BOX2I
Definition: box2.h:847
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:180
PCB_LAYER_ID m_layer
Definition: board_item.h:329
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:214
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:43
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:185
virtual bool IsLocked() const
Definition: board_item.cpp:71
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:94
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetOrigin() const
Definition: box2.h:183
void SetX(coord_type val)
Definition: box2.h:235
const Vec GetCenter() const
Definition: box2.h:195
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
void SetY(coord_type val)
Definition: box2.h:240
coord_type GetY() const
Definition: box2.h:181
coord_type GetWidth() const
Definition: box2.h:187
void SetWidth(coord_type val)
Definition: box2.h:245
const Vec GetEnd() const
Definition: box2.h:185
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
coord_type GetX() const
Definition: box2.h:180
coord_type GetRight() const
Definition: box2.h:189
void SetHeight(coord_type val)
Definition: box2.h:250
coord_type GetBottom() const
Definition: box2.h:190
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:588
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
virtual ORIGIN_TRANSFORMS & GetOriginTransforms()
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
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:82
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: eda_item.cpp:254
EDA_ITEM * m_parent
Linked list: Link (parent struct)
Definition: eda_item.h:496
int GetTextHeight() const
Definition: eda_text.h:195
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:503
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:201
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:120
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:371
KIFONT::FONT * GetFont() const
Definition: eda_text.h:181
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:224
int GetTextWidth() const
Definition: eda_text.h:192
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:389
bool IsMirrored() const
Definition: eda_text.h:132
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition: eda_text.cpp:297
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:163
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:193
int GetTextThickness() const
Definition: eda_text.h:112
const wxString & GetName() const
Definition: font.h:121
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.
Definition: pcb_dimension.h:96
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.
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.
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)
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.
PCB_TEXT m_text
The actual text object.
PCB_TEXT & Text()
PCB_DIMENSION_BASE(BOARD_ITEM *aParent, KICAD_T aType=PCB_DIMENSION_T)
int m_extensionOffset
Distance from feature points to extension line start.
void SetText(const wxString &aNewText)
Set the override text - has no effect if m_overrideValue == false.
void SetParent(EDA_ITEM *aParent) override
bool m_keepTextAligned
Calculate text orientation to match dimension.
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
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.
bool m_overrideTextEnabled
Manually specify the displayed measurement value.
wxString GetSelectMenuText(UNITS_PROVIDER *aUnitsProvider) const override
Return the text to display to be used in the selection clarification context menu when multiple items...
DIM_UNITS_FORMAT m_unitsFormat
How to render the units suffix.
int GetMeasuredValue() const
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
int m_precision
Number of digits to display after decimal.
const wxString GetText() const
Retrieve the value text or override text, not including prefix or suffix.
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.
wxString GetValueText() const
wxString m_prefix
String prepended to the value.
int GetPrecision() const
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
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.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
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.
VECTOR2I GetPosition() const override
For better understanding of the points that make a dimension:
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 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
PCB_DIM_ALIGNED(BOARD_ITEM *aParent, KICAD_T aType)
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.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
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.
PCB_DIM_CENTER(BOARD_ITEM *aParent, bool aInFP=false)
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.
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.
virtual void swapData(BOARD_ITEM *aImage) override
PCB_DIM_LEADER(BOARD_ITEM *aParent, bool aInFP=false)
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
PCB_DIM_ORTHOGONAL(BOARD_ITEM *aParent, bool aInFP=false)
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.
A radial dimension indicates either the radius or diameter of an arc or circle.
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.
PCB_DIM_RADIAL(BOARD_ITEM *aParent, bool aInFP=false)
VECTOR2I GetKnee() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
virtual VECTOR2I GetPosition() const override
Definition: pcb_text.h:76
wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const override
Return the string actually shown after processing of the base text.
Definition: pcb_text.cpp:55
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition: pcb_text.cpp:172
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:64
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:66
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)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
int NewOutline()
Creates a new hole in a given outline.
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 aPolygonIdx-th polygon edges.
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:293
extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition: vector2d.h:487
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:378
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 _(s)
static constexpr EDA_ANGLE & ANGLE_180
Definition: eda_angle.h:416
static constexpr EDA_ANGLE & ANGLE_HORIZONTAL
Definition: eda_angle.h:408
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_VERTICAL
Definition: eda_angle.h:409
static constexpr EDA_ANGLE & ANGLE_45
Definition: eda_angle.h:413
static constexpr EDA_ANGLE & FULL_CIRCLE
Definition: eda_angle.h:410
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:414
static constexpr EDA_ANGLE & ANGLE_270
Definition: eda_angle.h:417
static constexpr EDA_ANGLE & ANGLE_135
Definition: eda_angle.h:415
#define PCB_EDIT_FRAME_NAME
EDA_UNITS
Definition: eda_units.h:43
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:53
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:147
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ Dwgs_User
Definition: layer_ids.h:109
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:544
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:194
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:98
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:125
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
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:48
@ OUTSIDE
Text appears outside the dimension line (default)
@ INLINE
Text appears in line with the dimension line.
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:58
DIM_TEXT_BORDER
Frame to show around dimension text.
Definition: pcb_dimension.h:69
#define TYPE_HASH(x)
Definition: property.h:61
#define REGISTER_TYPE(x)
Definition: property_mgr.h:256
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
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:110
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:107
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:108
@ PCB_FP_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:97
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:109
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:618