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>
40#include <geometry/shape_rect.h>
44#include <trigo.h>
45#include <api/api_enums.h>
46#include <api/api_utils.h>
47#include <api/board/board_types.pb.h>
48#include <properties/property.h>
51
54
55
57
58static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
59
60
69static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
70 bool aStart = true )
71{
72 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
73 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
74
75 if( aPoly.Contains( start ) )
76 return std::nullopt;
77
78 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
79 {
80 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
81 {
82 if( ( *intersection - start ).SquaredEuclideanNorm()
83 < ( endpoint - start ).SquaredEuclideanNorm() )
84 endpoint = *intersection;
85 }
86 }
87
88 if( start == endpoint )
89 return std::nullopt;
90
91 return OPT_VECTOR2I( endpoint );
92}
93
94
95static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true )
96{
97 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
98 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
99
100 if( aCircle.Contains( start ) )
101 return std::nullopt;
102
103 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
104
105 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
106 {
107 if( ( intersection - start ).SquaredEuclideanNorm()
108 < ( endpoint - start ).SquaredEuclideanNorm() )
109 endpoint = intersection;
110 }
111
112 if( start == endpoint )
113 return std::nullopt;
114
115 return OPT_VECTOR2I( endpoint );
116}
117
118
123static void CollectKnockedOutSegments( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
124 std::vector<std::shared_ptr<SHAPE>>& aSegmentsAfterKnockout )
125{
126 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
127 const bool containsA = aPoly.Contains( aSeg.A );
128 const bool containsB = aPoly.Contains( aSeg.B );
129
130 const OPT_VECTOR2I endpointA = segPolyIntersection( aPoly, aSeg );
131 const OPT_VECTOR2I endpointB = segPolyIntersection( aPoly, aSeg, false );
132
133 if( endpointA )
134 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg.A, *endpointA ) );
135
136 if( endpointB )
137 {
138 bool can_add = true;
139
140 if( endpointA )
141 {
142 if( ( *endpointB == aSeg.A && *endpointA == aSeg.B )
143 || ( *endpointA == *endpointB && aSeg.A == aSeg.B ) )
144 can_add = false;
145 }
146
147 if( can_add )
148 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( *endpointB, aSeg.B ) );
149 }
150
151 if( !containsA && !containsB && !endpointA && !endpointB )
152 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg ) );
153}
154
155
157 PCB_TEXT( aParent, aType ),
158 m_overrideTextEnabled( false ),
160 m_autoUnits( false ),
164 m_suppressZeroes( false ),
165 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
166 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
169 m_keepTextAligned( true ),
170 m_measuredValue( 0 ),
171 m_start( 0, 0 ),
172 m_end( 0, 0 ),
173 m_inClearRenderCache( false )
174{
176 m_busy = false;
177}
178
179
181{
182 if( const FOOTPRINT* fp = GetParentFootprint() )
183 return fp->GetTransform().Apply( m_start );
184
185 return m_start;
186}
187
188
190{
191 if( const FOOTPRINT* fp = GetParentFootprint() )
192 return fp->GetTransform().Apply( m_end );
193
194 return m_end;
195}
196
197
199{
200 if( const FOOTPRINT* fp = GetParentFootprint() )
201 m_start = fp->GetTransform().InverseApply( aPoint );
202 else
203 m_start = aPoint;
204}
205
206
208{
209 if( const FOOTPRINT* fp = GetParentFootprint() )
210 m_end = fp->GetTransform().InverseApply( aPoint );
211 else
212 m_end = aPoint;
213}
214
215
216void PCB_DIMENSION_BASE::OnFootprintRescaled( double /* aRatioX */, double /* aRatioY */, double /* aLinearFactor */,
217 const VECTOR2I& /* aAnchor */, const EDA_ANGLE& /* aParentRotate */ )
218{
221}
222
223
231
232
234{
235 if( Type() != aOther.Type() )
236 return false;
237
238 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
239
240 return *this == other;
241}
242
243
245{
246 if( m_textPosition != aOther.m_textPosition )
247 return false;
248
250 return false;
251
252 if( m_units != aOther.m_units )
253 return false;
254
255 if( m_autoUnits != aOther.m_autoUnits )
256 return false;
257
258 if( m_unitsFormat != aOther.m_unitsFormat )
259 return false;
260
261 if( m_precision != aOther.m_precision )
262 return false;
263
264 if( m_suppressZeroes != aOther.m_suppressZeroes )
265 return false;
266
267 if( m_lineThickness != aOther.m_lineThickness )
268 return false;
269
270 if( m_arrowLength != aOther.m_arrowLength )
271 return false;
272
274 return false;
275
276 if( m_measuredValue != aOther.m_measuredValue )
277 return false;
278
279 return EDA_TEXT::operator==( aOther );
280}
281
282
283double PCB_DIMENSION_BASE::Similarity( const BOARD_ITEM& aOther ) const
284{
285 if( m_Uuid == aOther.m_Uuid )
286 return 1.0;
287
288 if( Type() != aOther.Type() )
289 return 0.0;
290
291 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
292
293 double similarity = 1.0;
294
295 if( m_textPosition != other.m_textPosition )
296 similarity *= 0.9;
297
299 similarity *= 0.9;
300
301 if( m_units != other.m_units )
302 similarity *= 0.9;
303
304 if( m_autoUnits != other.m_autoUnits )
305 similarity *= 0.9;
306
307 if( m_unitsFormat != other.m_unitsFormat )
308 similarity *= 0.9;
309
310 if( m_precision != other.m_precision )
311 similarity *= 0.9;
312
314 similarity *= 0.9;
315
316 if( m_lineThickness != other.m_lineThickness )
317 similarity *= 0.9;
318
319 if( m_arrowLength != other.m_arrowLength )
320 similarity *= 0.9;
321
323 similarity *= 0.9;
324
325 if( m_measuredValue != other.m_measuredValue )
326 similarity *= 0.9;
327
328 similarity *= EDA_TEXT::Similarity( other );
329
330 return similarity;
331}
332
333
334void PCB_DIMENSION_BASE::Serialize( google::protobuf::Any &aContainer ) const
335{
336 using namespace kiapi::common;
337 using namespace kiapi::board::types;
338 Dimension dimension;
339
340 dimension.mutable_id()->set_value( m_Uuid.AsStdString() );
341 dimension.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
342 dimension.set_locked( IsLocked() ? types::LockedState::LS_LOCKED
343 : types::LockedState::LS_UNLOCKED );
344
345 EDA_TEXT::Serialize( *dimension.mutable_text(), pcbIUScale );
346
347 types::Text* text = dimension.mutable_text();
348 text->set_text( GetValueText() );
349
350 dimension.set_override_text_enabled( m_overrideTextEnabled );
351 dimension.set_override_text( m_valueString.ToUTF8() );
352 dimension.set_prefix( m_prefix.ToUTF8() );
353 dimension.set_suffix( m_suffix.ToUTF8() );
354
356 dimension.set_unit_format(
358 dimension.set_arrow_direction(
361 dimension.set_suppress_trailing_zeroes( m_suppressZeroes );
362
363 if( FOOTPRINT* parent = GetParentFootprint() )
364 dimension.mutable_parent()->set_value( parent->m_Uuid.AsStdString() );
365 else if( const BOARD* board = GetBoard() )
366 dimension.mutable_parent()->set_value( board->m_Uuid.AsStdString() );
367
368 dimension.mutable_line_thickness()->set_value_nm( m_lineThickness );
369 dimension.mutable_arrow_length()->set_value_nm( m_arrowLength );
370 dimension.mutable_extension_offset()->set_value_nm( m_extensionOffset );
371 dimension.set_text_position(
373 dimension.set_keep_text_aligned( m_keepTextAligned );
374
375 kiapi::common::PackCustomProperties( dimension.mutable_custom_properties(), *this );
376 aContainer.PackFrom( dimension );
377}
378
379
380bool PCB_DIMENSION_BASE::Deserialize( const google::protobuf::Any &aContainer )
381{
382 using namespace kiapi::common;
383 kiapi::board::types::Dimension dimension;
384
385 if( !aContainer.UnpackTo( &dimension ) )
386 return false;
387
389 SetUuidDirect( KIID( dimension.id().value() ) );
390 SetLocked( dimension.locked() == types::LockedState::LS_LOCKED );
391
392 // Setting text attributes triggers Update(), which must already see the text position mode
393 SetTextPositionMode( FromProtoEnum<DIM_TEXT_POSITION>( dimension.text_position() ) );
394 SetKeepTextAligned( dimension.keep_text_aligned() );
395
396 EDA_TEXT::Deserialize( dimension.text(), pcbIUScale );
397
398 SetOverrideTextEnabled( dimension.override_text_enabled() );
399 SetOverrideText( wxString::FromUTF8( dimension.override_text() ) );
400 SetPrefix( wxString::FromUTF8( dimension.prefix() ) );
401 SetSuffix( wxString::FromUTF8( dimension.suffix() ) );
402
403 SetUnitsMode( FromProtoEnum<DIM_UNITS_MODE>( dimension.unit() ) );
404 SetUnitsFormat( FromProtoEnum<DIM_UNITS_FORMAT>( dimension.unit_format() ) );
405 SetArrowDirection( FromProtoEnum<DIM_ARROW_DIRECTION>( dimension.arrow_direction() ) );
406 SetPrecision( FromProtoEnum<DIM_PRECISION>( dimension.precision() ) );
407 SetSuppressZeroes( dimension.suppress_trailing_zeroes() );
408
409 SetLineThickness( dimension.line_thickness().value_nm() );
410 SetArrowLength( dimension.arrow_length().value_nm() );
411 SetExtensionOffset( dimension.extension_offset().value_nm() );
412
413 kiapi::common::UnpackCustomProperties( dimension.custom_properties(), *this );
414
415 Update();
416
417 return true;
418}
419
420
421void PCB_DIMENSION_BASE::drawAnArrow( VECTOR2I startPoint, EDA_ANGLE anAngle, int aLength )
422{
423 if( aLength )
424 {
425 VECTOR2I tailEnd( aLength, 0 );
426 RotatePoint( tailEnd, -anAngle );
427 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + tailEnd ) );
428 }
429
430 VECTOR2I arrowEndPos( m_arrowLength, 0 );
431 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
432
433 RotatePoint( arrowEndPos, -anAngle + s_arrowAngle );
434 RotatePoint( arrowEndNeg, -anAngle - s_arrowAngle );
435
436 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndPos ) );
437 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndNeg ) );
438}
439
440
442{
444
445 switch( m_unitsFormat )
446 {
447 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
448 break;
449
450 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
452 break;
453
454 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
455 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
456 break;
457 }
458
459 text.Prepend( m_prefix );
460 text.Append( m_suffix );
461
462 SetText( text );
463}
464
465
467{
469
470 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
471 // have changed and we may need to update the dimension text
472
474 {
476 Update();
477 m_inClearRenderCache = false;
478 }
479}
480
481
482template<typename ShapeType>
483void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
484{
485 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
486}
487
488
490{
491 struct lconv* lc = localeconv();
492 wxChar sep = lc->decimal_point[0];
493
494 int val = GetMeasuredValue();
495 int precision = static_cast<int>( m_precision );
496 wxString text;
497
498 if( precision >= 6 )
499 {
500 switch( m_units )
501 {
502 case EDA_UNITS::INCH: precision = precision - 4; break;
503 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
504 case EDA_UNITS::MM: precision = precision - 5; break;
505 default: precision = precision - 4; break;
506 }
507 }
508
509 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
510
511 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
512
513 if( m_suppressZeroes && precision > 0 )
514 {
515 while( text.EndsWith( '0' ) )
516 {
517 text.RemoveLast();
518
519 if( text.EndsWith( '.' ) || text.EndsWith( sep ) )
520 {
521 text.RemoveLast();
522 break;
523 }
524 }
525 }
526
527 return text;
528}
529
530
535
536
542
543
545{
546 switch( GetValueMode() )
547 {
549 {
550 PCB_CONSTRAINT* lengthConstraint = FindDimensionLengthConstraint( GetBoard(), this );
551
552 if( lengthConstraint && lengthConstraint->GetValue() )
553 {
555 *lengthConstraint->GetValue() );
556 }
557
558 return GetValueText();
559 }
560
562 return GetOverrideText();
563
565 default:
566 return GetValueText();
567 }
568}
569
570
571void PCB_DIMENSION_BASE::ChangeValueFieldText( const wxString& aText )
572{
574 {
575 SetOverrideText( aText );
576 Update();
577 }
578}
579
580
581void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
582{
583 m_prefix = aPrefix;
584}
585
586
587void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
588{
589 m_suffix = aSuffix;
590}
591
592
594{
595 m_units = aUnits;
596}
597
598
600{
601 if( m_autoUnits )
602 {
604 }
605 else
606 {
607 switch( m_units )
608 {
609 default:
613 }
614 }
615}
616
617
619{
620 switch( aMode )
621 {
623 m_autoUnits = false;
625 break;
626
628 m_autoUnits = false;
630 break;
631
633 m_autoUnits = false;
635 break;
636
638 m_autoUnits = true;
640 break;
641 }
642}
643
644
646{
647 SetTextAngleDegrees( aDegrees );
648 // Create or repair any knockouts
649 Update();
650}
651
652
654{
655 SetKeepTextAligned( aKeepAligned );
656 // Re-align the text and repair any knockouts
657 Update();
658}
659
660
662{
663 PCB_TEXT::Offset( offset );
664
665 if( const FOOTPRINT* fp = GetParentFootprint() )
666 {
667 const TRANSFORM_TRS& xform = fp->GetTransform();
668 VECTOR2I libOffset = xform.InverseApply( offset ) - xform.InverseApply( VECTOR2I( 0, 0 ) );
669 m_start += libOffset;
670 m_end += libOffset;
671 }
672 else
673 {
674 m_start += offset;
675 m_end += offset;
676 }
677
678 Update();
679}
680
681
682void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
683{
684 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
685 newAngle.Normalize();
686 SetTextAngle( newAngle );
687
688 VECTOR2I pt = GetTextPos();
689 RotatePoint( pt, aRotCentre, aAngle );
690 SetTextPos( pt );
691
692 VECTOR2I boardStart = GetStart();
693 VECTOR2I boardEnd = GetEnd();
694 RotatePoint( boardStart, aRotCentre, aAngle );
695 RotatePoint( boardEnd, aRotCentre, aAngle );
696
697 if( const FOOTPRINT* fp = GetParentFootprint() )
698 {
699 m_start = fp->GetTransform().InverseApply( boardStart );
700 m_end = fp->GetTransform().InverseApply( boardEnd );
701 }
702 else
703 {
704 m_start = boardStart;
705 m_end = boardEnd;
706 }
707
708 Update();
709}
710
711
712void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
713{
714 Mirror( aCentre, aFlipDirection );
715
717}
718
719
720void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
721{
722 if( const FOOTPRINT* fp = GetParentFootprint() )
723 {
724 const VECTOR2I libAxis = fp->GetTransform().InverseApply( axis_pos );
725
726 auto mirrorPt = [&]( VECTOR2I& p )
727 {
728 if( aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
729 p.x = 2 * libAxis.x - p.x;
730 else
731 p.y = 2 * libAxis.y - p.y;
732 };
733
734 mirrorPt( m_start );
735 mirrorPt( m_end );
736
737 VECTOR2I libTextPos = EDA_TEXT::GetTextPos();
738 mirrorPt( libTextPos );
739 SetLibTextPos( libTextPos );
740
741 EDA_ANGLE newLibAngle =
743 SetLibTextAngle( newLibAngle );
744
745 if( IsSideSpecific() )
747
749 Update();
750 return;
751 }
752
753 VECTOR2I newPos = GetTextPos();
754
755 MIRROR( newPos, axis_pos, aFlipDirection );
756
757 SetTextPos( newPos );
758
759 // invert angle
761
762 MIRROR( m_start, axis_pos, aFlipDirection );
763 MIRROR( m_end, axis_pos, aFlipDirection );
764
765 if( IsSideSpecific() )
767
768 Update();
769}
770
771
772void PCB_DIMENSION_BASE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& aSettings, bool aCheckSide )
773{
774 PCB_TEXT::StyleFromSettings( aSettings, aCheckSide );
775
783
784 Update(); // refresh text & geometry
785
786}
787
788
790 std::vector<MSG_PANEL_ITEM>& aList )
791{
792 // for now, display only the text within the DIMENSION using class PCB_TEXT.
793 wxString msg;
794
795 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
796
797 // Don't use GetShownText(); we want to see the variable references here
798 aList.emplace_back( _( "Dimension" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
799
800 aList.emplace_back( _( "Prefix" ), GetPrefix() );
801
803 {
804 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
805 }
806 else
807 {
808 aList.emplace_back( _( "Value" ), GetValueText() );
809
810 switch( GetPrecision() )
811 {
812 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
813 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
814 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
815 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
816 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
817 }
818
819 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
820 }
821
822 aList.emplace_back( _( "Suffix" ), GetSuffix() );
823
824 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
825 // in frame's units.
826 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
827 unitsProvider.SetUserUnits( GetUnits() );
828
829 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
830
831 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
832 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
833 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
834 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
835
836 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
837
838 if( Type() == PCB_DIM_CENTER_T )
839 {
840 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
841 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
842 aFrame->MessageTextFromValue( startCoord.x ),
843 aFrame->MessageTextFromValue( startCoord.y ) );
844
845 aList.emplace_back( start, wxEmptyString );
846 }
847 else
848 {
849 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
850 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
851 aFrame->MessageTextFromValue( startCoord.x ),
852 aFrame->MessageTextFromValue( startCoord.y ) );
853 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
854 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
855 aFrame->MessageTextFromValue( endCoord.x ),
856 aFrame->MessageTextFromValue( endCoord.y ) );
857
858 aList.emplace_back( start, end );
859 }
860
861 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
862 aList.emplace_back( _( "Status" ), _( "Locked" ) );
863
864 aList.emplace_back( _( "Layer" ), GetLayerName() );
865}
866
867
869{
870 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
871
872 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
873
874 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
875 effectiveShape->AddShape( shape->Clone() );
876
877 return effectiveShape;
878}
879
880
881bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
882{
883 if( TextHitTest( aPosition ) )
884 return true;
885
886 int dist_max = aAccuracy + ( m_lineThickness / 2 );
887
888 // Locate SEGMENTS
889
890 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
891 {
892 if( shape->Collide( aPosition, dist_max ) )
893 return true;
894 }
895
896 return false;
897}
898
899
900bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
901{
902 BOX2I arect = aRect;
903 arect.Inflate( aAccuracy );
904
905 BOX2I rect = GetBoundingBox();
906
907 if( aAccuracy )
908 rect.Inflate( aAccuracy );
909
910 if( aContained )
911 return arect.Contains( rect );
912
913 return arect.Intersects( rect );
914}
915
916
917bool PCB_DIMENSION_BASE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
918{
919 // Note: Can't use GetEffectiveShape() because we want text as BoundingBox, not as graphics.
920 SHAPE_COMPOUND effShape;
921
922 // Add shapes
923 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
924 effShape.AddShape( shape );
925
926 if( aContained )
927 return TextHitTest( aPoly, aContained ) && KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
928 else
929 return TextHitTest( aPoly, aContained ) || KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
930}
931
932
934{
935 BOX2I bBox;
936 int xmin, xmax, ymin, ymax;
937
938 bBox = GetTextBox( nullptr );
939 xmin = bBox.GetX();
940 xmax = bBox.GetRight();
941 ymin = bBox.GetY();
942 ymax = bBox.GetBottom();
943
944 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
945 {
946 BOX2I shapeBox = shape->BBox();
947 shapeBox.Inflate( m_lineThickness / 2 );
948
949 xmin = std::min( xmin, shapeBox.GetOrigin().x );
950 xmax = std::max( xmax, shapeBox.GetEnd().x );
951 ymin = std::min( ymin, shapeBox.GetOrigin().y );
952 ymax = std::max( ymax, shapeBox.GetEnd().y );
953 }
954
955 bBox.SetX( xmin );
956 bBox.SetY( ymin );
957 bBox.SetWidth( xmax - xmin + 1 );
958 bBox.SetHeight( ymax - ymin + 1 );
959
960 bBox.Normalize();
961
962 return bBox;
963}
964
965
966wxString PCB_DIMENSION_BASE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
967{
968 return wxString::Format( _( "Dimension '%s' on %s" ),
970 GetLayerName() );
971}
972
973
974
976{
978 VECTOR2I( GetBoundingBox().GetSize() ) );
979 dimBBox.Merge( PCB_TEXT::ViewBBox() );
980
981 return dimBBox;
982}
983
984
985std::vector<int> PCB_DIMENSION_BASE::ViewGetLayers() const
986{
987 std::vector<int> layers = PCB_TEXT::ViewGetLayers();
988
989 // Always advertised while ViewGetLOD gates the draw on actual constraint reference
990 layers.push_back( LAYER_CONSTRAINT_SHADOW );
991
992 return layers;
993}
994
995
996double PCB_DIMENSION_BASE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
997{
998 if( aLayer == LAYER_CONSTRAINT_SHADOW && aView )
999 {
1000 KIGFX::PCB_RENDER_SETTINGS& renderSettings =
1001 *static_cast<KIGFX::PCB_PAINTER&>( *aView->GetPainter() ).GetSettings();
1002
1003 if( !renderSettings.GetConstrainedItems().count( m_Uuid ) )
1004 return LOD_HIDE;
1005
1006 if( !aView->IsLayerVisibleCached( GetLayer() ) )
1007 return LOD_HIDE;
1008
1009 if( renderSettings.GetHighContrast() && GetLayer() != renderSettings.GetPrimaryHighContrastLayer() )
1010 return LOD_HIDE;
1011
1012 return LOD_SHOW;
1013 }
1014
1015 return PCB_TEXT::ViewGetLOD( aLayer, aView );
1016}
1017
1018
1019double PCB_DIMENSION_BASE::GetCoverageArea( int aTextMargin ) const
1020{
1021 // A dimension covers its whole drawing, not only the value text it inherits from
1022 return BOARD_ITEM::GetCoverageArea( aTextMargin );
1023}
1024
1025
1027 int aClearance, int aError, ERROR_LOC aErrorLoc,
1028 bool aIgnoreLineWidth ) const
1029{
1030 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
1031
1032 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
1033 {
1034 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
1035 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
1036
1037 if( circle )
1038 {
1039 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
1040 circle->GetRadius() + m_lineThickness / 2 + aClearance,
1041 aError, aErrorLoc );
1042 }
1043 else if( seg )
1044 {
1045 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
1046 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
1047 }
1048 else
1049 {
1050 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
1051 }
1052 }
1053}
1054
1055
1057 PCB_DIMENSION_BASE( aParent, aType ),
1058 m_height( 0 )
1059{
1060 // To preserve look of old dimensions, initialize extension height based on default arrow length
1061 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1062}
1063
1064
1066{
1067 return new PCB_DIM_ALIGNED( *this );
1068}
1069
1070
1072{
1073 wxCHECK( aOther && aOther->Type() == PCB_DIM_ALIGNED_T, /* void */ );
1074 *this = *static_cast<const PCB_DIM_ALIGNED*>( aOther );
1075}
1076
1077void PCB_DIM_ALIGNED::Serialize( google::protobuf::Any &aContainer ) const
1078{
1079 using namespace kiapi::common;
1080 kiapi::board::types::Dimension dimension;
1081
1082 PCB_DIMENSION_BASE::Serialize( aContainer );
1083 aContainer.UnpackTo( &dimension );
1084
1085 PackVector2( *dimension.mutable_aligned()->mutable_start(), GetStart() );
1086 PackVector2( *dimension.mutable_aligned()->mutable_end(), GetEnd() );
1087 dimension.mutable_aligned()->mutable_height()->set_value_nm( m_height );
1088 dimension.mutable_aligned()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1089
1090 aContainer.PackFrom( dimension );
1091}
1092
1093
1094bool PCB_DIM_ALIGNED::Deserialize( const google::protobuf::Any &aContainer )
1095{
1096 using namespace kiapi::common;
1097
1098 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1099 return false;
1100
1101 kiapi::board::types::Dimension dimension;
1102 aContainer.UnpackTo( &dimension );
1103
1104 if( !dimension.has_aligned() )
1105 return false;
1106
1107 SetStart( UnpackVector2( dimension.aligned().start() ) );
1108 SetEnd( UnpackVector2( dimension.aligned().end() ) );
1109 SetHeight( dimension.aligned().height().value_nm());
1110 SetExtensionHeight( dimension.aligned().extension_height().value_nm() );
1111
1112 Update();
1113
1114 return true;
1115}
1116
1117
1119{
1120 wxASSERT( aImage->Type() == Type() );
1121
1122 m_shapes.clear();
1123 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
1124
1125 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
1126
1127 Update();
1128}
1129
1130
1131void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1132{
1133 m_height = -m_height;
1134 // Call this last for the Update()
1135 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1136}
1137
1138
1143
1144
1145void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
1146{
1147 VECTOR2D height( aCrossbarStart - GetStart() );
1148 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
1149
1150 if( height.Cross( crossBar ) > 0 )
1151 m_height = -height.EuclideanNorm();
1152 else
1153 m_height = height.EuclideanNorm();
1154
1155 Update();
1156}
1157
1158
1160{
1161 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1162 return;
1163
1164 m_busy = true;
1165
1166 m_shapes.clear();
1167
1168 const VECTOR2I start = GetStart();
1169 const VECTOR2I end = GetEnd();
1170 VECTOR2I dimension( end - start );
1171
1172 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
1173
1174 VECTOR2I extension;
1175
1176 if( m_height > 0 )
1177 extension = VECTOR2I( -dimension.y, dimension.x );
1178 else
1179 extension = VECTOR2I( dimension.y, -dimension.x );
1180
1181 // Add extension lines
1182 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1183
1184 VECTOR2I extStart( start );
1185 extStart += extension.Resize( m_extensionOffset );
1186
1187 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1188
1189 extStart = VECTOR2I( end );
1190 extStart += extension.Resize( m_extensionOffset );
1191
1192 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1193
1194 // Add crossbar
1195 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1196 m_crossBarStart = start + crossBarDistance;
1197 m_crossBarEnd = end + crossBarDistance;
1198
1199 // Update text after calculating crossbar position but before adding crossbar lines
1200 updateText();
1201
1202 // Now that we have the text updated, we can determine how to draw the crossbar.
1203 // First we need to create an appropriate bounding polygon to collide with
1204 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, - GetEffectiveTextPenWidth() );
1205
1206 SHAPE_POLY_SET polyBox;
1207 polyBox.NewOutline();
1208 polyBox.Append( textBox.GetOrigin() );
1209 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1210 polyBox.Append( textBox.GetEnd() );
1211 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1212 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1213
1214 // The ideal crossbar, if the text doesn't collide
1215 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1216
1217 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1218
1220 {
1221 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ),
1223 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ),
1225 }
1226 else
1227 {
1228 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ), 0 );
1229 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ), 0 );
1230 }
1231
1232 m_busy = false;
1233}
1234
1235
1237{
1238 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1239
1241 {
1242 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1243 EDA_ANGLE rotation;
1244
1245 if( crossbarCenter.x == 0 )
1246 rotation = ANGLE_90 * sign( -crossbarCenter.y );
1247 else if( crossbarCenter.x < 0 )
1248 rotation = -ANGLE_90;
1249 else
1250 rotation = ANGLE_90;
1251
1252 VECTOR2I textOffset = crossbarCenter;
1253 RotatePoint( textOffset, rotation );
1254 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
1255
1256 SetTextPos( m_crossBarStart + textOffset );
1257 }
1259 {
1260 SetTextPos( m_crossBarStart + crossbarCenter );
1261 }
1262
1263 if( m_keepTextAligned )
1264 {
1265 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
1266 textAngle.Normalize();
1267
1268 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1269 textAngle -= ANGLE_180;
1270
1271 SetTextAngle( textAngle );
1272 }
1273
1275}
1276
1277
1278void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1279{
1280 PCB_DIMENSION_BASE::GetMsgPanelInfo( aFrame, aList );
1281
1282 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
1283 // in frame's units.
1284 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
1285 unitsProvider.SetUserUnits( GetUnits() );
1286
1287 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
1288}
1289
1290
1293{
1294 // To preserve look of old dimensions, initialize extension height based on default arrow length
1295 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1297}
1298
1299
1301{
1302 return new PCB_DIM_ORTHOGONAL( *this );
1303}
1304
1305
1307{
1308 wxCHECK( aOther && aOther->Type() == PCB_DIM_ORTHOGONAL_T, /* void */ );
1309 *this = *static_cast<const PCB_DIM_ORTHOGONAL*>( aOther );
1310}
1311
1312void PCB_DIM_ORTHOGONAL::Serialize( google::protobuf::Any &aContainer ) const
1313{
1314 using namespace kiapi::common;
1315 kiapi::board::types::Dimension dimension;
1316
1317 PCB_DIMENSION_BASE::Serialize( aContainer );
1318 aContainer.UnpackTo( &dimension );
1319
1320 PackVector2( *dimension.mutable_orthogonal()->mutable_start(), GetStart() );
1321 PackVector2( *dimension.mutable_orthogonal()->mutable_end(), GetEnd() );
1322 dimension.mutable_orthogonal()->mutable_height()->set_value_nm( m_height );
1323 dimension.mutable_orthogonal()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1324
1325 dimension.mutable_orthogonal()->set_alignment( m_orientation == DIR::VERTICAL
1326 ? types::AxisAlignment::AA_Y_AXIS
1327 : types::AxisAlignment::AA_X_AXIS );
1328 aContainer.PackFrom( dimension );
1329}
1330
1331
1332bool PCB_DIM_ORTHOGONAL::Deserialize( const google::protobuf::Any &aContainer )
1333{
1334 using namespace kiapi::common;
1335
1336 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1337 return false;
1338
1339 kiapi::board::types::Dimension dimension;
1340 aContainer.UnpackTo( &dimension );
1341
1342 if( !dimension.has_orthogonal() )
1343 return false;
1344
1345 SetStart( UnpackVector2( dimension.orthogonal().start() ) );
1346 SetEnd( UnpackVector2( dimension.orthogonal().end() ) );
1347 SetHeight( dimension.orthogonal().height().value_nm());
1348 SetExtensionHeight( dimension.orthogonal().extension_height().value_nm() );
1349 SetOrientation( dimension.orthogonal().alignment() == types::AxisAlignment::AA_Y_AXIS
1351 : DIR::HORIZONTAL );
1352
1353 Update();
1354
1355 return true;
1356}
1357
1358
1360{
1361 wxASSERT( aImage->Type() == Type() );
1362
1363 m_shapes.clear();
1364 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
1365
1366 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
1367 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
1368
1369 Update();
1370}
1371
1372
1373void PCB_DIM_ORTHOGONAL::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1374{
1375 // Only reverse the height if the height is aligned with the flip
1376 if( m_orientation == DIR::HORIZONTAL && aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
1377 m_height = -m_height;
1378 else if( m_orientation == DIR::VERTICAL && aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1379 m_height = -m_height;
1380
1381 // Call this last, as we need the Update()
1382 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1383}
1384
1385
1390
1391
1393{
1394 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1395 return;
1396
1397 m_busy = true;
1398 m_shapes.clear();
1399
1400 const VECTOR2I start = GetStart();
1401 const VECTOR2I end = GetEnd();
1402
1403 int measurement = ( m_orientation == DIR::HORIZONTAL ? end.x - start.x : end.y - start.y );
1405
1406 VECTOR2I extension;
1407
1409 extension = VECTOR2I( 0, m_height );
1410 else
1411 extension = VECTOR2I( m_height, 0 );
1412
1413 // Add first extension line
1414 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1415
1416 VECTOR2I extStart( start );
1417 extStart += extension.Resize( m_extensionOffset );
1418
1419 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1420
1421 // Add crossbar
1422 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1423 m_crossBarStart = start + crossBarDistance;
1424
1427 else
1429
1430 // Add second extension line (end to crossbar end)
1432 extension = VECTOR2I( 0, end.y - m_crossBarEnd.y );
1433 else
1434 extension = VECTOR2I( end.x - m_crossBarEnd.x, 0 );
1435
1436 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
1437
1438 extStart = VECTOR2I( m_crossBarEnd );
1439 extStart -= extension.Resize( m_extensionHeight );
1440
1441 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1442
1443 // Update text after calculating crossbar position but before adding crossbar lines
1444 updateText();
1445
1446 // Now that we have the text updated, we can determine how to draw the crossbar.
1447 // First we need to create an appropriate bounding polygon to collide with
1448 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1449
1450 SHAPE_POLY_SET polyBox;
1451 polyBox.NewOutline();
1452 polyBox.Append( textBox.GetOrigin() );
1453 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1454 polyBox.Append( textBox.GetEnd() );
1455 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1456 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1457
1458 // The ideal crossbar, if the text doesn't collide
1459 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1460
1461 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1462
1463 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
1464
1466 {
1467 // Arrows with fixed length.
1468 drawAnArrow( m_crossBarStart, crossBarAngle + EDA_ANGLE( 180 ),
1471 }
1472 else
1473 {
1474 drawAnArrow( m_crossBarStart, crossBarAngle, 0 );
1475 drawAnArrow( m_crossBarEnd, crossBarAngle + EDA_ANGLE( 180 ), 0 );
1476 }
1477
1478 m_busy = false;
1479}
1480
1481
1483{
1484 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1485
1487 {
1488 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1489
1490 VECTOR2I textOffset;
1491
1493 textOffset.y = -textOffsetDistance;
1494 else
1495 textOffset.x = -textOffsetDistance;
1496
1497 textOffset += crossbarCenter;
1498
1499 SetTextPos( m_crossBarStart + textOffset );
1500 }
1502 {
1503 SetTextPos( m_crossBarStart + crossbarCenter );
1504 }
1505
1506 if( m_keepTextAligned )
1507 {
1508 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
1510 else
1512 }
1513
1515}
1516
1517
1518void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1519{
1520 EDA_ANGLE angle( aAngle );
1521
1522 // restrict angle to -179.9 to 180.0 degrees
1523 angle.Normalize180();
1524
1525 // adjust orientation and height to new angle
1526 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
1527 // in the other cases we will use the nearest 90 degree angle to
1528 // choose at least an approximate axis for the target orientation
1529 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
1530 if( angle > ANGLE_45 && angle <= ANGLE_135 )
1531 {
1532 // about 90 degree
1534 {
1536 }
1537 else
1538 {
1540 m_height = -m_height;
1541 }
1542 }
1543 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
1544 {
1545 // about -90 degree
1547 {
1549 m_height = -m_height;
1550 }
1551 else
1552 {
1554 }
1555 }
1556 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
1557 {
1558 // about 180 degree
1559 m_height = -m_height;
1560 }
1561
1562 // this will update m_crossBarStart and m_crossbarEnd
1563 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
1564}
1565
1566
1577
1578
1580{
1581 wxCHECK( aOther && aOther->Type() == PCB_DIM_LEADER_T, /* void */ );
1582 *this = *static_cast<const PCB_DIM_LEADER*>( aOther );
1583}
1584
1585void PCB_DIM_LEADER::Serialize( google::protobuf::Any &aContainer ) const
1586{
1587 using namespace kiapi::common;
1588 kiapi::board::types::Dimension dimension;
1589
1590 PCB_DIMENSION_BASE::Serialize( aContainer );
1591 aContainer.UnpackTo( &dimension );
1592
1593 PackVector2( *dimension.mutable_leader()->mutable_start(), GetStart() );
1594 PackVector2( *dimension.mutable_leader()->mutable_end(), GetEnd() );
1595 dimension.mutable_leader()->set_border_style(
1597 m_textBorder ) );
1598
1599 aContainer.PackFrom( dimension );
1600}
1601
1602
1603bool PCB_DIM_LEADER::Deserialize( const google::protobuf::Any &aContainer )
1604{
1605 using namespace kiapi::common;
1606
1607 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1608 return false;
1609
1610 kiapi::board::types::Dimension dimension;
1611 aContainer.UnpackTo( &dimension );
1612
1613 if( !dimension.has_leader() )
1614 return false;
1615
1616 SetStart( UnpackVector2( dimension.leader().start() ) );
1617 SetEnd( UnpackVector2( dimension.leader().end() ) );
1618 SetTextBorder( FromProtoEnum<DIM_TEXT_BORDER>( dimension.leader().border_style() ) );
1619
1620 Update();
1621
1622 return true;
1623}
1624
1625
1627{
1628 return new PCB_DIM_LEADER( *this );
1629}
1630
1631
1633{
1634 wxASSERT( aImage->Type() == Type() );
1635
1636 m_shapes.clear();
1637 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
1638
1639 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
1640
1641 Update();
1642}
1643
1644
1649
1650
1652{
1653 // Our geometry is dependent on the size of the text, so just update the whole shebang
1655}
1656
1657
1659{
1660 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1661 return;
1662
1663 m_busy = true;
1664
1665 m_shapes.clear();
1666
1668
1669 // Now that we have the text updated, we can determine how to draw the second line
1670 // First we need to create an appropriate bounding polygon to collide with
1671 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1672
1673 SHAPE_POLY_SET polyBox;
1674 polyBox.NewOutline();
1675 polyBox.Append( textBox.GetOrigin() );
1676 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1677 polyBox.Append( textBox.GetEnd() );
1678 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1679 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1680
1681 const VECTOR2I boardStart = GetStart();
1682 const VECTOR2I boardEnd = GetEnd();
1683
1684 VECTOR2I firstLine( boardEnd - boardStart );
1685 VECTOR2I start( boardStart );
1686 start += firstLine.Resize( m_extensionOffset );
1687
1688 SEG arrowSeg( boardStart, boardEnd );
1689 SEG textSeg( boardEnd, GetTextPos() );
1690 OPT_VECTOR2I arrowSegEnd;
1691 OPT_VECTOR2I textSegEnd;
1692
1694 {
1695 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1696 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1697 CIRCLE circle( textBox.GetCenter(), radius );
1698
1699 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1700 textSegEnd = segCircleIntersection( circle, textSeg );
1701 }
1702 else
1703 {
1704 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1705 textSegEnd = segPolyIntersection( polyBox, textSeg );
1706 }
1707
1708 if( !arrowSegEnd )
1709 arrowSegEnd = boardEnd;
1710
1711 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1712
1713 drawAnArrow( start, EDA_ANGLE( firstLine ), 0 );
1714
1715 if( !GetText().IsEmpty() )
1716 {
1717 switch( m_textBorder )
1718 {
1720 {
1721 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1722 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1723
1724 break;
1725 }
1726
1728 {
1729 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1730 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1731 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1732
1733 break;
1734 }
1735
1736 default:
1737 break;
1738 }
1739 }
1740
1741 if( textSegEnd && *arrowSegEnd == boardEnd )
1742 m_shapes.emplace_back( new SHAPE_SEGMENT( boardEnd, *textSegEnd ) );
1743
1744 m_busy = false;
1745}
1746
1747
1748void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1749{
1750 // Don't use GetShownText(); we want to see the variable references here
1751 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1752
1753 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
1754
1755 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1756 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1757 aFrame->MessageTextFromValue( startCoord.x ),
1758 aFrame->MessageTextFromValue( startCoord.y ) );
1759
1760 aList.emplace_back( start, wxEmptyString );
1761
1762 aList.emplace_back( _( "Layer" ), GetLayerName() );
1763}
1764
1765
1775
1777{
1778 wxCHECK( aOther && aOther->Type() == PCB_DIM_RADIAL_T, /* void */ );
1779 *this = *static_cast<const PCB_DIM_RADIAL*>( aOther );
1780}
1781
1782void PCB_DIM_RADIAL::Serialize( google::protobuf::Any &aContainer ) const
1783{
1784 using namespace kiapi::common;
1785 kiapi::board::types::Dimension dimension;
1786
1787 PCB_DIMENSION_BASE::Serialize( aContainer );
1788 aContainer.UnpackTo( &dimension );
1789
1790 PackVector2( *dimension.mutable_radial()->mutable_center(), GetStart() );
1791 PackVector2( *dimension.mutable_radial()->mutable_radius_point(), GetEnd() );
1792 dimension.mutable_radial()->mutable_leader_length()->set_value_nm( m_leaderLength );
1793
1794 aContainer.PackFrom( dimension );
1795}
1796
1797
1798bool PCB_DIM_RADIAL::Deserialize( const google::protobuf::Any &aContainer )
1799{
1800 using namespace kiapi::common;
1801
1802 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1803 return false;
1804
1805 kiapi::board::types::Dimension dimension;
1806 aContainer.UnpackTo( &dimension );
1807
1808 if( !dimension.has_radial() )
1809 return false;
1810
1811 SetStart( UnpackVector2( dimension.radial().center() ) );
1812 SetEnd( UnpackVector2( dimension.radial().radius_point() ) );
1813 SetLeaderLength( dimension.radial().leader_length().value_nm() );
1814
1815 Update();
1816
1817 return true;
1818}
1819
1820
1822{
1823 return new PCB_DIM_RADIAL( *this );
1824}
1825
1826
1828{
1829 wxASSERT( aImage->Type() == Type() );
1830
1831 m_shapes.clear();
1832 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1833
1834 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1835
1836 Update();
1837}
1838
1839
1844
1845
1847{
1848 const VECTOR2I end = GetEnd();
1849 VECTOR2I radial( end - GetStart() );
1850
1851 return end + radial.Resize( m_leaderLength );
1852}
1853
1854
1856{
1857 if( m_keepTextAligned )
1858 {
1859 VECTOR2I textLine( GetTextPos() - GetKnee() );
1860 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1861
1862 textAngle.Normalize();
1863
1864 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1865 textAngle -= ANGLE_180;
1866
1867 // Round to nearest degree
1868 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1869
1870 SetTextAngle( textAngle );
1871 }
1872
1874}
1875
1876
1878{
1879 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1880 return;
1881
1882 m_busy = true;
1883
1884 m_shapes.clear();
1885
1886 const VECTOR2I boardStart = GetStart();
1887 const VECTOR2I boardEnd = GetEnd();
1888
1889 VECTOR2I center( boardStart );
1890 VECTOR2I centerArm( 0, m_arrowLength );
1891
1892 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1893
1894 RotatePoint( centerArm, -ANGLE_90 );
1895
1896 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1897
1898 VECTOR2I radius( boardEnd - boardStart );
1899
1900 m_measuredValue = KiROUND( radius.EuclideanNorm() );
1901
1902 updateText();
1903
1904 // Now that we have the text updated, we can determine how to draw the second line
1905 // First we need to create an appropriate bounding polygon to collide with
1906 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1907
1908 SHAPE_POLY_SET polyBox;
1909 polyBox.NewOutline();
1910 polyBox.Append( textBox.GetOrigin() );
1911 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1912 polyBox.Append( textBox.GetEnd() );
1913 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1914 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1915
1916 VECTOR2I radial( boardEnd - boardStart );
1917 radial = radial.Resize( m_leaderLength );
1918
1919 SEG arrowSeg( boardEnd, boardEnd + radial );
1920 SEG textSeg( arrowSeg.B, GetTextPos() );
1921
1922 CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
1923 CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
1924
1925 drawAnArrow( boardEnd, EDA_ANGLE( radial ), 0 );
1926
1927 m_busy = false;
1928}
1929
1930
1937
1939{
1940 wxCHECK( aOther && aOther->Type() == PCB_DIM_CENTER_T, /* void */ );
1941 *this = *static_cast<const PCB_DIM_CENTER*>( aOther );
1942}
1943
1944void PCB_DIM_CENTER::Serialize( google::protobuf::Any &aContainer ) const
1945{
1946 using namespace kiapi::common;
1947 kiapi::board::types::Dimension dimension;
1948
1949 PCB_DIMENSION_BASE::Serialize( aContainer );
1950 aContainer.UnpackTo( &dimension );
1951
1952 PackVector2( *dimension.mutable_center()->mutable_center(), GetStart() );
1953 PackVector2( *dimension.mutable_center()->mutable_end(), GetEnd() );
1954
1955 aContainer.PackFrom( dimension );
1956}
1957
1958
1959bool PCB_DIM_CENTER::Deserialize( const google::protobuf::Any &aContainer )
1960{
1961 using namespace kiapi::common;
1962
1963 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1964 return false;
1965
1966 kiapi::board::types::Dimension dimension;
1967 aContainer.UnpackTo( &dimension );
1968
1969 if( !dimension.has_center() )
1970 return false;
1971
1972 SetStart( UnpackVector2( dimension.center().center() ) );
1973 SetEnd( UnpackVector2( dimension.center().end() ) );
1974
1975 Update();
1976
1977 return true;
1978}
1979
1980
1982{
1983 return new PCB_DIM_CENTER( *this );
1984}
1985
1986
1988{
1989 wxASSERT( aImage->Type() == Type() );
1990
1991 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1992}
1993
1994
1999
2000
2002{
2003 BOX2I bBox;
2004 int xmin, xmax, ymin, ymax;
2005
2006 const VECTOR2I start = GetStart();
2007 xmin = start.x;
2008 xmax = start.x;
2009 ymin = start.y;
2010 ymax = start.y;
2011
2012 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
2013 {
2014 BOX2I shapeBox = shape->BBox();
2015 shapeBox.Inflate( m_lineThickness / 2 );
2016
2017 xmin = std::min( xmin, shapeBox.GetOrigin().x );
2018 xmax = std::max( xmax, shapeBox.GetEnd().x );
2019 ymin = std::min( ymin, shapeBox.GetOrigin().y );
2020 ymax = std::max( ymax, shapeBox.GetEnd().y );
2021 }
2022
2023 bBox.SetX( xmin );
2024 bBox.SetY( ymin );
2025 bBox.SetWidth( xmax - xmin + 1 );
2026 bBox.SetHeight( ymax - ymin + 1 );
2027
2028 bBox.Normalize();
2029
2030 return bBox;
2031}
2032
2033
2035{
2036 return GetBoundingBox();
2037}
2038
2039
2041{
2042 // Even if PCB_DIM_CENTER has no text, we still need to update its text position
2043 // so GetTextPos() users get a valid value. Required at least for lasso hit-testing.
2044 SetTextPos( GetStart() );
2045
2047}
2048
2049
2051{
2052 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
2053 return;
2054
2055 m_busy = true;
2056
2057 m_shapes.clear();
2058
2059 const VECTOR2I boardStart = GetStart();
2060 const VECTOR2I boardEnd = GetEnd();
2061 VECTOR2I center( boardStart );
2062 VECTOR2I arm( boardEnd - boardStart );
2063
2064 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
2065
2066 RotatePoint( arm, -ANGLE_90 );
2067
2068 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
2069
2070 updateText();
2071
2072 m_busy = false;
2073}
2074
2075
2076static struct DIMENSION_DESC
2077{
2079 {
2081 .Map( DIM_PRECISION::X, _HKI( "0" ) )
2082 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
2083 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
2084 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
2085 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
2086 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
2087 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
2088 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
2089 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
2090 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
2091
2093 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
2094 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
2095 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
2096
2098 .Map( DIM_UNITS_MODE::INCH, _HKI( "Inches" ) )
2099 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
2100 .Map( DIM_UNITS_MODE::MM, _HKI( "Millimeters" ) )
2101 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
2102
2104 .Map( DIM_ARROW_DIRECTION::INWARD, _HKI( "Inward" ) )
2105 .Map( DIM_ARROW_DIRECTION::OUTWARD, _HKI( "Outward" ) );
2106
2108 .Map( DIM_VALUE_MODE::DRIVEN, _HKI( "Driven" ) )
2109 .Map( DIM_VALUE_MODE::DRIVING, _HKI( "Driving" ) )
2110 .Map( DIM_VALUE_MODE::ARBITRARY, _HKI( "Arbitrary" ) );
2111
2113 .Map( DIM_TEXT_POSITION::OUTSIDE, _HKI( "Outside" ) )
2114 .Map( DIM_TEXT_POSITION::INLINE, _HKI( "Inline" ) )
2115 .Map( DIM_TEXT_POSITION::MANUAL, _HKI( "Manual" ) );
2116
2125
2126 propMgr.Mask( TYPE_HASH( PCB_DIMENSION_BASE ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
2127
2128 const wxString groupDimension = _HKI( "Dimension Properties" );
2129
2130 auto isLeader =
2131 []( INSPECTABLE* aItem ) -> bool
2132 {
2133 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
2134 };
2135
2136 auto isNotLeader =
2137 []( INSPECTABLE* aItem ) -> bool
2138 {
2139 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
2140 };
2141
2142 auto isNotCenter =
2143 []( INSPECTABLE* aItem ) -> bool
2144 {
2145 return dynamic_cast<PCB_DIM_CENTER*>( aItem ) == nullptr;
2146 };
2147
2148 auto isMultiArrowDirection =
2149 []( INSPECTABLE* aItem ) -> bool
2150 {
2151 return dynamic_cast<PCB_DIM_ALIGNED*>( aItem ) != nullptr;
2152 };
2153
2156 groupDimension )
2157 .SetAvailableFunc( isNotLeader );
2160 groupDimension )
2161 .SetAvailableFunc( isNotLeader );
2162
2163 auto hasValueMode =
2164 []( INSPECTABLE* aItem ) -> bool
2165 {
2166 return DimensionHasValueMode( dynamic_cast<PCB_DIMENSION_BASE*>( aItem ) );
2167 };
2168
2169 // Value bearing dims use Value row instead while leaders keep Text below
2170 // Override Text left for centre mark only
2171 auto usesOverrideText =
2172 [isLeader, hasValueMode]( INSPECTABLE* aItem ) -> bool
2173 {
2174 return aItem && !isLeader( aItem ) && !hasValueMode( aItem );
2175 };
2176
2177 // Driving needs both endpoints bound to movable geometry
2178 // Dropdown always offers it so gate the transition here
2179 auto valueModeValidator =
2180 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2181 {
2182 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2183
2184 if( !dim )
2185 return std::nullopt;
2186
2187 int mode = 0;
2188
2189 if( aValue.CheckType<DIM_VALUE_MODE>() )
2190 mode = static_cast<int>( aValue.As<DIM_VALUE_MODE>() );
2191 else if( !aValue.GetAs( &mode ) )
2192 return std::nullopt;
2193
2194 if( mode == static_cast<int>( DIM_VALUE_MODE::DRIVING )
2195 && !DimensionCanDrive( dim->GetBoard(), dim ) )
2196 {
2197 return std::make_unique<VALIDATION_ERROR_MSG>(
2198 _( "Driving requires both dimension endpoints bound to objects" ) );
2199 }
2200
2201 return std::nullopt;
2202 };
2203
2204 // Driving edits length constraint which must stay positive
2205 // Catches zero and negative and stale exprs parsing to zero
2206 auto drivingValueValidator =
2207 []( const wxAny&& aValue, EDA_ITEM* aItem ) -> VALIDATOR_RESULT
2208 {
2209 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2210
2211 if( !dim || dim->GetValueMode() != DIM_VALUE_MODE::DRIVING )
2212 return std::nullopt;
2213
2214 wxString text;
2215
2216 if( !aValue.GetAs( &text ) )
2217 return std::nullopt;
2218
2220
2221 if( !( iu > 0.0 ) )
2222 {
2223 return std::make_unique<VALIDATION_ERROR_MSG>(
2224 _( "Enter a positive length for a driving dimension" ) );
2225 }
2226
2227 return std::nullopt;
2228 };
2229
2230 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
2232 groupDimension )
2233 .SetAvailableFunc( usesOverrideText );
2234
2237 groupDimension )
2238 .SetAvailableFunc( hasValueMode )
2239 .SetValidator( std::move( valueModeValidator ) );
2240
2243 groupDimension )
2244 .SetAvailableFunc( hasValueMode )
2246 []( INSPECTABLE* aItem ) -> bool
2247 {
2248 // Driven mirrors measured geometry so grey it out since edit would not stick
2249 PCB_DIMENSION_BASE* dim = dynamic_cast<PCB_DIMENSION_BASE*>( aItem );
2250 return dim && dim->GetValueMode() != DIM_VALUE_MODE::DRIVEN;
2251 } )
2252 .SetValidator( std::move( drivingValueValidator ) );
2253
2256 groupDimension )
2257 .SetAvailableFunc( isLeader );
2258
2261 groupDimension )
2262 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2265 groupDimension )
2266 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2269 groupDimension )
2270 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2271 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
2273 groupDimension )
2274 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2275
2278 groupDimension )
2279 .SetAvailableFunc( isMultiArrowDirection ).SetIsCopyable();
2280
2281 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, int>( _HKI( "Line Thickness" ),
2284 groupDimension )
2285 .SetIsCopyable();
2286
2287 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, int>( _HKI( "Arrow Length" ),
2290 groupDimension )
2291 .SetAvailableFunc( isNotCenter ).SetIsCopyable();
2292
2293 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, int>( _HKI( "Extension Line Offset" ),
2296 groupDimension )
2297 .SetAvailableFunc( isNotCenter ).SetIsCopyable();
2298
2299 const wxString groupText = _HKI( "Text Properties" );
2300
2303 groupText )
2304 .SetAvailableFunc( isNotLeader ).SetIsCopyable();
2305
2306 const auto isTextOrientationWriteable =
2307 []( INSPECTABLE* aItem ) -> bool
2308 {
2309 return !static_cast<PCB_DIMENSION_BASE*>( aItem )->GetKeepTextAligned();
2310 };
2311
2312 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Keep Aligned with Dimension" ),
2315 groupText );
2316
2317 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, double>( _HKI( "Orientation" ),
2321 groupText )
2322 .SetWriteableFunc( isTextOrientationWriteable );
2323 }
2325
2332
2333
2335{
2337 {
2348
2349 const wxString groupDimension = _HKI( "Dimension Properties" );
2350
2351 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
2354 groupDimension );
2355 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
2358 groupDimension );
2359
2361 _HKI( "Text" ),
2362 []( INSPECTABLE* aItem ) { return false; } );
2364 _HKI( "Vertical Justification" ),
2365 []( INSPECTABLE* aItem ) { return false; } );
2367 _HKI( "Hyperlink" ),
2368 []( INSPECTABLE* aItem ) { return false; } );
2370 _HKI( "Knockout" ),
2371 []( INSPECTABLE* aItem ) { return false; } );
2372 }
2374
2375
2377{
2379 {
2392
2394 _HKI( "Text" ),
2395 []( INSPECTABLE* aItem ) { return false; } );
2397 _HKI( "Vertical Justification" ),
2398 []( INSPECTABLE* aItem ) { return false; } );
2400 _HKI( "Hyperlink" ),
2401 []( INSPECTABLE* aItem ) { return false; } );
2403 _HKI( "Knockout" ),
2404 []( INSPECTABLE* aItem ) { return false; } );
2405 }
2407
2408
2410{
2412 {
2423
2424 const wxString groupDimension = _HKI( "Dimension Properties" );
2425
2426 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
2429 groupDimension );
2430
2432 _HKI( "Text" ),
2433 []( INSPECTABLE* aItem ) { return false; } );
2435 _HKI( "Vertical Justification" ),
2436 []( INSPECTABLE* aItem ) { return false; } );
2438 _HKI( "Hyperlink" ),
2439 []( INSPECTABLE* aItem ) { return false; } );
2441 _HKI( "Knockout" ),
2442 []( INSPECTABLE* aItem ) { return false; } );
2443 }
2445
2446
2448{
2450 {
2452 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
2453 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
2454 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
2455
2466
2467 const wxString groupDimension = _HKI( "Dimension Properties" );
2468
2471 groupDimension );
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 }
2487
2489
2490
2492{
2494 {
2505
2506
2508 _HKI( "Text" ),
2509 []( INSPECTABLE* aItem ) { return false; } );
2511 _HKI( "Vertical Justification" ),
2512 []( INSPECTABLE* aItem ) { return false; } );
2514 _HKI( "Hyperlink" ),
2515 []( INSPECTABLE* aItem ) { return false; } );
2517 _HKI( "Knockout" ),
2518 []( INSPECTABLE* aItem ) { return false; } );
2519 }
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:85
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:87
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:427
PCB_LAYER_ID GetFlippedLayer(PCB_LAYER_ID aLayer) const
Return the layer paired with aLayer on the opposite side of the board.
PCB_LAYER_ID m_layer
Definition board_item.h:600
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:383
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.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
EDA_UNITS GetUserUnits()
Definition board.h:1032
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:792
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:94
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:68
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:472
PAINTER * GetPainter() const
Return the painter object used by the view for drawing VIEW_ITEM objects.
Definition view.h:242
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 ChangeLineThickness(int aWidth)
int GetLineThickness() const
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)
void ChangeExtensionOffset(int aOffset)
int m_extensionOffset
Distance from feature points to extension line start.
DIM_TEXT_POSITION GetTextPositionMode() const
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.
void ChangeTextPositionMode(DIM_TEXT_POSITION aMode)
virtual VECTOR2I GetEnd() const
void ChangePrecision(DIM_PRECISION aPrecision)
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &aSettings, bool aCheckSide) override
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
int GetExtensionOffset() 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 ChangeArrowLength(int aLength)
void ChangeSuppressZeroes(bool aSuppress)
int GetArrowLength() const
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)
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.
EDA_ANGLE GetLibTextAngle() const
Text angle in the parent footprint's lib frame, or absolute when not in a footprint.
Definition pcb_text.h:128
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &aSettings, bool aCheckSide) override
Definition pcb_text.cpp:371
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:130
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:275
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition property.h:305
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:380
PROPERTY_BASE & SetIsCopyable(bool aIsCopyable=true)
Definition property.h:371
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:93
bool DimensionHasValueMode(const PCB_DIMENSION_BASE *aDimension)
True for dimension types with a measured value aligned orthogonal or radial offering the Driven Drivi...
bool DimensionCanDrive(const 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 DimensionValueMode(const BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
The value mode aDimension is in, derived from state: a self driving length means Driving,...
PCB_CONSTRAINT * FindDimensionLengthConstraint(const BOARD *aBoard, const PCB_DIMENSION_BASE *aDimension)
Self FIXED_LENGTH constraint whose members are exactly aDimension START and END or nullptr the drivin...
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.
#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.
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)
@ MANUAL
Text placement is manually set by the user.
@ 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:899
@ 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:167
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707