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) 2023 CERN
8 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#include <bitmaps.h>
25#include <pcb_edit_frame.h>
26#include <base_units.h>
28#include <font/font.h>
29#include <board.h>
30#include <footprint.h>
31#include <pcb_dimension.h>
32#include <pcb_painter.h>
33#include <pcb_text.h>
34#include <view/view.h>
39#include <geometry/shape_rect.h>
43#include <trigo.h>
44#include <api/api_enums.h>
45#include <api/api_utils.h>
46#include <api/board/board_types.pb.h>
47#include <properties/property.h>
50
53
54
56
57static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
58
59
68static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
69 bool aStart = true )
70{
71 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
72 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
73
74 if( aPoly.Contains( start ) )
75 return std::nullopt;
76
77 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
78 {
79 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
80 {
81 if( ( *intersection - start ).SquaredEuclideanNorm()
82 < ( endpoint - start ).SquaredEuclideanNorm() )
83 endpoint = *intersection;
84 }
85 }
86
87 if( start == endpoint )
88 return std::nullopt;
89
90 return OPT_VECTOR2I( endpoint );
91}
92
93
94static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true )
95{
96 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
97 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
98
99 if( aCircle.Contains( start ) )
100 return std::nullopt;
101
102 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
103
104 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
105 {
106 if( ( intersection - start ).SquaredEuclideanNorm()
107 < ( endpoint - start ).SquaredEuclideanNorm() )
108 endpoint = intersection;
109 }
110
111 if( start == endpoint )
112 return std::nullopt;
113
114 return OPT_VECTOR2I( endpoint );
115}
116
117
122static void CollectKnockedOutSegments( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
123 std::vector<std::shared_ptr<SHAPE>>& aSegmentsAfterKnockout )
124{
125 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
126 const bool containsA = aPoly.Contains( aSeg.A );
127 const bool containsB = aPoly.Contains( aSeg.B );
128
129 const OPT_VECTOR2I endpointA = segPolyIntersection( aPoly, aSeg );
130 const OPT_VECTOR2I endpointB = segPolyIntersection( aPoly, aSeg, false );
131
132 if( endpointA )
133 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg.A, *endpointA ) );
134
135 if( endpointB )
136 {
137 bool can_add = true;
138
139 if( endpointA )
140 {
141 if( ( *endpointB == aSeg.A && *endpointA == aSeg.B )
142 || ( *endpointA == *endpointB && aSeg.A == aSeg.B ) )
143 can_add = false;
144 }
145
146 if( can_add )
147 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( *endpointB, aSeg.B ) );
148 }
149
150 if( !containsA && !containsB && !endpointA && !endpointB )
151 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg ) );
152}
153
154
156 PCB_TEXT( aParent, aType ),
157 m_overrideTextEnabled( false ),
159 m_autoUnits( false ),
163 m_suppressZeroes( false ),
164 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
165 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
168 m_keepTextAligned( true ),
169 m_measuredValue( 0 ),
170 m_start( 0, 0 ),
171 m_end( 0, 0 ),
172 m_inClearRenderCache( false )
173{
175 m_busy = false;
176}
177
178
180{
181 if( const FOOTPRINT* fp = GetParentFootprint() )
182 return fp->GetTransform().Apply( m_start );
183
184 return m_start;
185}
186
187
189{
190 if( const FOOTPRINT* fp = GetParentFootprint() )
191 return fp->GetTransform().Apply( m_end );
192
193 return m_end;
194}
195
196
198{
199 if( const FOOTPRINT* fp = GetParentFootprint() )
200 m_start = fp->GetTransform().InverseApply( aPoint );
201 else
202 m_start = aPoint;
203}
204
205
207{
208 if( const FOOTPRINT* fp = GetParentFootprint() )
209 m_end = fp->GetTransform().InverseApply( aPoint );
210 else
211 m_end = aPoint;
212}
213
214
215void PCB_DIMENSION_BASE::OnFootprintRescaled( double /* aRatioX */, double /* aRatioY */, double /* aLinearFactor */,
216 const VECTOR2I& /* aAnchor */, const EDA_ANGLE& /* aParentRotate */ )
217{
220}
221
222
230
231
233{
234 if( Type() != aOther.Type() )
235 return false;
236
237 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
238
239 return *this == other;
240}
241
242
244{
245 if( m_textPosition != aOther.m_textPosition )
246 return false;
247
249 return false;
250
251 if( m_units != aOther.m_units )
252 return false;
253
254 if( m_autoUnits != aOther.m_autoUnits )
255 return false;
256
257 if( m_unitsFormat != aOther.m_unitsFormat )
258 return false;
259
260 if( m_precision != aOther.m_precision )
261 return false;
262
263 if( m_suppressZeroes != aOther.m_suppressZeroes )
264 return false;
265
266 if( m_lineThickness != aOther.m_lineThickness )
267 return false;
268
269 if( m_arrowLength != aOther.m_arrowLength )
270 return false;
271
273 return false;
274
275 if( m_measuredValue != aOther.m_measuredValue )
276 return false;
277
278 return EDA_TEXT::operator==( aOther );
279}
280
281
282double PCB_DIMENSION_BASE::Similarity( const BOARD_ITEM& aOther ) const
283{
284 if( m_Uuid == aOther.m_Uuid )
285 return 1.0;
286
287 if( Type() != aOther.Type() )
288 return 0.0;
289
290 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
291
292 double similarity = 1.0;
293
294 if( m_textPosition != other.m_textPosition )
295 similarity *= 0.9;
296
298 similarity *= 0.9;
299
300 if( m_units != other.m_units )
301 similarity *= 0.9;
302
303 if( m_autoUnits != other.m_autoUnits )
304 similarity *= 0.9;
305
306 if( m_unitsFormat != other.m_unitsFormat )
307 similarity *= 0.9;
308
309 if( m_precision != other.m_precision )
310 similarity *= 0.9;
311
313 similarity *= 0.9;
314
315 if( m_lineThickness != other.m_lineThickness )
316 similarity *= 0.9;
317
318 if( m_arrowLength != other.m_arrowLength )
319 similarity *= 0.9;
320
322 similarity *= 0.9;
323
324 if( m_measuredValue != other.m_measuredValue )
325 similarity *= 0.9;
326
327 similarity *= EDA_TEXT::Similarity( other );
328
329 return similarity;
330}
331
332
333void PCB_DIMENSION_BASE::Serialize( google::protobuf::Any &aContainer ) const
334{
335 using namespace kiapi::common;
336 using namespace kiapi::board::types;
337 Dimension dimension;
338
339 dimension.mutable_id()->set_value( m_Uuid.AsStdString() );
340 dimension.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
341 dimension.set_locked( IsLocked() ? types::LockedState::LS_LOCKED
342 : types::LockedState::LS_UNLOCKED );
343
344 EDA_TEXT::Serialize( *dimension.mutable_text(), pcbIUScale );
345
346 types::Text* text = dimension.mutable_text();
347 text->set_text( GetValueText() );
348
349 dimension.set_override_text_enabled( m_overrideTextEnabled );
350 dimension.set_override_text( m_valueString.ToUTF8() );
351 dimension.set_prefix( m_prefix.ToUTF8() );
352 dimension.set_suffix( m_suffix.ToUTF8() );
353
355 dimension.set_unit_format(
357 dimension.set_arrow_direction(
360 dimension.set_suppress_trailing_zeroes( m_suppressZeroes );
361
362 if( FOOTPRINT* parent = GetParentFootprint() )
363 dimension.mutable_parent()->set_value( parent->m_Uuid.AsStdString() );
364 else if( const BOARD* board = GetBoard() )
365 dimension.mutable_parent()->set_value( board->m_Uuid.AsStdString() );
366
367 dimension.mutable_line_thickness()->set_value_nm( m_lineThickness );
368 dimension.mutable_arrow_length()->set_value_nm( m_arrowLength );
369 dimension.mutable_extension_offset()->set_value_nm( m_extensionOffset );
370 dimension.set_text_position(
372 dimension.set_keep_text_aligned( m_keepTextAligned );
373
374 kiapi::common::PackCustomProperties( dimension.mutable_custom_properties(), *this );
375 aContainer.PackFrom( dimension );
376}
377
378
379bool PCB_DIMENSION_BASE::Deserialize( const google::protobuf::Any &aContainer )
380{
381 using namespace kiapi::common;
382 kiapi::board::types::Dimension dimension;
383
384 if( !aContainer.UnpackTo( &dimension ) )
385 return false;
386
388 SetUuidDirect( KIID( dimension.id().value() ) );
389 SetLocked( dimension.locked() == types::LockedState::LS_LOCKED );
390
391 EDA_TEXT::Deserialize( dimension.text(), pcbIUScale );
392
393 SetOverrideTextEnabled( dimension.override_text_enabled() );
394 SetOverrideText( wxString::FromUTF8( dimension.override_text() ) );
395 SetPrefix( wxString::FromUTF8( dimension.prefix() ) );
396 SetSuffix( wxString::FromUTF8( dimension.suffix() ) );
397
398 SetUnitsMode( FromProtoEnum<DIM_UNITS_MODE>( dimension.unit() ) );
399 SetUnitsFormat( FromProtoEnum<DIM_UNITS_FORMAT>( dimension.unit_format() ) );
400 SetArrowDirection( FromProtoEnum<DIM_ARROW_DIRECTION>( dimension.arrow_direction() ) );
401 SetPrecision( FromProtoEnum<DIM_PRECISION>( dimension.precision() ) );
402 SetSuppressZeroes( dimension.suppress_trailing_zeroes() );
403
404 SetLineThickness( dimension.line_thickness().value_nm() );
405 SetArrowLength( dimension.arrow_length().value_nm() );
406 SetExtensionOffset( dimension.extension_offset().value_nm() );
407 SetTextPositionMode( FromProtoEnum<DIM_TEXT_POSITION>( dimension.text_position() ) );
408 SetKeepTextAligned( dimension.keep_text_aligned() );
409
410 kiapi::common::UnpackCustomProperties( dimension.custom_properties(), *this );
411
412 Update();
413
414 return true;
415}
416
417
418void PCB_DIMENSION_BASE::drawAnArrow( VECTOR2I startPoint, EDA_ANGLE anAngle, int aLength )
419{
420 if( aLength )
421 {
422 VECTOR2I tailEnd( aLength, 0 );
423 RotatePoint( tailEnd, -anAngle );
424 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + tailEnd ) );
425 }
426
427 VECTOR2I arrowEndPos( m_arrowLength, 0 );
428 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
429
430 RotatePoint( arrowEndPos, -anAngle + s_arrowAngle );
431 RotatePoint( arrowEndNeg, -anAngle - s_arrowAngle );
432
433 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndPos ) );
434 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndNeg ) );
435}
436
437
439{
441
442 switch( m_unitsFormat )
443 {
444 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
445 break;
446
447 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
449 break;
450
451 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
452 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
453 break;
454 }
455
456 text.Prepend( m_prefix );
457 text.Append( m_suffix );
458
459 SetText( text );
460}
461
462
464{
466
467 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
468 // have changed and we may need to update the dimension text
469
471 {
473 Update();
474 m_inClearRenderCache = false;
475 }
476}
477
478
479template<typename ShapeType>
480void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
481{
482 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
483}
484
485
487{
488 struct lconv* lc = localeconv();
489 wxChar sep = lc->decimal_point[0];
490
491 int val = GetMeasuredValue();
492 int precision = static_cast<int>( m_precision );
493 wxString text;
494
495 if( precision >= 6 )
496 {
497 switch( m_units )
498 {
499 case EDA_UNITS::INCH: precision = precision - 4; break;
500 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
501 case EDA_UNITS::MM: precision = precision - 5; break;
502 default: precision = precision - 4; break;
503 }
504 }
505
506 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
507
508 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
509
510 if( m_suppressZeroes )
511 {
512 while( text.EndsWith( '0' ) )
513 {
514 text.RemoveLast();
515
516 if( text.EndsWith( '.' ) || text.EndsWith( sep ) )
517 {
518 text.RemoveLast();
519 break;
520 }
521 }
522 }
523
524 return text;
525}
526
527
529{
530 // Read only here but shared lookup helpers require a mutable board pointer
531 BOARD* board = const_cast<BOARD*>( GetBoard() );
532
533 return DimensionValueMode( board, this );
534}
535
536
542
543
545{
546 switch( GetValueMode() )
547 {
549 {
550 PCB_CONSTRAINT* lengthConstraint =
551 FindDimensionLengthConstraint( const_cast<BOARD*>( GetBoard() ), this );
552
553 if( lengthConstraint && lengthConstraint->GetValue() )
554 {
556 *lengthConstraint->GetValue() );
557 }
558
559 return GetValueText();
560 }
561
563 return GetOverrideText();
564
566 default:
567 return GetValueText();
568 }
569}
570
571
572void PCB_DIMENSION_BASE::ChangeValueFieldText( const wxString& aText )
573{
575 {
576 SetOverrideText( aText );
577 Update();
578 }
579}
580
581
582void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
583{
584 m_prefix = aPrefix;
585}
586
587
588void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
589{
590 m_suffix = aSuffix;
591}
592
593
595{
596 m_units = aUnits;
597}
598
599
601{
602 if( m_autoUnits )
603 {
605 }
606 else
607 {
608 switch( m_units )
609 {
610 default:
614 }
615 }
616}
617
618
620{
621 switch( aMode )
622 {
624 m_autoUnits = false;
626 break;
627
629 m_autoUnits = false;
631 break;
632
634 m_autoUnits = false;
636 break;
637
639 m_autoUnits = true;
641 break;
642 }
643}
644
645
647{
648 SetTextAngleDegrees( aDegrees );
649 // Create or repair any knockouts
650 Update();
651}
652
653
655{
656 SetKeepTextAligned( aKeepAligned );
657 // Re-align the text and repair any knockouts
658 Update();
659}
660
661
663{
664 PCB_TEXT::Offset( offset );
665
666 if( const FOOTPRINT* fp = GetParentFootprint() )
667 {
668 const TRANSFORM_TRS& xform = fp->GetTransform();
669 VECTOR2I libOffset = xform.InverseApply( offset ) - xform.InverseApply( VECTOR2I( 0, 0 ) );
670 m_start += libOffset;
671 m_end += libOffset;
672 }
673 else
674 {
675 m_start += offset;
676 m_end += offset;
677 }
678
679 Update();
680}
681
682
683void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
684{
685 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
686 newAngle.Normalize();
687 SetTextAngle( newAngle );
688
689 VECTOR2I pt = GetTextPos();
690 RotatePoint( pt, aRotCentre, aAngle );
691 SetTextPos( pt );
692
693 VECTOR2I boardStart = GetStart();
694 VECTOR2I boardEnd = GetEnd();
695 RotatePoint( boardStart, aRotCentre, aAngle );
696 RotatePoint( boardEnd, aRotCentre, aAngle );
697
698 if( const FOOTPRINT* fp = GetParentFootprint() )
699 {
700 m_start = fp->GetTransform().InverseApply( boardStart );
701 m_end = fp->GetTransform().InverseApply( boardEnd );
702 }
703 else
704 {
705 m_start = boardStart;
706 m_end = boardEnd;
707 }
708
709 Update();
710}
711
712
713void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
714{
715 Mirror( aCentre, aFlipDirection );
716
718}
719
720
721void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
722{
723 if( const FOOTPRINT* fp = GetParentFootprint() )
724 {
725 const VECTOR2I libAxis = fp->GetTransform().InverseApply( axis_pos );
726
727 auto mirrorPt = [&]( VECTOR2I& p )
728 {
729 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
730 p.x = 2 * libAxis.x - p.x;
731 else
732 p.y = 2 * libAxis.y - p.y;
733 };
734
735 mirrorPt( m_start );
736 mirrorPt( m_end );
737
738 VECTOR2I libTextPos = EDA_TEXT::GetTextPos();
739 mirrorPt( libTextPos );
740 SetLibTextPos( libTextPos );
741
742 EDA_ANGLE newLibAngle =
744 SetLibTextAngle( newLibAngle );
745
746 if( IsSideSpecific() )
748
750 Update();
751 return;
752 }
753
754 VECTOR2I newPos = GetTextPos();
755
756 MIRROR( newPos, axis_pos, aFlipDirection );
757
758 SetTextPos( newPos );
759
760 // invert angle
762
763 MIRROR( m_start, axis_pos, aFlipDirection );
764 MIRROR( m_end, axis_pos, aFlipDirection );
765
766 if( IsSideSpecific() )
768
769 Update();
770}
771
772
773void PCB_DIMENSION_BASE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
774{
775 PCB_TEXT::StyleFromSettings( settings, aCheckSide );
776
784
785 Update(); // refresh text & geometry
786
787}
788
789
791 std::vector<MSG_PANEL_ITEM>& aList )
792{
793 // for now, display only the text within the DIMENSION using class PCB_TEXT.
794 wxString msg;
795
796 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
797
798 // Don't use GetShownText(); we want to see the variable references here
799 aList.emplace_back( _( "Dimension" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
800
801 aList.emplace_back( _( "Prefix" ), GetPrefix() );
802
804 {
805 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
806 }
807 else
808 {
809 aList.emplace_back( _( "Value" ), GetValueText() );
810
811 switch( GetPrecision() )
812 {
813 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
814 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
815 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
816 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
817 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
818 }
819
820 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
821 }
822
823 aList.emplace_back( _( "Suffix" ), GetSuffix() );
824
825 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
826 // in frame's units.
827 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
828 unitsProvider.SetUserUnits( GetUnits() );
829
830 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
831
832 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
833 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
834 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
835 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
836
837 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
838
839 if( Type() == PCB_DIM_CENTER_T )
840 {
841 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
842 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
843 aFrame->MessageTextFromValue( startCoord.x ),
844 aFrame->MessageTextFromValue( startCoord.y ) );
845
846 aList.emplace_back( start, wxEmptyString );
847 }
848 else
849 {
850 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
851 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
852 aFrame->MessageTextFromValue( startCoord.x ),
853 aFrame->MessageTextFromValue( startCoord.y ) );
854 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
855 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
856 aFrame->MessageTextFromValue( endCoord.x ),
857 aFrame->MessageTextFromValue( endCoord.y ) );
858
859 aList.emplace_back( start, end );
860 }
861
862 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
863 aList.emplace_back( _( "Status" ), _( "Locked" ) );
864
865 aList.emplace_back( _( "Layer" ), GetLayerName() );
866}
867
868
870{
871 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
872
873 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
874
875 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
876 effectiveShape->AddShape( shape->Clone() );
877
878 return effectiveShape;
879}
880
881
882bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
883{
884 if( TextHitTest( aPosition ) )
885 return true;
886
887 int dist_max = aAccuracy + ( m_lineThickness / 2 );
888
889 // Locate SEGMENTS
890
891 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
892 {
893 if( shape->Collide( aPosition, dist_max ) )
894 return true;
895 }
896
897 return false;
898}
899
900
901bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
902{
903 BOX2I arect = aRect;
904 arect.Inflate( aAccuracy );
905
906 BOX2I rect = GetBoundingBox();
907
908 if( aAccuracy )
909 rect.Inflate( aAccuracy );
910
911 if( aContained )
912 return arect.Contains( rect );
913
914 return arect.Intersects( rect );
915}
916
917
918bool PCB_DIMENSION_BASE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
919{
920 // Note: Can't use GetEffectiveShape() because we want text as BoundingBox, not as graphics.
921 SHAPE_COMPOUND effShape;
922
923 // Add shapes
924 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
925 effShape.AddShape( shape );
926
927 if( aContained )
928 return TextHitTest( aPoly, aContained ) && KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
929 else
930 return TextHitTest( aPoly, aContained ) || KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
931}
932
933
935{
936 BOX2I bBox;
937 int xmin, xmax, ymin, ymax;
938
939 bBox = GetTextBox( nullptr );
940 xmin = bBox.GetX();
941 xmax = bBox.GetRight();
942 ymin = bBox.GetY();
943 ymax = bBox.GetBottom();
944
945 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
946 {
947 BOX2I shapeBox = shape->BBox();
948 shapeBox.Inflate( m_lineThickness / 2 );
949
950 xmin = std::min( xmin, shapeBox.GetOrigin().x );
951 xmax = std::max( xmax, shapeBox.GetEnd().x );
952 ymin = std::min( ymin, shapeBox.GetOrigin().y );
953 ymax = std::max( ymax, shapeBox.GetEnd().y );
954 }
955
956 bBox.SetX( xmin );
957 bBox.SetY( ymin );
958 bBox.SetWidth( xmax - xmin + 1 );
959 bBox.SetHeight( ymax - ymin + 1 );
960
961 bBox.Normalize();
962
963 return bBox;
964}
965
966
967wxString PCB_DIMENSION_BASE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
968{
969 return wxString::Format( _( "Dimension '%s' on %s" ),
971 GetLayerName() );
972}
973
974
975
977{
979 VECTOR2I( GetBoundingBox().GetSize() ) );
980 dimBBox.Merge( PCB_TEXT::ViewBBox() );
981
982 return dimBBox;
983}
984
985
986std::vector<int> PCB_DIMENSION_BASE::ViewGetLayers() const
987{
988 std::vector<int> layers = PCB_TEXT::ViewGetLayers();
989
990 // Always advertised while ViewGetLOD gates the draw on actual constraint reference
991 layers.push_back( LAYER_CONSTRAINT_SHADOW );
992
993 return layers;
994}
995
996
997double PCB_DIMENSION_BASE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
998{
999 if( aLayer == LAYER_CONSTRAINT_SHADOW && aView )
1000 {
1001 KIGFX::PCB_RENDER_SETTINGS& renderSettings =
1002 *static_cast<KIGFX::PCB_PAINTER&>( *aView->GetPainter() ).GetSettings();
1003
1004 if( !renderSettings.GetConstrainedItems().count( m_Uuid ) )
1005 return LOD_HIDE;
1006
1007 if( !aView->IsLayerVisibleCached( GetLayer() ) )
1008 return LOD_HIDE;
1009
1010 if( renderSettings.GetHighContrast() && GetLayer() != renderSettings.GetPrimaryHighContrastLayer() )
1011 return LOD_HIDE;
1012
1013 return LOD_SHOW;
1014 }
1015
1016 return PCB_TEXT::ViewGetLOD( aLayer, aView );
1017}
1018
1019
1020double PCB_DIMENSION_BASE::GetCoverageArea( int aTextMargin ) const
1021{
1022 // A dimension covers its whole drawing, not only the value text it inherits from
1023 return BOARD_ITEM::GetCoverageArea( aTextMargin );
1024}
1025
1026
1028 int aClearance, int aError, ERROR_LOC aErrorLoc,
1029 bool aIgnoreLineWidth ) const
1030{
1031 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
1032
1033 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
1034 {
1035 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
1036 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
1037
1038 if( circle )
1039 {
1040 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
1041 circle->GetRadius() + m_lineThickness / 2 + aClearance,
1042 aError, aErrorLoc );
1043 }
1044 else if( seg )
1045 {
1046 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
1047 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
1048 }
1049 else
1050 {
1051 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
1052 }
1053 }
1054}
1055
1056
1058 PCB_DIMENSION_BASE( aParent, aType ),
1059 m_height( 0 )
1060{
1061 // To preserve look of old dimensions, initialize extension height based on default arrow length
1062 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1063}
1064
1065
1067{
1068 return new PCB_DIM_ALIGNED( *this );
1069}
1070
1071
1073{
1074 wxCHECK( aOther && aOther->Type() == PCB_DIM_ALIGNED_T, /* void */ );
1075 *this = *static_cast<const PCB_DIM_ALIGNED*>( aOther );
1076}
1077
1078void PCB_DIM_ALIGNED::Serialize( google::protobuf::Any &aContainer ) const
1079{
1080 using namespace kiapi::common;
1081 kiapi::board::types::Dimension dimension;
1082
1083 PCB_DIMENSION_BASE::Serialize( aContainer );
1084 aContainer.UnpackTo( &dimension );
1085
1086 PackVector2( *dimension.mutable_aligned()->mutable_start(), GetStart() );
1087 PackVector2( *dimension.mutable_aligned()->mutable_end(), GetEnd() );
1088 dimension.mutable_aligned()->mutable_height()->set_value_nm( m_height );
1089 dimension.mutable_aligned()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1090
1091 aContainer.PackFrom( dimension );
1092}
1093
1094
1095bool PCB_DIM_ALIGNED::Deserialize( const google::protobuf::Any &aContainer )
1096{
1097 using namespace kiapi::common;
1098
1099 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1100 return false;
1101
1102 kiapi::board::types::Dimension dimension;
1103 aContainer.UnpackTo( &dimension );
1104
1105 if( !dimension.has_aligned() )
1106 return false;
1107
1108 SetStart( UnpackVector2( dimension.aligned().start() ) );
1109 SetEnd( UnpackVector2( dimension.aligned().end() ) );
1110 SetHeight( dimension.aligned().height().value_nm());
1111 SetExtensionHeight( dimension.aligned().extension_height().value_nm() );
1112
1113 Update();
1114
1115 return true;
1116}
1117
1118
1120{
1121 wxASSERT( aImage->Type() == Type() );
1122
1123 m_shapes.clear();
1124 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
1125
1126 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
1127
1128 Update();
1129}
1130
1131
1132void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1133{
1134 m_height = -m_height;
1135 // Call this last for the Update()
1136 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1137}
1138
1139
1144
1145
1146void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
1147{
1148 VECTOR2D height( aCrossbarStart - GetStart() );
1149 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
1150
1151 if( height.Cross( crossBar ) > 0 )
1152 m_height = -height.EuclideanNorm();
1153 else
1154 m_height = height.EuclideanNorm();
1155
1156 Update();
1157}
1158
1159
1161{
1162 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1163 return;
1164
1165 m_busy = true;
1166
1167 m_shapes.clear();
1168
1169 const VECTOR2I start = GetStart();
1170 const VECTOR2I end = GetEnd();
1171 VECTOR2I dimension( end - start );
1172
1173 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
1174
1175 VECTOR2I extension;
1176
1177 if( m_height > 0 )
1178 extension = VECTOR2I( -dimension.y, dimension.x );
1179 else
1180 extension = VECTOR2I( dimension.y, -dimension.x );
1181
1182 // Add extension lines
1183 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1184
1185 VECTOR2I extStart( start );
1186 extStart += extension.Resize( m_extensionOffset );
1187
1188 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1189
1190 extStart = VECTOR2I( end );
1191 extStart += extension.Resize( m_extensionOffset );
1192
1193 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1194
1195 // Add crossbar
1196 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1197 m_crossBarStart = start + crossBarDistance;
1198 m_crossBarEnd = end + crossBarDistance;
1199
1200 // Update text after calculating crossbar position but before adding crossbar lines
1201 updateText();
1202
1203 // Now that we have the text updated, we can determine how to draw the crossbar.
1204 // First we need to create an appropriate bounding polygon to collide with
1205 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, - GetEffectiveTextPenWidth() );
1206
1207 SHAPE_POLY_SET polyBox;
1208 polyBox.NewOutline();
1209 polyBox.Append( textBox.GetOrigin() );
1210 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1211 polyBox.Append( textBox.GetEnd() );
1212 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1213 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1214
1215 // The ideal crossbar, if the text doesn't collide
1216 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1217
1218 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1219
1221 {
1222 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ),
1224 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ),
1226 }
1227 else
1228 {
1229 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ), 0 );
1230 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ), 0 );
1231 }
1232
1233 m_busy = false;
1234}
1235
1236
1238{
1239 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1240
1242 {
1243 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1244 EDA_ANGLE rotation;
1245
1246 if( crossbarCenter.x == 0 )
1247 rotation = ANGLE_90 * sign( -crossbarCenter.y );
1248 else if( crossbarCenter.x < 0 )
1249 rotation = -ANGLE_90;
1250 else
1251 rotation = ANGLE_90;
1252
1253 VECTOR2I textOffset = crossbarCenter;
1254 RotatePoint( textOffset, rotation );
1255 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
1256
1257 SetTextPos( m_crossBarStart + textOffset );
1258 }
1260 {
1261 SetTextPos( m_crossBarStart + crossbarCenter );
1262 }
1263
1264 if( m_keepTextAligned )
1265 {
1266 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
1267 textAngle.Normalize();
1268
1269 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1270 textAngle -= ANGLE_180;
1271
1272 SetTextAngle( textAngle );
1273 }
1274
1276}
1277
1278
1279void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1280{
1281 PCB_DIMENSION_BASE::GetMsgPanelInfo( aFrame, aList );
1282
1283 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
1284 // in frame's units.
1285 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
1286 unitsProvider.SetUserUnits( GetUnits() );
1287
1288 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
1289}
1290
1291
1294{
1295 // To preserve look of old dimensions, initialize extension height based on default arrow length
1296 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1298}
1299
1300
1302{
1303 return new PCB_DIM_ORTHOGONAL( *this );
1304}
1305
1306
1308{
1309 wxCHECK( aOther && aOther->Type() == PCB_DIM_ORTHOGONAL_T, /* void */ );
1310 *this = *static_cast<const PCB_DIM_ORTHOGONAL*>( aOther );
1311}
1312
1313void PCB_DIM_ORTHOGONAL::Serialize( google::protobuf::Any &aContainer ) const
1314{
1315 using namespace kiapi::common;
1316 kiapi::board::types::Dimension dimension;
1317
1318 PCB_DIMENSION_BASE::Serialize( aContainer );
1319 aContainer.UnpackTo( &dimension );
1320
1321 PackVector2( *dimension.mutable_orthogonal()->mutable_start(), GetStart() );
1322 PackVector2( *dimension.mutable_orthogonal()->mutable_end(), GetEnd() );
1323 dimension.mutable_orthogonal()->mutable_height()->set_value_nm( m_height );
1324 dimension.mutable_orthogonal()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1325
1326 dimension.mutable_orthogonal()->set_alignment( m_orientation == DIR::VERTICAL
1327 ? types::AxisAlignment::AA_Y_AXIS
1328 : types::AxisAlignment::AA_X_AXIS );
1329 aContainer.PackFrom( dimension );
1330}
1331
1332
1333bool PCB_DIM_ORTHOGONAL::Deserialize( const google::protobuf::Any &aContainer )
1334{
1335 using namespace kiapi::common;
1336
1337 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1338 return false;
1339
1340 kiapi::board::types::Dimension dimension;
1341 aContainer.UnpackTo( &dimension );
1342
1343 if( !dimension.has_orthogonal() )
1344 return false;
1345
1346 SetStart( UnpackVector2( dimension.orthogonal().start() ) );
1347 SetEnd( UnpackVector2( dimension.orthogonal().end() ) );
1348 SetHeight( dimension.orthogonal().height().value_nm());
1349 SetExtensionHeight( dimension.orthogonal().extension_height().value_nm() );
1350 SetOrientation( dimension.orthogonal().alignment() == types::AxisAlignment::AA_Y_AXIS
1352 : DIR::HORIZONTAL );
1353
1354 Update();
1355
1356 return true;
1357}
1358
1359
1361{
1362 wxASSERT( aImage->Type() == Type() );
1363
1364 m_shapes.clear();
1365 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
1366
1367 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
1368 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
1369
1370 Update();
1371}
1372
1373
1374void PCB_DIM_ORTHOGONAL::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1375{
1376 // Only reverse the height if the height is aligned with the flip
1377 if( m_orientation == DIR::HORIZONTAL && aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
1378 m_height = -m_height;
1379 else if( m_orientation == DIR::VERTICAL && aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1380 m_height = -m_height;
1381
1382 // Call this last, as we need the Update()
1383 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1384}
1385
1386
1391
1392
1394{
1395 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1396 return;
1397
1398 m_busy = true;
1399 m_shapes.clear();
1400
1401 const VECTOR2I start = GetStart();
1402 const VECTOR2I end = GetEnd();
1403
1404 int measurement = ( m_orientation == DIR::HORIZONTAL ? end.x - start.x : end.y - start.y );
1406
1407 VECTOR2I extension;
1408
1410 extension = VECTOR2I( 0, m_height );
1411 else
1412 extension = VECTOR2I( m_height, 0 );
1413
1414 // Add first extension line
1415 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1416
1417 VECTOR2I extStart( start );
1418 extStart += extension.Resize( m_extensionOffset );
1419
1420 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1421
1422 // Add crossbar
1423 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1424 m_crossBarStart = start + crossBarDistance;
1425
1428 else
1430
1431 // Add second extension line (end to crossbar end)
1433 extension = VECTOR2I( 0, end.y - m_crossBarEnd.y );
1434 else
1435 extension = VECTOR2I( end.x - m_crossBarEnd.x, 0 );
1436
1437 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
1438
1439 extStart = VECTOR2I( m_crossBarEnd );
1440 extStart -= extension.Resize( m_extensionHeight );
1441
1442 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1443
1444 // Update text after calculating crossbar position but before adding crossbar lines
1445 updateText();
1446
1447 // Now that we have the text updated, we can determine how to draw the crossbar.
1448 // First we need to create an appropriate bounding polygon to collide with
1449 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1450
1451 SHAPE_POLY_SET polyBox;
1452 polyBox.NewOutline();
1453 polyBox.Append( textBox.GetOrigin() );
1454 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1455 polyBox.Append( textBox.GetEnd() );
1456 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1457 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1458
1459 // The ideal crossbar, if the text doesn't collide
1460 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1461
1462 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1463
1464 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
1465
1467 {
1468 // Arrows with fixed length.
1469 drawAnArrow( m_crossBarStart, crossBarAngle + EDA_ANGLE( 180 ),
1472 }
1473 else
1474 {
1475 drawAnArrow( m_crossBarStart, crossBarAngle, 0 );
1476 drawAnArrow( m_crossBarEnd, crossBarAngle + EDA_ANGLE( 180 ), 0 );
1477 }
1478
1479 m_busy = false;
1480}
1481
1482
1484{
1485 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1486
1488 {
1489 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1490
1491 VECTOR2I textOffset;
1492
1494 textOffset.y = -textOffsetDistance;
1495 else
1496 textOffset.x = -textOffsetDistance;
1497
1498 textOffset += crossbarCenter;
1499
1500 SetTextPos( m_crossBarStart + textOffset );
1501 }
1503 {
1504 SetTextPos( m_crossBarStart + crossbarCenter );
1505 }
1506
1507 if( m_keepTextAligned )
1508 {
1509 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
1511 else
1513 }
1514
1516}
1517
1518
1519void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1520{
1521 EDA_ANGLE angle( aAngle );
1522
1523 // restrict angle to -179.9 to 180.0 degrees
1524 angle.Normalize180();
1525
1526 // adjust orientation and height to new angle
1527 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
1528 // in the other cases we will use the nearest 90 degree angle to
1529 // choose at least an approximate axis for the target orientation
1530 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
1531 if( angle > ANGLE_45 && angle <= ANGLE_135 )
1532 {
1533 // about 90 degree
1535 {
1537 }
1538 else
1539 {
1541 m_height = -m_height;
1542 }
1543 }
1544 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
1545 {
1546 // about -90 degree
1548 {
1550 m_height = -m_height;
1551 }
1552 else
1553 {
1555 }
1556 }
1557 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
1558 {
1559 // about 180 degree
1560 m_height = -m_height;
1561 }
1562
1563 // this will update m_crossBarStart and m_crossbarEnd
1564 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
1565}
1566
1567
1578
1579
1581{
1582 wxCHECK( aOther && aOther->Type() == PCB_DIM_LEADER_T, /* void */ );
1583 *this = *static_cast<const PCB_DIM_LEADER*>( aOther );
1584}
1585
1586void PCB_DIM_LEADER::Serialize( google::protobuf::Any &aContainer ) const
1587{
1588 using namespace kiapi::common;
1589 kiapi::board::types::Dimension dimension;
1590
1591 PCB_DIMENSION_BASE::Serialize( aContainer );
1592 aContainer.UnpackTo( &dimension );
1593
1594 PackVector2( *dimension.mutable_leader()->mutable_start(), GetStart() );
1595 PackVector2( *dimension.mutable_leader()->mutable_end(), GetEnd() );
1596 dimension.mutable_leader()->set_border_style(
1598 m_textBorder ) );
1599
1600 aContainer.PackFrom( dimension );
1601}
1602
1603
1604bool PCB_DIM_LEADER::Deserialize( const google::protobuf::Any &aContainer )
1605{
1606 using namespace kiapi::common;
1607
1608 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1609 return false;
1610
1611 kiapi::board::types::Dimension dimension;
1612 aContainer.UnpackTo( &dimension );
1613
1614 if( !dimension.has_leader() )
1615 return false;
1616
1617 SetStart( UnpackVector2( dimension.leader().start() ) );
1618 SetEnd( UnpackVector2( dimension.leader().end() ) );
1619 SetTextBorder( FromProtoEnum<DIM_TEXT_BORDER>( dimension.leader().border_style() ) );
1620
1621 Update();
1622
1623 return true;
1624}
1625
1626
1628{
1629 return new PCB_DIM_LEADER( *this );
1630}
1631
1632
1634{
1635 wxASSERT( aImage->Type() == Type() );
1636
1637 m_shapes.clear();
1638 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
1639
1640 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
1641
1642 Update();
1643}
1644
1645
1650
1651
1653{
1654 // Our geometry is dependent on the size of the text, so just update the whole shebang
1656}
1657
1658
1660{
1661 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1662 return;
1663
1664 m_busy = true;
1665
1666 m_shapes.clear();
1667
1669
1670 // Now that we have the text updated, we can determine how to draw the second line
1671 // First we need to create an appropriate bounding polygon to collide with
1672 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1673
1674 SHAPE_POLY_SET polyBox;
1675 polyBox.NewOutline();
1676 polyBox.Append( textBox.GetOrigin() );
1677 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1678 polyBox.Append( textBox.GetEnd() );
1679 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1680 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1681
1682 const VECTOR2I boardStart = GetStart();
1683 const VECTOR2I boardEnd = GetEnd();
1684
1685 VECTOR2I firstLine( boardEnd - boardStart );
1686 VECTOR2I start( boardStart );
1687 start += firstLine.Resize( m_extensionOffset );
1688
1689 SEG arrowSeg( boardStart, boardEnd );
1690 SEG textSeg( boardEnd, GetTextPos() );
1691 OPT_VECTOR2I arrowSegEnd;
1692 OPT_VECTOR2I textSegEnd;
1693
1695 {
1696 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1697 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1698 CIRCLE circle( textBox.GetCenter(), radius );
1699
1700 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1701 textSegEnd = segCircleIntersection( circle, textSeg );
1702 }
1703 else
1704 {
1705 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1706 textSegEnd = segPolyIntersection( polyBox, textSeg );
1707 }
1708
1709 if( !arrowSegEnd )
1710 arrowSegEnd = boardEnd;
1711
1712 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1713
1714 drawAnArrow( start, EDA_ANGLE( firstLine ), 0 );
1715
1716 if( !GetText().IsEmpty() )
1717 {
1718 switch( m_textBorder )
1719 {
1721 {
1722 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1723 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1724
1725 break;
1726 }
1727
1729 {
1730 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1731 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1732 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1733
1734 break;
1735 }
1736
1737 default:
1738 break;
1739 }
1740 }
1741
1742 if( textSegEnd && *arrowSegEnd == boardEnd )
1743 m_shapes.emplace_back( new SHAPE_SEGMENT( boardEnd, *textSegEnd ) );
1744
1745 m_busy = false;
1746}
1747
1748
1749void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1750{
1751 // Don't use GetShownText(); we want to see the variable references here
1752 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1753
1754 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
1755
1756 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1757 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1758 aFrame->MessageTextFromValue( startCoord.x ),
1759 aFrame->MessageTextFromValue( startCoord.y ) );
1760
1761 aList.emplace_back( start, wxEmptyString );
1762
1763 aList.emplace_back( _( "Layer" ), GetLayerName() );
1764}
1765
1766
1776
1778{
1779 wxCHECK( aOther && aOther->Type() == PCB_DIM_RADIAL_T, /* void */ );
1780 *this = *static_cast<const PCB_DIM_RADIAL*>( aOther );
1781}
1782
1783void PCB_DIM_RADIAL::Serialize( google::protobuf::Any &aContainer ) const
1784{
1785 using namespace kiapi::common;
1786 kiapi::board::types::Dimension dimension;
1787
1788 PCB_DIMENSION_BASE::Serialize( aContainer );
1789 aContainer.UnpackTo( &dimension );
1790
1791 PackVector2( *dimension.mutable_radial()->mutable_center(), GetStart() );
1792 PackVector2( *dimension.mutable_radial()->mutable_radius_point(), GetEnd() );
1793 dimension.mutable_radial()->mutable_leader_length()->set_value_nm( m_leaderLength );
1794
1795 aContainer.PackFrom( dimension );
1796}
1797
1798
1799bool PCB_DIM_RADIAL::Deserialize( const google::protobuf::Any &aContainer )
1800{
1801 using namespace kiapi::common;
1802
1803 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1804 return false;
1805
1806 kiapi::board::types::Dimension dimension;
1807 aContainer.UnpackTo( &dimension );
1808
1809 if( !dimension.has_radial() )
1810 return false;
1811
1812 SetStart( UnpackVector2( dimension.radial().center() ) );
1813 SetEnd( UnpackVector2( dimension.radial().radius_point() ) );
1814 SetLeaderLength( dimension.radial().leader_length().value_nm() );
1815
1816 Update();
1817
1818 return true;
1819}
1820
1821
1823{
1824 return new PCB_DIM_RADIAL( *this );
1825}
1826
1827
1829{
1830 wxASSERT( aImage->Type() == Type() );
1831
1832 m_shapes.clear();
1833 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1834
1835 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1836
1837 Update();
1838}
1839
1840
1845
1846
1848{
1849 const VECTOR2I end = GetEnd();
1850 VECTOR2I radial( end - GetStart() );
1851
1852 return end + radial.Resize( m_leaderLength );
1853}
1854
1855
1857{
1858 if( m_keepTextAligned )
1859 {
1860 VECTOR2I textLine( GetTextPos() - GetKnee() );
1861 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1862
1863 textAngle.Normalize();
1864
1865 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1866 textAngle -= ANGLE_180;
1867
1868 // Round to nearest degree
1869 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1870
1871 SetTextAngle( textAngle );
1872 }
1873
1875}
1876
1877
1879{
1880 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1881 return;
1882
1883 m_busy = true;
1884
1885 m_shapes.clear();
1886
1887 const VECTOR2I boardStart = GetStart();
1888 const VECTOR2I boardEnd = GetEnd();
1889
1890 VECTOR2I center( boardStart );
1891 VECTOR2I centerArm( 0, m_arrowLength );
1892
1893 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1894
1895 RotatePoint( centerArm, -ANGLE_90 );
1896
1897 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1898
1899 VECTOR2I radius( boardEnd - boardStart );
1900
1901 m_measuredValue = KiROUND( radius.EuclideanNorm() );
1902
1903 updateText();
1904
1905 // Now that we have the text updated, we can determine how to draw the second line
1906 // First we need to create an appropriate bounding polygon to collide with
1907 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1908
1909 SHAPE_POLY_SET polyBox;
1910 polyBox.NewOutline();
1911 polyBox.Append( textBox.GetOrigin() );
1912 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1913 polyBox.Append( textBox.GetEnd() );
1914 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1915 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1916
1917 VECTOR2I radial( boardEnd - boardStart );
1918 radial = radial.Resize( m_leaderLength );
1919
1920 SEG arrowSeg( boardEnd, boardEnd + radial );
1921 SEG textSeg( arrowSeg.B, GetTextPos() );
1922
1923 CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
1924 CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
1925
1926 drawAnArrow( boardEnd, EDA_ANGLE( radial ), 0 );
1927
1928 m_busy = false;
1929}
1930
1931
1938
1940{
1941 wxCHECK( aOther && aOther->Type() == PCB_DIM_CENTER_T, /* void */ );
1942 *this = *static_cast<const PCB_DIM_CENTER*>( aOther );
1943}
1944
1945void PCB_DIM_CENTER::Serialize( google::protobuf::Any &aContainer ) const
1946{
1947 using namespace kiapi::common;
1948 kiapi::board::types::Dimension dimension;
1949
1950 PCB_DIMENSION_BASE::Serialize( aContainer );
1951 aContainer.UnpackTo( &dimension );
1952
1953 PackVector2( *dimension.mutable_center()->mutable_center(), GetStart() );
1954 PackVector2( *dimension.mutable_center()->mutable_end(), GetEnd() );
1955
1956 aContainer.PackFrom( dimension );
1957}
1958
1959
1960bool PCB_DIM_CENTER::Deserialize( const google::protobuf::Any &aContainer )
1961{
1962 using namespace kiapi::common;
1963
1964 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1965 return false;
1966
1967 kiapi::board::types::Dimension dimension;
1968 aContainer.UnpackTo( &dimension );
1969
1970 if( !dimension.has_center() )
1971 return false;
1972
1973 SetStart( UnpackVector2( dimension.center().center() ) );
1974 SetEnd( UnpackVector2( dimension.center().end() ) );
1975
1976 Update();
1977
1978 return true;
1979}
1980
1981
1983{
1984 return new PCB_DIM_CENTER( *this );
1985}
1986
1987
1989{
1990 wxASSERT( aImage->Type() == Type() );
1991
1992 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1993}
1994
1995
2000
2001
2003{
2004 BOX2I bBox;
2005 int xmin, xmax, ymin, ymax;
2006
2007 const VECTOR2I start = GetStart();
2008 xmin = start.x;
2009 xmax = start.x;
2010 ymin = start.y;
2011 ymax = start.y;
2012
2013 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
2014 {
2015 BOX2I shapeBox = shape->BBox();
2016 shapeBox.Inflate( m_lineThickness / 2 );
2017
2018 xmin = std::min( xmin, shapeBox.GetOrigin().x );
2019 xmax = std::max( xmax, shapeBox.GetEnd().x );
2020 ymin = std::min( ymin, shapeBox.GetOrigin().y );
2021 ymax = std::max( ymax, shapeBox.GetEnd().y );
2022 }
2023
2024 bBox.SetX( xmin );
2025 bBox.SetY( ymin );
2026 bBox.SetWidth( xmax - xmin + 1 );
2027 bBox.SetHeight( ymax - ymin + 1 );
2028
2029 bBox.Normalize();
2030
2031 return bBox;
2032}
2033
2034
2036{
2037 return GetBoundingBox();
2038}
2039
2040
2042{
2043 // Even if PCB_DIM_CENTER has no text, we still need to update its text position
2044 // so GetTextPos() users get a valid value. Required at least for lasso hit-testing.
2045 SetTextPos( GetStart() );
2046
2048}
2049
2050
2052{
2053 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
2054 return;
2055
2056 m_busy = true;
2057
2058 m_shapes.clear();
2059
2060 const VECTOR2I boardStart = GetStart();
2061 const VECTOR2I boardEnd = GetEnd();
2062 VECTOR2I center( boardStart );
2063 VECTOR2I arm( boardEnd - boardStart );
2064
2065 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
2066
2067 RotatePoint( arm, -ANGLE_90 );
2068
2069 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
2070
2071 updateText();
2072
2073 m_busy = false;
2074}
2075
2076
2077static struct DIMENSION_DESC
2078{
2080 {
2082 .Map( DIM_PRECISION::X, _HKI( "0" ) )
2083 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
2084 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
2085 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
2086 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
2087 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
2088 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
2089 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
2090 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
2091 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
2092
2094 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
2095 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
2096 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
2097
2099 .Map( DIM_UNITS_MODE::INCH, _HKI( "Inches" ) )
2100 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
2101 .Map( DIM_UNITS_MODE::MM, _HKI( "Millimeters" ) )
2102 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
2103
2105 .Map( DIM_ARROW_DIRECTION::INWARD, _HKI( "Inward" ) )
2106 .Map( DIM_ARROW_DIRECTION::OUTWARD, _HKI( "Outward" ) );
2107
2109 .Map( DIM_VALUE_MODE::DRIVEN, _HKI( "Driven" ) )
2110 .Map( DIM_VALUE_MODE::DRIVING, _HKI( "Driving" ) )
2111 .Map( DIM_VALUE_MODE::ARBITRARY, _HKI( "Arbitrary" ) );
2112
2121
2122 propMgr.Mask( TYPE_HASH( PCB_DIMENSION_BASE ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
2123
2124 const wxString groupDimension = _HKI( "Dimension Properties" );
2125
2126 auto isLeader =
2127 []( INSPECTABLE* aItem ) -> bool
2128 {
2129 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
2130 };
2131
2132 auto isNotLeader =
2133 []( INSPECTABLE* aItem ) -> bool
2134 {
2135 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
2136 };
2137
2138 auto isMultiArrowDirection =
2139 []( INSPECTABLE* aItem ) -> bool
2140 {
2141 return dynamic_cast<PCB_DIM_ALIGNED*>( aItem ) != nullptr;
2142 };
2143
2146 groupDimension )
2147 .SetAvailableFunc( isNotLeader );
2150 groupDimension )
2151 .SetAvailableFunc( isNotLeader );
2152
2153 auto hasValueMode =
2154 []( INSPECTABLE* aItem ) -> bool
2155 {
2156 return DimensionHasValueMode( dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) );
2157 };
2158
2159 // Value bearing dims use Value row instead while leaders keep Text below
2160 // Override Text left for centre mark only
2161 auto usesOverrideText =
2162 [isLeader, hasValueMode]( INSPECTABLE* aItem ) -> bool
2163 {
2164 return aItem && !isLeader( aItem ) && !hasValueMode( aItem );
2165 };
2166
2167 // Driving needs both endpoints bound to movable geometry
2168 // Dropdown always offers it so gate the transition here
2169 auto valueModeValidator =
2170 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2171 {
2172 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2173
2174 if( !dim )
2175 return std::nullopt;
2176
2177 int mode = 0;
2178
2179 if( aValue.CheckType<DIM_VALUE_MODE>() )
2180 mode = static_cast<int>( aValue.As<DIM_VALUE_MODE>() );
2181 else if( !aValue.GetAs( &mode ) )
2182 return std::nullopt;
2183
2184 if( mode == static_cast<int>( DIM_VALUE_MODE::DRIVING )
2185 && !DimensionCanDrive( dim->GetBoard(), dim ) )
2186 {
2187 return std::make_unique<VALIDATION_ERROR_MSG>(
2188 _( "Driving requires both dimension endpoints bound to objects" ) );
2189 }
2190
2191 return std::nullopt;
2192 };
2193
2194 // Driving edits length constraint which must stay positive
2195 // Catches zero and negative and stale exprs parsing to zero
2196 auto drivingValueValidator =
2197 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2198 {
2199 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2200
2201 if( !dim || dim->GetValueMode() != DIM_VALUE_MODE::DRIVING )
2202 return std::nullopt;
2203
2204 wxString text;
2205
2206 if( !aValue.GetAs( &text ) )
2207 return std::nullopt;
2208
2210
2211 if( !( iu > 0.0 ) )
2212 {
2213 return std::make_unique<VALIDATION_ERROR_MSG>(
2214 _( "Enter a positive length for a driving dimension" ) );
2215 }
2216
2217 return std::nullopt;
2218 };
2219
2220 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
2222 groupDimension )
2223 .SetAvailableFunc( usesOverrideText );
2224
2227 groupDimension )
2228 .SetAvailableFunc( hasValueMode )
2229 .SetValidator( std::move( valueModeValidator ) );
2230
2233 groupDimension )
2234 .SetAvailableFunc( hasValueMode )
2236 []( INSPECTABLE* aItem ) -> bool
2237 {
2238 // Driven mirrors measured geometry so grey it out since edit would not stick
2239 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2240 return dim && dim->GetValueMode() != DIM_VALUE_MODE::DRIVEN;
2241 } )
2242 .SetValidator( std::move( drivingValueValidator ) );
2243
2246 groupDimension )
2247 .SetAvailableFunc( isLeader );
2248
2251 groupDimension )
2252 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2255 groupDimension )
2256 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2259 groupDimension )
2260 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2261 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
2263 groupDimension )
2264 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2265
2268 groupDimension )
2269 .SetAvailableFunc( isMultiArrowDirection ).SetIsCopyable();
2270
2271 const wxString groupText = _HKI( "Text Properties" );
2272
2273 const auto isTextOrientationWriteable =
2274 []( INSPECTABLE* aItem ) -> bool
2275 {
2276 return !static_cast<PCB_DIMENSION_BASE*>( aItem )->GetKeepTextAligned();
2277 };
2278
2279 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Keep Aligned with Dimension" ),
2282 groupText );
2283
2284 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, double>( _HKI( "Orientation" ),
2288 groupText )
2289 .SetWriteableFunc( isTextOrientationWriteable );
2290 }
2292
2298
2299
2301{
2303 {
2314
2315 const wxString groupDimension = _HKI( "Dimension Properties" );
2316
2317 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
2320 groupDimension );
2321 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
2324 groupDimension );
2325
2327 _HKI( "Text" ),
2328 []( INSPECTABLE* aItem ) { return false; } );
2330 _HKI( "Vertical Justification" ),
2331 []( INSPECTABLE* aItem ) { return false; } );
2333 _HKI( "Hyperlink" ),
2334 []( INSPECTABLE* aItem ) { return false; } );
2336 _HKI( "Knockout" ),
2337 []( INSPECTABLE* aItem ) { return false; } );
2338 }
2340
2341
2343{
2345 {
2358
2360 _HKI( "Text" ),
2361 []( INSPECTABLE* aItem ) { return false; } );
2363 _HKI( "Vertical Justification" ),
2364 []( INSPECTABLE* aItem ) { return false; } );
2366 _HKI( "Hyperlink" ),
2367 []( INSPECTABLE* aItem ) { return false; } );
2369 _HKI( "Knockout" ),
2370 []( INSPECTABLE* aItem ) { return false; } );
2371 }
2373
2374
2376{
2378 {
2389
2390 const wxString groupDimension = _HKI( "Dimension Properties" );
2391
2392 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
2395 groupDimension );
2396
2398 _HKI( "Text" ),
2399 []( INSPECTABLE* aItem ) { return false; } );
2401 _HKI( "Vertical Justification" ),
2402 []( INSPECTABLE* aItem ) { return false; } );
2404 _HKI( "Hyperlink" ),
2405 []( INSPECTABLE* aItem ) { return false; } );
2407 _HKI( "Knockout" ),
2408 []( INSPECTABLE* aItem ) { return false; } );
2409 }
2411
2412
2414{
2416 {
2418 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
2419 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
2420 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
2421
2432
2433 const wxString groupDimension = _HKI( "Dimension Properties" );
2434
2437 groupDimension );
2438
2440 _HKI( "Text" ),
2441 []( INSPECTABLE* aItem ) { return false; } );
2443 _HKI( "Vertical Justification" ),
2444 []( INSPECTABLE* aItem ) { return false; } );
2446 _HKI( "Hyperlink" ),
2447 []( INSPECTABLE* aItem ) { return false; } );
2449 _HKI( "Knockout" ),
2450 []( INSPECTABLE* aItem ) { return false; } );
2451 }
2453
2455
2456
2458{
2460 {
2471
2472
2474 _HKI( "Text" ),
2475 []( INSPECTABLE* aItem ) { return false; } );
2477 _HKI( "Vertical Justification" ),
2478 []( INSPECTABLE* aItem ) { return false; } );
2480 _HKI( "Hyperlink" ),
2481 []( INSPECTABLE* aItem ) { return false; } );
2483 _HKI( "Knockout" ),
2484 []( INSPECTABLE* aItem ) { return false; } );
2485 }
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
BITMAPS
A list of all bitmap identifiers.
@ add_radial_dimension
@ add_aligned_dimension
@ add_center_dimension
@ add_orthogonal_dimension
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
Container for design settings for a BOARD object.
DIM_PRECISION m_DimensionPrecision
Number of digits after the decimal.
DIM_UNITS_FORMAT m_DimensionUnitsFormat
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
DIM_TEXT_POSITION m_DimensionTextPosition
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
friend class BOARD
Definition board_item.h:593
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:418
PCB_LAYER_ID m_layer
Definition board_item.h:586
bool IsLocked() const override
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual double GetCoverageArea(int aTextMargin) const
Return the board area this item covers, used to rank candidates under the cursor so a click on a smal...
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:374
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
bool IsSideSpecific() const
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
EDA_UNITS GetUserUnits()
Definition board.h:1030
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr void SetHeight(size_type val)
Definition box2.h:289
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr coord_type GetY() const
Definition box2.h:205
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr coord_type GetX() const
Definition box2.h:204
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr const Vec GetCenter() const
Definition box2.h:227
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr void SetWidth(size_type val)
Definition box2.h:284
constexpr void SetX(coord_type val)
Definition box2.h:274
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr void SetY(coord_type val)
Definition box2.h:279
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
constexpr coord_type GetBottom() const
Definition box2.h:219
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:243
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:228
double AsDegrees() const
Definition eda_angle.h:115
EDA_ANGLE Normalize180()
Definition eda_angle.h:273
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:98
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:609
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition eda_text.cpp:170
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:313
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:556
virtual int GetTextHeight() const
Definition eda_text.h:307
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition eda_text.cpp:200
KIFONT::FONT * GetFont() const
Definition eda_text.h:286
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:354
BOX2I GetTextBox(const RENDER_SETTINGS *aSettings, int aLine=-1) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition eda_text.cpp:754
virtual int GetTextWidth() const
Definition eda_text.h:304
virtual void ClearBoundingBoxCache()
Definition eda_text.cpp:675
double Similarity(const EDA_TEXT &aOther) const
virtual void ClearRenderCache()
Definition eda_text.cpp:669
bool IsMirrored() const
Definition eda_text.h:229
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:427
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, const BOX2I &aBBox=BOX2I(), const EDA_ANGLE &aAngle=ANGLE_0) const
Build a list of segments (SHAPE_SEGMENT) to describe a text shape.
void SetTextAngleDegrees(double aOrientation)
Definition eda_text.h:181
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
bool operator==(const EDA_TEXT &aRhs) const
Definition eda_text.h:444
static ENUM_MAP< T > & Instance()
Definition property.h:783
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
Contains methods for drawing PCB-specific items.
virtual PCB_RENDER_SETTINGS * GetSettings() override
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
Definition pcb_painter.h:84
const std::unordered_set< KIID > & GetConstrainedItems() const
PCB_LAYER_ID GetPrimaryHighContrastLayer() const
Return the board layer which is in high-contrast mode.
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:176
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:441
PAINTER * GetPainter() const
Return the painter object used by the view for drawing VIEW_ITEM objects.
Definition view.h:227
Definition kiid.h:46
A class to perform either relative or absolute display origin transforms for a single axis of a point...
T ToDisplayAbs(const T &aValue) const
A geometric constraint between board items (issue #2329).
std::optional< double > GetValue() const
Abstract dimension API.
EDA_UNITS GetUnits() const
bool m_autoUnits
If true, follow the currently selected UI units.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
void Update()
Update the dimension's cached text and geometry.
void ChangeSuffix(const wxString &aSuffix)
void OnFootprintRescaled(double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I &aAnchor, const EDA_ANGLE &aParentRotate) override
Apply a parent footprint scale to this item.
wxString GetOverrideText() const
wxString GetSuffix() const
std::vector< std::shared_ptr< SHAPE > > m_shapes
Internal cache of drawn shapes.
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
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 Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void ClearRenderCache() override
int m_lineThickness
Thickness used for all graphics in the dimension.
virtual void SetEnd(const VECTOR2I &aPoint)
void Move(const VECTOR2I &offset) override
Move this object.
void SetUnitsFormat(const DIM_UNITS_FORMAT aFormat)
bool m_suppressZeroes
Suppress trailing zeroes.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
void SetUnits(EDA_UNITS aUnits)
VECTOR2I m_start
Start, FP-relative when in a footprint, board absolute otherwise.
DIM_PRECISION m_precision
Number of digits to display after decimal.
virtual void SetStart(const VECTOR2I &aPoint)
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)
void SetExtensionOffset(int aOffset)
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
void SetSuppressZeroes(bool aSuppress)
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.
void ChangeArrowDirection(const DIM_ARROW_DIRECTION &aDirection)
bool GetKeepTextAligned() const
void OnFootprintTransformed() override
Hook for items inside a footprint to refresh after the FP transform changes (translate,...
void ChangeTextAngleDegrees(double aDegrees)
bool m_keepTextAligned
Calculate text orientation to match dimension.
DIM_PRECISION GetPrecision() const
wxString GetPrefix() const
void SetOverrideTextEnabled(bool aOverride)
void SetSuffix(const wxString &aSuffix)
bool operator==(const PCB_DIMENSION_BASE &aOther) const
void ChangeValueMode(DIM_VALUE_MODE aMode)
Property panel setter for value mode override text flag lives on dimension length constraint is board...
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
DIM_UNITS_MODE GetUnitsMode() const
void drawAnArrow(VECTOR2I aStartPoint, EDA_ANGLE anAngle, int aLength)
Draws an arrow and updates the shape container.
void SetTextPositionMode(DIM_TEXT_POSITION aMode)
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_VALUE_MODE GetValueMode() const
Value mode from board state via DimensionValueMode.
DIM_UNITS_FORMAT GetUnitsFormat() const
void SetLineThickness(int aWidth)
void SetArrowLength(int aLength)
DIM_ARROW_DIRECTION GetArrowDirection() const
wxString m_valueString
Displayed value when m_overrideValue = true.
virtual VECTOR2I GetEnd() const
void ChangePrecision(DIM_PRECISION aPrecision)
void SetPrecision(DIM_PRECISION aPrecision)
bool m_overrideTextEnabled
Manually specify the displayed measurement value.
DIM_UNITS_FORMAT m_unitsFormat
How to render the units suffix.
int GetMeasuredValue() const
bool GetSuppressZeroes() const
void SetArrowDirection(const DIM_ARROW_DIRECTION &aDirection)
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.
void SetOverrideText(const wxString &aValue)
wxString GetValueText() const
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
void ChangePrefix(const wxString &aPrefix)
wxString m_prefix
String prepended to the value.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
virtual VECTOR2I GetStart() const
The dimension's origin is the first feature point for the dimension.
DIM_ARROW_DIRECTION m_arrowDirection
direction of dimension arrow.
void ChangeKeepTextAligned(bool aKeepAligned)
void ChangeUnitsFormat(const DIM_UNITS_FORMAT aFormat)
wxString GetValueFieldText() const
Mode aware value for panel driving shows constraint length arbitrary shows override text otherwise sh...
void ChangeSuppressZeroes(bool aSuppress)
double GetCoverageArea(int aTextMargin) const override
Return the board area this item covers, used to rank candidates under the cursor so a click on a smal...
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.
void ChangeValueFieldText(const wxString &aText)
Property panel setter for value arbitrary text owned by dimension driving edits board level constrain...
double GetTextAngleDegreesProp() const
bool GetOverrideTextEnabled() const
void SetUnitsMode(DIM_UNITS_MODE aMode)
int m_arrowLength
Length of arrow shapes.
virtual void Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
VECTOR2I m_end
End, FP-relative when in a footprint, board absolute otherwise.
void ChangeUnitsMode(DIM_UNITS_MODE aMode)
void SetKeepTextAligned(bool aKeepAligned)
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
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.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
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).
void SetExtensionHeight(int aHeight)
VECTOR2I m_crossBarStart
Crossbar start control point.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
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.
void CopyFrom(const BOARD_ITEM *aOther) override
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
VECTOR2I m_crossBarEnd
Crossbar end control point.
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.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void CopyFrom(const BOARD_ITEM *aOther) override
virtual void swapData(BOARD_ITEM *aImage) override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
PCB_DIM_CENTER(BOARD_ITEM *aParent)
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
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
void CopyFrom(const BOARD_ITEM *aOther) override
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).
void SetTextBorder(DIM_TEXT_BORDER aBorder)
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 Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void ChangeTextBorder(DIM_TEXT_BORDER aBorder)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
void swapData(BOARD_ITEM *aImage) override
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
void CopyFrom(const BOARD_ITEM *aOther) override
void SetOrientation(DIR aOrientation)
Set the orientation of the dimension line (so, perpendicular to the feature lines).
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.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
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 Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
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 SetLeaderLength(int aLength)
void CopyFrom(const BOARD_ITEM *aOther) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void ChangeLeaderLength(int aLength)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
VECTOR2I GetKnee() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
Definition pcb_text.cpp:371
EDA_ANGLE GetLibTextAngle() const
Text angle in the parent footprint's lib frame, or absolute when not in a footprint.
Definition pcb_text.h:127
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition pcb_text.cpp:242
EDA_ANGLE GetTextAngle() const override
Definition pcb_text.cpp:560
void Offset(const VECTOR2I &aOffset) override
Definition pcb_text.cpp:525
void SetLibTextAngle(const EDA_ANGLE &aAngle)
Definition pcb_text.h:129
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition pcb_text.cpp:257
VECTOR2I GetTextPos() const override
Definition pcb_text.cpp:461
PCB_TEXT(BOARD_ITEM *parent, KICAD_T idtype=PCB_TEXT_T)
Definition pcb_text.cpp:49
void OnFootprintRescaled(double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I &aAnchor, const EDA_ANGLE &aParentRotate) override
Apply a parent footprint scale to this item.
Definition pcb_text.cpp:616
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
Definition pcb_text.cpp:248
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition pcb_text.cpp:426
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_text.cpp:695
int GetTextThickness() const override
Definition pcb_text.cpp:497
void SetTextAngle(const EDA_ANGLE &aAngle) override
Definition pcb_text.cpp:572
wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition pcb_text.cpp:178
void SetLibTextPos(const VECTOR2I &aPos)
Definition pcb_text.cpp:542
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:263
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition property.h:293
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:368
PROPERTY_BASE & SetIsCopyable(bool aIsCopyable=true)
Definition property.h:359
Provide class metadata.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
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:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
void AddShape(SHAPE *aShape)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void 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...
SEGMENT_ITERATOR_TEMPLATE< SEG > SEGMENT_ITERATOR
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.
SEGMENT_ITERATOR_TEMPLATE< const SEG > CONST_SEGMENT_ITERATOR
const SEG & GetSeg() const
VECTOR2I InverseApply(const VECTOR2I &aPoint) const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
void SetUserUnits(EDA_UNITS aUnits)
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition vector2d.h:559
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:281
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:406
@ FOR_GUI
Definition common.h:91
DIM_VALUE_MODE DimensionValueMode(BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
The value mode aDimension is in, derived from state: a self driving length means Driving,...
bool DimensionHasValueMode(const PCB_DIMENSION_BASE *aDimension)
True for dimension types with a measured value aligned orthogonal or radial offering the Driven Drivi...
PCB_CONSTRAINT * FindDimensionLengthConstraint(BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
Self FIXED_LENGTH constraint whose members are exactly aDimension START and END or nullptr the drivin...
bool DimensionCanDrive(BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
True when Driving mode may be offered for aDimension needs both endpoints bound via DimensionEndpoint...
DIM_VALUE_MODE
Mode a value bearing dimension value is in Driven mirrors measured geometry Driving forces geometry t...
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.
DRC_CONSTRAINT_T
Definition drc_rule.h:49
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
@ DEGREES_T
Definition eda_angle.h:30
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:445
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:444
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:449
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:453
static constexpr EDA_ANGLE FULL_CIRCLE
Definition eda_angle.h:446
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:452
static constexpr EDA_ANGLE ANGLE_135
Definition eda_angle.h:451
#define PCB_EDIT_FRAME_NAME
EDA_UNITS
Definition eda_units.h:44
a few functions useful in geometry calculations.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:179
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:180
@ LAYER_CONSTRAINT_SHADOW
Shadow layer for items bound to a constraint.
Definition layer_ids.h:320
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Dwgs_User
Definition layer_ids.h:103
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:41
FLIP_DIRECTION
Definition mirror.h:23
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:25
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
KICOMMON_API double ToUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Convert aValue in internal units to the appropriate user units defined by aUnit.
KICOMMON_API wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
bool ShapeHitTest(const SHAPE_LINE_CHAIN &aHitter, const SHAPE &aHittee, bool aHitteeContained)
Perform a shape-to-shape hit test.
KICOMMON_API wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
KICOMMON_API wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
KICOMMON_API void PackCustomProperties(google::protobuf::RepeatedPtrField< types::CustomProperty > *aOutput, const EDA_ITEM &aItem)
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void UnpackCustomProperties(const google::protobuf::RepeatedPtrField< types::CustomProperty > &aInput, EDA_ITEM &aItem)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
#define _HKI(x)
Definition page_info.cpp:40
static const int INWARD_ARROW_LENGTH_TO_HEAD_RATIO
static const EDA_ANGLE s_arrowAngle(27.5, DEGREES_T)
static struct DIMENSION_DESC _DIMENSION_DESC
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.
static OPT_VECTOR2I segCircleIntersection(CIRCLE &aCircle, SEG &aSeg, bool aStart=true)
static void CollectKnockedOutSegments(const SHAPE_POLY_SET &aPoly, const SEG &aSeg, std::vector< std::shared_ptr< SHAPE > > &aSegmentsAfterKnockout)
Knockout a polygon from a segment.
DIM_TEXT_POSITION
Where to place the text on a dimension.
@ 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.
DIM_UNITS_MODE
Used for storing the units selection in the file because EDA_UNITS alone doesn't cut it.
DIM_ARROW_DIRECTION
Used for dimension's arrow.
DIM_TEXT_BORDER
Frame to show around dimension text.
DIM_PRECISION
#define TYPE_HASH(x)
Macro to generate unique identifier for a type.
Definition property.h:74
#define ENUM_TO_WXANY(type)
Definition property.h:890
@ PT_DEGREE
Angle expressed in degrees.
Definition property.h:66
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
Helper macro to map type hashes to names.
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:35
VECTOR2I center
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
constexpr int sign(T val)
Definition util.h:166
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707