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