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, you may find one here:
22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * or you may search the http://www.gnu.org website for the version 2 license,
24 * or you may write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
28#include <bitmaps.h>
29#include <pcb_edit_frame.h>
30#include <base_units.h>
32#include <font/font.h>
33#include <board.h>
34#include <pcb_dimension.h>
35#include <pcb_text.h>
40#include <geometry/shape_rect.h>
44#include <trigo.h>
45#include <api/api_enums.h>
46#include <api/api_utils.h>
47#include <api/board/board_types.pb.h>
48
49
51
52static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
53
54
63static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
64 bool aStart = true )
65{
66 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
67 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
68
69 if( aPoly.Contains( start ) )
70 return std::nullopt;
71
72 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
73 {
74 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
75 {
76 if( ( *intersection - start ).SquaredEuclideanNorm()
77 < ( endpoint - start ).SquaredEuclideanNorm() )
78 endpoint = *intersection;
79 }
80 }
81
82 if( start == endpoint )
83 return std::nullopt;
84
85 return OPT_VECTOR2I( endpoint );
86}
87
88
89static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true )
90{
91 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
92 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
93
94 if( aCircle.Contains( start ) )
95 return std::nullopt;
96
97 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
98
99 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
100 {
101 if( ( intersection - start ).SquaredEuclideanNorm()
102 < ( endpoint - start ).SquaredEuclideanNorm() )
103 endpoint = intersection;
104 }
105
106 if( start == endpoint )
107 return std::nullopt;
108
109 return OPT_VECTOR2I( endpoint );
110}
111
112
117static void CollectKnockedOutSegments( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
118 std::vector<std::shared_ptr<SHAPE>>& aSegmentsAfterKnockout )
119{
120 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
121 const bool containsA = aPoly.Contains( aSeg.A );
122 const bool containsB = aPoly.Contains( aSeg.B );
123
124 const OPT_VECTOR2I endpointA = segPolyIntersection( aPoly, aSeg );
125 const OPT_VECTOR2I endpointB = segPolyIntersection( aPoly, aSeg, false );
126
127 if( endpointA )
128 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg.A, *endpointA ) );
129
130 if( endpointB )
131 {
132 bool can_add = true;
133
134 if( endpointA )
135 {
136 if( ( *endpointB == aSeg.A && *endpointA == aSeg.B )
137 || ( *endpointA == *endpointB && aSeg.A == aSeg.B ) )
138 can_add = false;
139 }
140
141 if( can_add )
142 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( *endpointB, aSeg.B ) );
143 }
144
145 if( !containsA && !containsB && !endpointA && !endpointB )
146 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg ) );
147}
148
149
151 PCB_TEXT( aParent, aType ),
152 m_overrideTextEnabled( false ),
154 m_autoUnits( false ),
158 m_suppressZeroes( false ),
159 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
160 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
163 m_keepTextAligned( true ),
164 m_measuredValue( 0 ),
165 m_inClearRenderCache( false )
166{
168 m_busy = false;
169}
170
171
173{
174 if( Type() != aOther.Type() )
175 return false;
176
177 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
178
179 return *this == other;
180}
181
182
184{
185 if( m_textPosition != aOther.m_textPosition )
186 return false;
187
189 return false;
190
191 if( m_units != aOther.m_units )
192 return false;
193
194 if( m_autoUnits != aOther.m_autoUnits )
195 return false;
196
197 if( m_unitsFormat != aOther.m_unitsFormat )
198 return false;
199
200 if( m_precision != aOther.m_precision )
201 return false;
202
203 if( m_suppressZeroes != aOther.m_suppressZeroes )
204 return false;
205
206 if( m_lineThickness != aOther.m_lineThickness )
207 return false;
208
209 if( m_arrowLength != aOther.m_arrowLength )
210 return false;
211
213 return false;
214
215 if( m_measuredValue != aOther.m_measuredValue )
216 return false;
217
218 return EDA_TEXT::operator==( aOther );
219}
220
221
222double PCB_DIMENSION_BASE::Similarity( const BOARD_ITEM& aOther ) const
223{
224 if( m_Uuid == aOther.m_Uuid )
225 return 1.0;
226
227 if( Type() != aOther.Type() )
228 return 0.0;
229
230 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
231
232 double similarity = 1.0;
233
234 if( m_textPosition != other.m_textPosition )
235 similarity *= 0.9;
236
238 similarity *= 0.9;
239
240 if( m_units != other.m_units )
241 similarity *= 0.9;
242
243 if( m_autoUnits != other.m_autoUnits )
244 similarity *= 0.9;
245
246 if( m_unitsFormat != other.m_unitsFormat )
247 similarity *= 0.9;
248
249 if( m_precision != other.m_precision )
250 similarity *= 0.9;
251
253 similarity *= 0.9;
254
255 if( m_lineThickness != other.m_lineThickness )
256 similarity *= 0.9;
257
258 if( m_arrowLength != other.m_arrowLength )
259 similarity *= 0.9;
260
262 similarity *= 0.9;
263
264 if( m_measuredValue != other.m_measuredValue )
265 similarity *= 0.9;
266
267 similarity *= EDA_TEXT::Similarity( other );
268
269 return similarity;
270}
271
272
273void PCB_DIMENSION_BASE::Serialize( google::protobuf::Any &aContainer ) const
274{
275 using namespace kiapi::common;
276 using namespace kiapi::board::types;
277 Dimension dimension;
278
279 dimension.mutable_id()->set_value( m_Uuid.AsStdString() );
280 dimension.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
281 dimension.set_locked( IsLocked() ? types::LockedState::LS_LOCKED
282 : types::LockedState::LS_UNLOCKED );
283
284 google::protobuf::Any any;
286 any.UnpackTo( dimension.mutable_text() );
287
288 types::Text* text = dimension.mutable_text();
289 text->set_text( GetValueText() );
290
291 dimension.set_override_text_enabled( m_overrideTextEnabled );
292 dimension.set_override_text( m_valueString.ToUTF8() );
293 dimension.set_prefix( m_prefix.ToUTF8() );
294 dimension.set_suffix( m_suffix.ToUTF8() );
295
297 dimension.set_unit_format(
299 dimension.set_arrow_direction(
302 dimension.set_suppress_trailing_zeroes( m_suppressZeroes );
303
304 dimension.mutable_line_thickness()->set_value_nm( m_lineThickness );
305 dimension.mutable_arrow_length()->set_value_nm( m_arrowLength );
306 dimension.mutable_extension_offset()->set_value_nm( m_extensionOffset );
307 dimension.set_text_position(
309 dimension.set_keep_text_aligned( m_keepTextAligned );
310
311 aContainer.PackFrom( dimension );
312}
313
314
315bool PCB_DIMENSION_BASE::Deserialize( const google::protobuf::Any &aContainer )
316{
317 using namespace kiapi::common;
318 kiapi::board::types::Dimension dimension;
319
320 if( !aContainer.UnpackTo( &dimension ) )
321 return false;
322
324 const_cast<KIID&>( m_Uuid ) = KIID( dimension.id().value() );
325 SetLocked( dimension.locked() == types::LockedState::LS_LOCKED );
326
327 google::protobuf::Any any;
328 any.PackFrom( dimension.text() );
330
331 SetOverrideTextEnabled( dimension.override_text_enabled() );
332 SetOverrideText( wxString::FromUTF8( dimension.override_text() ) );
333 SetPrefix( wxString::FromUTF8( dimension.prefix() ) );
334 SetSuffix( wxString::FromUTF8( dimension.suffix() ) );
335
336 SetUnitsMode( FromProtoEnum<DIM_UNITS_MODE>( dimension.unit() ) );
337 SetUnitsFormat( FromProtoEnum<DIM_UNITS_FORMAT>( dimension.unit_format() ) );
338 SetArrowDirection( FromProtoEnum<DIM_ARROW_DIRECTION>( dimension.arrow_direction() ) );
339 SetPrecision( FromProtoEnum<DIM_PRECISION>( dimension.precision() ) );
340 SetSuppressZeroes( dimension.suppress_trailing_zeroes() );
341
342 SetLineThickness( dimension.line_thickness().value_nm() );
343 SetArrowLength( dimension.arrow_length().value_nm() );
344 SetExtensionOffset( dimension.extension_offset().value_nm() );
345 SetTextPositionMode( FromProtoEnum<DIM_TEXT_POSITION>( dimension.text_position() ) );
346 SetKeepTextAligned( dimension.keep_text_aligned() );
347
348 Update();
349
350 return true;
351}
352
353
354void PCB_DIMENSION_BASE::drawAnArrow( VECTOR2I startPoint, EDA_ANGLE anAngle, int aLength )
355{
356 if( aLength )
357 {
358 VECTOR2I tailEnd( aLength, 0 );
359 RotatePoint( tailEnd, -anAngle );
360 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + tailEnd ) );
361 }
362
363 VECTOR2I arrowEndPos( m_arrowLength, 0 );
364 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
365
366 RotatePoint( arrowEndPos, -anAngle + s_arrowAngle );
367 RotatePoint( arrowEndNeg, -anAngle - s_arrowAngle );
368
369 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndPos ) );
370 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndNeg ) );
371}
372
373
375{
377
378 switch( m_unitsFormat )
379 {
380 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
381 break;
382
383 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
385 break;
386
387 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
388 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
389 break;
390 }
391
392 text.Prepend( m_prefix );
393 text.Append( m_suffix );
394
395 SetText( text );
396}
397
398
400{
402
403 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
404 // have changed and we may need to update the dimension text
405
407 {
409 Update();
410 m_inClearRenderCache = false;
411 }
412}
413
414
415template<typename ShapeType>
416void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
417{
418 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
419}
420
421
423{
424 struct lconv* lc = localeconv();
425 wxChar sep = lc->decimal_point[0];
426
427 int val = GetMeasuredValue();
428 int precision = static_cast<int>( m_precision );
429 wxString text;
430
431 if( precision >= 6 )
432 {
433 switch( m_units )
434 {
435 case EDA_UNITS::INCH: precision = precision - 4; break;
436 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
437 case EDA_UNITS::MM: precision = precision - 5; break;
438 default: precision = precision - 4; break;
439 }
440 }
441
442 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
443
444 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
445
446 if( m_suppressZeroes )
447 {
448 while( text.EndsWith( '0' ) )
449 {
450 text.RemoveLast();
451
452 if( text.EndsWith( '.' ) || text.EndsWith( sep ) )
453 {
454 text.RemoveLast();
455 break;
456 }
457 }
458 }
459
460 return text;
461}
462
463
464void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
465{
466 m_prefix = aPrefix;
467}
468
469
470void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
471{
472 m_suffix = aSuffix;
473}
474
475
477{
478 m_units = aUnits;
479}
480
481
483{
484 if( m_autoUnits )
485 {
487 }
488 else
489 {
490 switch( m_units )
491 {
492 default:
496 }
497 }
498}
499
500
502{
503 switch( aMode )
504 {
506 m_autoUnits = false;
508 break;
509
511 m_autoUnits = false;
513 break;
514
516 m_autoUnits = false;
518 break;
519
521 m_autoUnits = true;
523 break;
524 }
525}
526
527
529{
530 SetTextAngleDegrees( aDegrees );
531 // Create or repair any knockouts
532 Update();
533}
534
535
537{
538 SetKeepTextAligned( aKeepAligned );
539 // Re-align the text and repair any knockouts
540 Update();
541}
542
543
545{
546 PCB_TEXT::Offset( offset );
547
548 m_start += offset;
549 m_end += offset;
550
551 Update();
552}
553
554
555void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
556{
557 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
558
559 newAngle.Normalize();
560
561 SetTextAngle( newAngle );
562
563 VECTOR2I pt = GetTextPos();
564 RotatePoint( pt, aRotCentre, aAngle );
565 SetTextPos( pt );
566
567 RotatePoint( m_start, aRotCentre, aAngle );
568 RotatePoint( m_end, aRotCentre, aAngle );
569
570 Update();
571}
572
573
574void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
575{
576 Mirror( aCentre, aFlipDirection );
577
579}
580
581
582void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
583{
584 VECTOR2I newPos = GetTextPos();
585
586 MIRROR( newPos, axis_pos, aFlipDirection );
587
588 SetTextPos( newPos );
589
590 // invert angle
592
593 MIRROR( m_start, axis_pos, aFlipDirection );
594 MIRROR( m_end, axis_pos, aFlipDirection );
595
596 if( IsSideSpecific() )
598
599 Update();
600}
601
602
603void PCB_DIMENSION_BASE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
604{
605 PCB_TEXT::StyleFromSettings( settings, aCheckSide );
606
614
615 Update(); // refresh text & geometry
616
617}
618
619
621 std::vector<MSG_PANEL_ITEM>& aList )
622{
623 // for now, display only the text within the DIMENSION using class PCB_TEXT.
624 wxString msg;
625
626 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
627
628 // Don't use GetShownText(); we want to see the variable references here
629 aList.emplace_back( _( "Dimension" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
630
631 aList.emplace_back( _( "Prefix" ), GetPrefix() );
632
634 {
635 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
636 }
637 else
638 {
639 aList.emplace_back( _( "Value" ), GetValueText() );
640
641 switch( GetPrecision() )
642 {
643 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
644 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
645 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
646 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
647 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
648 }
649
650 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
651 }
652
653 aList.emplace_back( _( "Suffix" ), GetSuffix() );
654
655 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
656 // in frame's units.
657 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
658 unitsProvider.SetUserUnits( GetUnits() );
659
660 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
661
662 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
663 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
664 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
665 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
666
667 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
668
669 if( Type() == PCB_DIM_CENTER_T )
670 {
671 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
672 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
673 aFrame->MessageTextFromValue( startCoord.x ),
674 aFrame->MessageTextFromValue( startCoord.y ) );
675
676 aList.emplace_back( start, wxEmptyString );
677 }
678 else
679 {
680 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
681 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
682 aFrame->MessageTextFromValue( startCoord.x ),
683 aFrame->MessageTextFromValue( startCoord.y ) );
684 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
685 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
686 aFrame->MessageTextFromValue( endCoord.x ),
687 aFrame->MessageTextFromValue( endCoord.y ) );
688
689 aList.emplace_back( start, end );
690 }
691
692 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
693 aList.emplace_back( _( "Status" ), _( "Locked" ) );
694
695 aList.emplace_back( _( "Layer" ), GetLayerName() );
696}
697
698
699std::shared_ptr<SHAPE> PCB_DIMENSION_BASE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
700{
701 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
702
703 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
704
705 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
706 effectiveShape->AddShape( shape->Clone() );
707
708 return effectiveShape;
709}
710
711
712bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
713{
714 if( TextHitTest( aPosition ) )
715 return true;
716
717 int dist_max = aAccuracy + ( m_lineThickness / 2 );
718
719 // Locate SEGMENTS
720
721 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
722 {
723 if( shape->Collide( aPosition, dist_max ) )
724 return true;
725 }
726
727 return false;
728}
729
730
731bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
732{
733 BOX2I arect = aRect;
734 arect.Inflate( aAccuracy );
735
736 BOX2I rect = GetBoundingBox();
737
738 if( aAccuracy )
739 rect.Inflate( aAccuracy );
740
741 if( aContained )
742 return arect.Contains( rect );
743
744 return arect.Intersects( rect );
745}
746
747
748bool PCB_DIMENSION_BASE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
749{
750 // Note: Can't use GetEffectiveShape() because we want text as BoundingBox, not as graphics.
751 SHAPE_COMPOUND effShape;
752
753 // Add shapes
754 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
755 effShape.AddShape( shape );
756
757 if( aContained )
758 return TextHitTest( aPoly, aContained ) && KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
759 else
760 return TextHitTest( aPoly, aContained ) || KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
761}
762
763
765{
766 BOX2I bBox;
767 int xmin, xmax, ymin, ymax;
768
769 bBox = GetTextBox( nullptr );
770 xmin = bBox.GetX();
771 xmax = bBox.GetRight();
772 ymin = bBox.GetY();
773 ymax = bBox.GetBottom();
774
775 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
776 {
777 BOX2I shapeBox = shape->BBox();
778 shapeBox.Inflate( m_lineThickness / 2 );
779
780 xmin = std::min( xmin, shapeBox.GetOrigin().x );
781 xmax = std::max( xmax, shapeBox.GetEnd().x );
782 ymin = std::min( ymin, shapeBox.GetOrigin().y );
783 ymax = std::max( ymax, shapeBox.GetEnd().y );
784 }
785
786 bBox.SetX( xmin );
787 bBox.SetY( ymin );
788 bBox.SetWidth( xmax - xmin + 1 );
789 bBox.SetHeight( ymax - ymin + 1 );
790
791 bBox.Normalize();
792
793 return bBox;
794}
795
796
797wxString PCB_DIMENSION_BASE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
798{
799 return wxString::Format( _( "Dimension '%s' on %s" ),
800 aFull ? GetShownText( false ) : KIUI::EllipsizeMenuText( GetText() ),
801 GetLayerName() );
802}
803
804
805
807{
809 VECTOR2I( GetBoundingBox().GetSize() ) );
810 dimBBox.Merge( PCB_TEXT::ViewBBox() );
811
812 return dimBBox;
813}
814
815
817 int aClearance, int aError, ERROR_LOC aErrorLoc,
818 bool aIgnoreLineWidth ) const
819{
820 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
821
822 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
823 {
824 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
825 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
826
827 if( circle )
828 {
829 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
830 circle->GetRadius() + m_lineThickness / 2 + aClearance,
831 aError, aErrorLoc );
832 }
833 else if( seg )
834 {
835 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
836 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
837 }
838 else
839 {
840 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
841 }
842 }
843}
844
845
847 PCB_DIMENSION_BASE( aParent, aType ),
848 m_height( 0 )
849{
850 // To preserve look of old dimensions, initialize extension height based on default arrow length
851 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
852}
853
854
856{
857 return new PCB_DIM_ALIGNED( *this );
858}
859
860
861void PCB_DIM_ALIGNED::Serialize( google::protobuf::Any &aContainer ) const
862{
863 using namespace kiapi::common;
864 kiapi::board::types::Dimension dimension;
865
866 PCB_DIMENSION_BASE::Serialize( aContainer );
867 aContainer.UnpackTo( &dimension );
868
869 PackVector2( *dimension.mutable_aligned()->mutable_start(), m_start );
870 PackVector2( *dimension.mutable_aligned()->mutable_end(), m_end );
871 dimension.mutable_aligned()->mutable_height()->set_value_nm( m_height );
872 dimension.mutable_aligned()->mutable_extension_height()->set_value_nm( m_extensionHeight );
873
874 aContainer.PackFrom( dimension );
875}
876
877
878bool PCB_DIM_ALIGNED::Deserialize( const google::protobuf::Any &aContainer )
879{
880 using namespace kiapi::common;
881
882 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
883 return false;
884
885 kiapi::board::types::Dimension dimension;
886 aContainer.UnpackTo( &dimension );
887
888 if( !dimension.has_aligned() )
889 return false;
890
891 SetStart( UnpackVector2( dimension.aligned().start() ) );
892 SetEnd( UnpackVector2( dimension.aligned().end() ) );
893 SetHeight( dimension.aligned().height().value_nm());
894 SetExtensionHeight( dimension.aligned().extension_height().value_nm() );
895
896 Update();
897
898 return true;
899}
900
901
903{
904 wxASSERT( aImage->Type() == Type() );
905
906 m_shapes.clear();
907 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
908
909 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
910
911 Update();
912}
913
914
915void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
916{
918 // Call this last for the Update()
919 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
920}
921
922
927
928
929void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
930{
931 VECTOR2D height( aCrossbarStart - GetStart() );
932 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
933
934 if( height.Cross( crossBar ) > 0 )
935 m_height = -height.EuclideanNorm();
936 else
937 m_height = height.EuclideanNorm();
938
939 Update();
940}
941
942
944{
945 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
946 return;
947
948 m_busy = true;
949
950 m_shapes.clear();
951
952 VECTOR2I dimension( m_end - m_start );
953
954 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
955
956 VECTOR2I extension;
957
958 if( m_height > 0 )
959 extension = VECTOR2I( -dimension.y, dimension.x );
960 else
961 extension = VECTOR2I( dimension.y, -dimension.x );
962
963 // Add extension lines
964 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
965
966 VECTOR2I extStart( m_start );
967 extStart += extension.Resize( m_extensionOffset );
968
969 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
970
971 extStart = VECTOR2I( m_end );
972 extStart += extension.Resize( m_extensionOffset );
973
974 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
975
976 // Add crossbar
977 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
978 m_crossBarStart = m_start + crossBarDistance;
979 m_crossBarEnd = m_end + crossBarDistance;
980
981 // Update text after calculating crossbar position but before adding crossbar lines
982 updateText();
983
984 // Now that we have the text updated, we can determine how to draw the crossbar.
985 // First we need to create an appropriate bounding polygon to collide with
986 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, - GetEffectiveTextPenWidth() );
987
988 SHAPE_POLY_SET polyBox;
989 polyBox.NewOutline();
990 polyBox.Append( textBox.GetOrigin() );
991 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
992 polyBox.Append( textBox.GetEnd() );
993 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
994 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
995
996 // The ideal crossbar, if the text doesn't collide
997 SEG crossbar( m_crossBarStart, m_crossBarEnd );
998
999 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1000
1002 {
1003 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ),
1005 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ),
1007 }
1008 else
1009 {
1010 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ), 0 );
1011 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ), 0 );
1012 }
1013
1014 m_busy = false;
1015}
1016
1017
1019{
1020 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1021
1023 {
1024 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1025 EDA_ANGLE rotation;
1026
1027 if( crossbarCenter.x == 0 )
1028 rotation = ANGLE_90 * sign( -crossbarCenter.y );
1029 else if( crossbarCenter.x < 0 )
1030 rotation = -ANGLE_90;
1031 else
1032 rotation = ANGLE_90;
1033
1034 VECTOR2I textOffset = crossbarCenter;
1035 RotatePoint( textOffset, rotation );
1036 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
1037
1038 SetTextPos( m_crossBarStart + textOffset );
1039 }
1041 {
1042 SetTextPos( m_crossBarStart + crossbarCenter );
1043 }
1044
1045 if( m_keepTextAligned )
1046 {
1047 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
1048 textAngle.Normalize();
1049
1050 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1051 textAngle -= ANGLE_180;
1052
1053 SetTextAngle( textAngle );
1054 }
1055
1057}
1058
1059
1060void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1061{
1062 PCB_DIMENSION_BASE::GetMsgPanelInfo( aFrame, aList );
1063
1064 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
1065 // in frame's units.
1066 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
1067 unitsProvider.SetUserUnits( GetUnits() );
1068
1069 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
1070}
1071
1072
1075{
1076 // To preserve look of old dimensions, initialize extension height based on default arrow length
1077 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1079}
1080
1081
1083{
1084 return new PCB_DIM_ORTHOGONAL( *this );
1085}
1086
1087
1088void PCB_DIM_ORTHOGONAL::Serialize( google::protobuf::Any &aContainer ) const
1089{
1090 using namespace kiapi::common;
1091 kiapi::board::types::Dimension dimension;
1092
1093 PCB_DIMENSION_BASE::Serialize( aContainer );
1094 aContainer.UnpackTo( &dimension );
1095
1096 PackVector2( *dimension.mutable_orthogonal()->mutable_start(), m_start );
1097 PackVector2( *dimension.mutable_orthogonal()->mutable_end(), m_end );
1098 dimension.mutable_orthogonal()->mutable_height()->set_value_nm( m_height );
1099 dimension.mutable_orthogonal()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1100
1101 dimension.mutable_orthogonal()->set_alignment( m_orientation == DIR::VERTICAL
1102 ? types::AxisAlignment::AA_Y_AXIS
1103 : types::AxisAlignment::AA_X_AXIS );
1104 aContainer.PackFrom( dimension );
1105}
1106
1107
1108bool PCB_DIM_ORTHOGONAL::Deserialize( const google::protobuf::Any &aContainer )
1109{
1110 using namespace kiapi::common;
1111
1112 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1113 return false;
1114
1115 kiapi::board::types::Dimension dimension;
1116 aContainer.UnpackTo( &dimension );
1117
1118 if( !dimension.has_orthogonal() )
1119 return false;
1120
1121 SetStart( UnpackVector2( dimension.orthogonal().start() ) );
1122 SetEnd( UnpackVector2( dimension.orthogonal().end() ) );
1123 SetHeight( dimension.orthogonal().height().value_nm());
1124 SetExtensionHeight( dimension.orthogonal().extension_height().value_nm() );
1125 SetOrientation( dimension.orthogonal().alignment() == types::AxisAlignment::AA_Y_AXIS
1127 : DIR::HORIZONTAL );
1128
1129 Update();
1130
1131 return true;
1132}
1133
1134
1136{
1137 wxASSERT( aImage->Type() == Type() );
1138
1139 m_shapes.clear();
1140 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
1141
1142 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
1143 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
1144
1145 Update();
1146}
1147
1148
1149void PCB_DIM_ORTHOGONAL::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1150{
1151 // Only reverse the height if the height is aligned with the flip
1152 if( m_orientation == DIR::HORIZONTAL && aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
1153 m_height = -m_height;
1154 else if( m_orientation == DIR::VERTICAL && aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1155 m_height = -m_height;
1156
1157 // Call this last, as we need the Update()
1158 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1159}
1160
1161
1166
1167
1169{
1170 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1171 return;
1172
1173 m_busy = true;
1174 m_shapes.clear();
1175
1177 m_end.y - m_start.y );
1179
1180 VECTOR2I extension;
1181
1183 extension = VECTOR2I( 0, m_height );
1184 else
1185 extension = VECTOR2I( m_height, 0 );
1186
1187 // Add first extension line
1188 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1189
1190 VECTOR2I extStart( m_start );
1191 extStart += extension.Resize( m_extensionOffset );
1192
1193 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1194
1195 // Add crossbar
1196 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1197 m_crossBarStart = m_start + crossBarDistance;
1198
1201 else
1203
1204 // Add second extension line (m_end to crossbar end)
1206 extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y );
1207 else
1208 extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 );
1209
1210 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
1211
1212 extStart = VECTOR2I( m_crossBarEnd );
1213 extStart -= extension.Resize( m_extensionHeight );
1214
1215 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1216
1217 // Update text after calculating crossbar position but before adding crossbar lines
1218 updateText();
1219
1220 // Now that we have the text updated, we can determine how to draw the crossbar.
1221 // First we need to create an appropriate bounding polygon to collide with
1222 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1223
1224 SHAPE_POLY_SET polyBox;
1225 polyBox.NewOutline();
1226 polyBox.Append( textBox.GetOrigin() );
1227 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1228 polyBox.Append( textBox.GetEnd() );
1229 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1230 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1231
1232 // The ideal crossbar, if the text doesn't collide
1233 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1234
1235 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1236
1237 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
1238
1240 {
1241 // Arrows with fixed length.
1242 drawAnArrow( m_crossBarStart, crossBarAngle + EDA_ANGLE( 180 ),
1245 }
1246 else
1247 {
1248 drawAnArrow( m_crossBarStart, crossBarAngle, 0 );
1249 drawAnArrow( m_crossBarEnd, crossBarAngle + EDA_ANGLE( 180 ), 0 );
1250 }
1251
1252 m_busy = false;
1253}
1254
1255
1257{
1258 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1259
1261 {
1262 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1263
1264 VECTOR2I textOffset;
1265
1267 textOffset.y = -textOffsetDistance;
1268 else
1269 textOffset.x = -textOffsetDistance;
1270
1271 textOffset += crossbarCenter;
1272
1273 SetTextPos( m_crossBarStart + textOffset );
1274 }
1276 {
1277 SetTextPos( m_crossBarStart + crossbarCenter );
1278 }
1279
1280 if( m_keepTextAligned )
1281 {
1282 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
1284 else
1286 }
1287
1289}
1290
1291
1292void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1293{
1294 EDA_ANGLE angle( aAngle );
1295
1296 // restrict angle to -179.9 to 180.0 degrees
1297 angle.Normalize180();
1298
1299 // adjust orientation and height to new angle
1300 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
1301 // in the other cases we will use the nearest 90 degree angle to
1302 // choose at least an approximate axis for the target orientation
1303 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
1304 if( angle > ANGLE_45 && angle <= ANGLE_135 )
1305 {
1306 // about 90 degree
1308 {
1310 }
1311 else
1312 {
1314 m_height = -m_height;
1315 }
1316 }
1317 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
1318 {
1319 // about -90 degree
1321 {
1323 m_height = -m_height;
1324 }
1325 else
1326 {
1328 }
1329 }
1330 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
1331 {
1332 // about 180 degree
1333 m_height = -m_height;
1334 }
1335
1336 // this will update m_crossBarStart and m_crossbarEnd
1337 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
1338}
1339
1340
1351
1352
1353void PCB_DIM_LEADER::Serialize( google::protobuf::Any &aContainer ) const
1354{
1355 using namespace kiapi::common;
1356 kiapi::board::types::Dimension dimension;
1357
1358 PCB_DIMENSION_BASE::Serialize( aContainer );
1359 aContainer.UnpackTo( &dimension );
1360
1361 PackVector2( *dimension.mutable_leader()->mutable_start(), m_start );
1362 PackVector2( *dimension.mutable_leader()->mutable_end(), m_end );
1363 dimension.mutable_leader()->set_border_style(
1365 m_textBorder ) );
1366
1367 aContainer.PackFrom( dimension );
1368}
1369
1370
1371bool PCB_DIM_LEADER::Deserialize( const google::protobuf::Any &aContainer )
1372{
1373 using namespace kiapi::common;
1374
1375 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1376 return false;
1377
1378 kiapi::board::types::Dimension dimension;
1379 aContainer.UnpackTo( &dimension );
1380
1381 if( !dimension.has_leader() )
1382 return false;
1383
1384 SetStart( UnpackVector2( dimension.leader().start() ) );
1385 SetEnd( UnpackVector2( dimension.leader().end() ) );
1386 SetTextBorder( FromProtoEnum<DIM_TEXT_BORDER>( dimension.leader().border_style() ) );
1387
1388 Update();
1389
1390 return true;
1391}
1392
1393
1395{
1396 return new PCB_DIM_LEADER( *this );
1397}
1398
1399
1401{
1402 wxASSERT( aImage->Type() == Type() );
1403
1404 m_shapes.clear();
1405 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
1406
1407 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
1408
1409 Update();
1410}
1411
1412
1417
1418
1420{
1421 // Our geometry is dependent on the size of the text, so just update the whole shebang
1423}
1424
1425
1427{
1428 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1429 return;
1430
1431 m_busy = true;
1432
1433 m_shapes.clear();
1434
1436
1437 // Now that we have the text updated, we can determine how to draw the second line
1438 // First we need to create an appropriate bounding polygon to collide with
1439 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1440
1441 SHAPE_POLY_SET polyBox;
1442 polyBox.NewOutline();
1443 polyBox.Append( textBox.GetOrigin() );
1444 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1445 polyBox.Append( textBox.GetEnd() );
1446 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1447 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1448
1449 VECTOR2I firstLine( m_end - m_start );
1450 VECTOR2I start( m_start );
1451 start += firstLine.Resize( m_extensionOffset );
1452
1453 SEG arrowSeg( m_start, m_end );
1454 SEG textSeg( m_end, GetTextPos() );
1455 OPT_VECTOR2I arrowSegEnd;
1456 OPT_VECTOR2I textSegEnd;
1457
1459 {
1460 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1461 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1462 CIRCLE circle( textBox.GetCenter(), radius );
1463
1464 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1465 textSegEnd = segCircleIntersection( circle, textSeg );
1466 }
1467 else
1468 {
1469 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1470 textSegEnd = segPolyIntersection( polyBox, textSeg );
1471 }
1472
1473 if( !arrowSegEnd )
1474 arrowSegEnd = m_end;
1475
1476 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1477
1478 drawAnArrow( start, EDA_ANGLE( firstLine ), 0 );
1479
1480 if( !GetText().IsEmpty() )
1481 {
1482 switch( m_textBorder )
1483 {
1485 {
1486 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1487 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1488
1489 break;
1490 }
1491
1493 {
1494 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1495 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1496 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1497
1498 break;
1499 }
1500
1501 default:
1502 break;
1503 }
1504 }
1505
1506 if( textSegEnd && *arrowSegEnd == m_end )
1507 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, *textSegEnd ) );
1508
1509 m_busy = false;
1510}
1511
1512
1513void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1514{
1515 // Don't use GetShownText(); we want to see the variable references here
1516 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1517
1518 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
1519
1520 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1521 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1522 aFrame->MessageTextFromValue( startCoord.x ),
1523 aFrame->MessageTextFromValue( startCoord.y ) );
1524
1525 aList.emplace_back( start, wxEmptyString );
1526
1527 aList.emplace_back( _( "Layer" ), GetLayerName() );
1528}
1529
1530
1540
1541
1542void PCB_DIM_RADIAL::Serialize( google::protobuf::Any &aContainer ) const
1543{
1544 using namespace kiapi::common;
1545 kiapi::board::types::Dimension dimension;
1546
1547 PCB_DIMENSION_BASE::Serialize( aContainer );
1548 aContainer.UnpackTo( &dimension );
1549
1550 PackVector2( *dimension.mutable_radial()->mutable_center(), m_start );
1551 PackVector2( *dimension.mutable_radial()->mutable_radius_point(), m_end );
1552 dimension.mutable_radial()->mutable_leader_length()->set_value_nm( m_leaderLength );
1553
1554 aContainer.PackFrom( dimension );
1555}
1556
1557
1558bool PCB_DIM_RADIAL::Deserialize( const google::protobuf::Any &aContainer )
1559{
1560 using namespace kiapi::common;
1561
1562 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1563 return false;
1564
1565 kiapi::board::types::Dimension dimension;
1566 aContainer.UnpackTo( &dimension );
1567
1568 if( !dimension.has_radial() )
1569 return false;
1570
1571 SetStart( UnpackVector2( dimension.radial().center() ) );
1572 SetEnd( UnpackVector2( dimension.radial().radius_point() ) );
1573 SetLeaderLength( dimension.radial().leader_length().value_nm() );
1574
1575 Update();
1576
1577 return true;
1578}
1579
1580
1582{
1583 return new PCB_DIM_RADIAL( *this );
1584}
1585
1586
1588{
1589 wxASSERT( aImage->Type() == Type() );
1590
1591 m_shapes.clear();
1592 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1593
1594 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1595
1596 Update();
1597}
1598
1599
1604
1605
1607{
1608 VECTOR2I radial( m_end - m_start );
1609
1610 return m_end + radial.Resize( m_leaderLength );
1611}
1612
1613
1615{
1616 if( m_keepTextAligned )
1617 {
1618 VECTOR2I textLine( GetTextPos() - GetKnee() );
1619 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1620
1621 textAngle.Normalize();
1622
1623 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1624 textAngle -= ANGLE_180;
1625
1626 // Round to nearest degree
1627 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1628
1629 SetTextAngle( textAngle );
1630 }
1631
1633}
1634
1635
1637{
1638 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1639 return;
1640
1641 m_busy = true;
1642
1643 m_shapes.clear();
1644
1646 VECTOR2I centerArm( 0, m_arrowLength );
1647
1648 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1649
1650 RotatePoint( centerArm, -ANGLE_90 );
1651
1652 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1653
1655
1656 m_measuredValue = KiROUND( radius.EuclideanNorm() );
1657
1658 updateText();
1659
1660 // Now that we have the text updated, we can determine how to draw the second line
1661 // First we need to create an appropriate bounding polygon to collide with
1662 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1663
1664 SHAPE_POLY_SET polyBox;
1665 polyBox.NewOutline();
1666 polyBox.Append( textBox.GetOrigin() );
1667 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1668 polyBox.Append( textBox.GetEnd() );
1669 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1670 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1671
1672 VECTOR2I radial( m_end - m_start );
1673 radial = radial.Resize( m_leaderLength );
1674
1675 SEG arrowSeg( m_end, m_end + radial );
1676 SEG textSeg( arrowSeg.B, GetTextPos() );
1677
1678 CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
1679 CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
1680
1681 drawAnArrow( m_end, EDA_ANGLE( radial ), 0 );
1682
1683 m_busy = false;
1684}
1685
1686
1693
1694
1695void PCB_DIM_CENTER::Serialize( google::protobuf::Any &aContainer ) const
1696{
1697 using namespace kiapi::common;
1698 kiapi::board::types::Dimension dimension;
1699
1700 PCB_DIMENSION_BASE::Serialize( aContainer );
1701 aContainer.UnpackTo( &dimension );
1702
1703 PackVector2( *dimension.mutable_center()->mutable_center(), m_start );
1704 PackVector2( *dimension.mutable_center()->mutable_end(), m_end );
1705
1706 aContainer.PackFrom( dimension );
1707}
1708
1709
1710bool PCB_DIM_CENTER::Deserialize( const google::protobuf::Any &aContainer )
1711{
1712 using namespace kiapi::common;
1713
1714 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1715 return false;
1716
1717 kiapi::board::types::Dimension dimension;
1718 aContainer.UnpackTo( &dimension );
1719
1720 if( !dimension.has_center() )
1721 return false;
1722
1723 SetStart( UnpackVector2( dimension.center().center() ) );
1724 SetEnd( UnpackVector2( dimension.center().end() ) );
1725
1726 Update();
1727
1728 return true;
1729}
1730
1731
1733{
1734 return new PCB_DIM_CENTER( *this );
1735}
1736
1737
1739{
1740 wxASSERT( aImage->Type() == Type() );
1741
1742 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1743}
1744
1745
1750
1751
1753{
1754 BOX2I bBox;
1755 int xmin, xmax, ymin, ymax;
1756
1757 xmin = m_start.x;
1758 xmax = m_start.x;
1759 ymin = m_start.y;
1760 ymax = m_start.y;
1761
1762 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
1763 {
1764 BOX2I shapeBox = shape->BBox();
1765 shapeBox.Inflate( m_lineThickness / 2 );
1766
1767 xmin = std::min( xmin, shapeBox.GetOrigin().x );
1768 xmax = std::max( xmax, shapeBox.GetEnd().x );
1769 ymin = std::min( ymin, shapeBox.GetOrigin().y );
1770 ymax = std::max( ymax, shapeBox.GetEnd().y );
1771 }
1772
1773 bBox.SetX( xmin );
1774 bBox.SetY( ymin );
1775 bBox.SetWidth( xmax - xmin + 1 );
1776 bBox.SetHeight( ymax - ymin + 1 );
1777
1778 bBox.Normalize();
1779
1780 return bBox;
1781}
1782
1783
1785{
1786 return GetBoundingBox();
1787}
1788
1789
1791{
1792 // Even if PCB_DIM_CENTER has no text, we still need to update its text position
1793 // so GetTextPos() users get a valid value. Required at least for lasso hit-testing.
1795
1797}
1798
1799
1801{
1802 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1803 return;
1804
1805 m_busy = true;
1806
1807 m_shapes.clear();
1808
1810 VECTOR2I arm( m_end - m_start );
1811
1812 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1813
1814 RotatePoint( arm, -ANGLE_90 );
1815
1816 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1817
1818 updateText();
1819
1820 m_busy = false;
1821}
1822
1823
1824static struct DIMENSION_DESC
1825{
1827 {
1829 .Map( DIM_PRECISION::X, _HKI( "0" ) )
1830 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
1831 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
1832 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
1833 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
1834 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
1835 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
1836 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
1837 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
1838 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
1839
1841 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
1842 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
1843 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
1844
1846 .Map( DIM_UNITS_MODE::INCH, _HKI( "Inches" ) )
1847 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
1848 .Map( DIM_UNITS_MODE::MM, _HKI( "Millimeters" ) )
1849 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
1850
1852 .Map( DIM_ARROW_DIRECTION::INWARD, _HKI( "Inward" ) )
1853 .Map( DIM_ARROW_DIRECTION::OUTWARD, _HKI( "Outward" ) );
1854
1863
1864 propMgr.Mask( TYPE_HASH( PCB_DIMENSION_BASE ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
1865
1866 const wxString groupDimension = _HKI( "Dimension Properties" );
1867
1868 auto isLeader =
1869 []( INSPECTABLE* aItem ) -> bool
1870 {
1871 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
1872 };
1873
1874 auto isNotLeader =
1875 []( INSPECTABLE* aItem ) -> bool
1876 {
1877 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
1878 };
1879
1880 auto isMultiArrowDirection =
1881 []( INSPECTABLE* aItem ) -> bool
1882 {
1883 return dynamic_cast<PCB_DIM_ALIGNED*>( aItem ) != nullptr;
1884 };
1885
1888 groupDimension )
1889 .SetAvailableFunc( isNotLeader );
1892 groupDimension )
1893 .SetAvailableFunc( isNotLeader );
1894 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
1896 groupDimension )
1897 .SetAvailableFunc( isNotLeader );
1898
1901 groupDimension )
1902 .SetAvailableFunc( isLeader );
1903
1906 groupDimension )
1907 .SetAvailableFunc( isNotLeader );
1910 groupDimension )
1911 .SetAvailableFunc( isNotLeader );
1914 groupDimension )
1915 .SetAvailableFunc( isNotLeader );
1916 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
1918 groupDimension )
1919 .SetAvailableFunc( isNotLeader );
1920
1923 groupDimension )
1924 .SetAvailableFunc( isMultiArrowDirection );
1925
1926 const wxString groupText = _HKI( "Text Properties" );
1927
1928 const auto isTextOrientationWriteable =
1929 []( INSPECTABLE* aItem ) -> bool
1930 {
1931 return !static_cast<PCB_DIMENSION_BASE*>( aItem )->GetKeepTextAligned();
1932 };
1933
1934 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Keep Aligned with Dimension" ),
1937 groupText );
1938
1939 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, double>( _HKI( "Orientation" ),
1943 groupText )
1944 .SetWriteableFunc( isTextOrientationWriteable );
1945 }
1947
1952
1953
1955{
1957 {
1968
1969 const wxString groupDimension = _HKI( "Dimension Properties" );
1970
1971 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
1974 groupDimension );
1975 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
1978 groupDimension );
1979
1981 _HKI( "Text" ),
1982 []( INSPECTABLE* aItem ) { return false; } );
1984 _HKI( "Vertical Justification" ),
1985 []( INSPECTABLE* aItem ) { return false; } );
1987 _HKI( "Hyperlink" ),
1988 []( INSPECTABLE* aItem ) { return false; } );
1990 _HKI( "Knockout" ),
1991 []( INSPECTABLE* aItem ) { return false; } );
1992 }
1994
1995
1997{
1999 {
2012
2014 _HKI( "Text" ),
2015 []( INSPECTABLE* aItem ) { return false; } );
2017 _HKI( "Vertical Justification" ),
2018 []( INSPECTABLE* aItem ) { return false; } );
2020 _HKI( "Hyperlink" ),
2021 []( INSPECTABLE* aItem ) { return false; } );
2023 _HKI( "Knockout" ),
2024 []( INSPECTABLE* aItem ) { return false; } );
2025 }
2027
2028
2030{
2032 {
2043
2044 const wxString groupDimension = _HKI( "Dimension Properties" );
2045
2046 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
2049 groupDimension );
2050
2052 _HKI( "Text" ),
2053 []( INSPECTABLE* aItem ) { return false; } );
2055 _HKI( "Vertical Justification" ),
2056 []( INSPECTABLE* aItem ) { return false; } );
2058 _HKI( "Hyperlink" ),
2059 []( INSPECTABLE* aItem ) { return false; } );
2061 _HKI( "Knockout" ),
2062 []( INSPECTABLE* aItem ) { return false; } );
2063 }
2065
2066
2068{
2070 {
2072 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
2073 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
2074 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
2075
2086
2087 const wxString groupDimension = _HKI( "Dimension Properties" );
2088
2091 groupDimension );
2092
2094 _HKI( "Text" ),
2095 []( INSPECTABLE* aItem ) { return false; } );
2097 _HKI( "Vertical Justification" ),
2098 []( INSPECTABLE* aItem ) { return false; } );
2100 _HKI( "Hyperlink" ),
2101 []( INSPECTABLE* aItem ) { return false; } );
2103 _HKI( "Knockout" ),
2104 []( INSPECTABLE* aItem ) { return false; } );
2105 }
2107
2109
2110
2112{
2114 {
2125
2126
2128 _HKI( "Text" ),
2129 []( INSPECTABLE* aItem ) { return false; } );
2131 _HKI( "Vertical Justification" ),
2132 []( INSPECTABLE* aItem ) { return false; } );
2134 _HKI( "Hyperlink" ),
2135 []( INSPECTABLE* aItem ) { return false; } );
2137 _HKI( "Knockout" ),
2138 []( INSPECTABLE* aItem ) { return false; } );
2139 }
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
Definition api_enums.cpp:96
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:35
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:112
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:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
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:79
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:81
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:232
void SetLocked(bool aLocked) override
Definition board_item.h:323
PCB_LAYER_ID m_layer
Definition board_item.h:453
bool IsLocked() const override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:280
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
bool IsSideSpecific() const
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
EDA_UNITS GetUserUnits()
Definition board.h:770
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr void SetHeight(size_type val)
Definition box2.h:292
constexpr const Vec GetEnd() const
Definition box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr coord_type GetY() const
Definition box2.h:208
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr coord_type GetX() const
Definition box2.h:207
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr void SetWidth(size_type val)
Definition box2.h:287
constexpr void SetX(coord_type val)
Definition box2.h:277
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr void SetY(coord_type val)
Definition box2.h:282
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
constexpr coord_type GetBottom() const
Definition box2.h:222
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:221
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:229
double AsDegrees() const
Definition eda_angle.h:116
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
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:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:528
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:80
int GetTextHeight() const
Definition eda_text.h:267
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition eda_text.cpp:198
const VECTOR2I & GetTextPos() const
Definition eda_text.h:273
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:147
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:589
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition eda_text.cpp:234
KIFONT::FONT * GetFont() const
Definition eda_text.h:247
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:404
int GetTextWidth() const
Definition eda_text.h:264
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:755
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:607
double Similarity(const EDA_TEXT &aOther) const
virtual void ClearRenderCache()
Definition eda_text.cpp:682
bool IsMirrored() const
Definition eda_text.h:190
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:476
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:150
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:281
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:310
int GetTextThickness() const
Definition eda_text.h:128
bool operator==(const EDA_TEXT &aRhs) const
Definition eda_text.h:396
static ENUM_MAP< T > & Instance()
Definition property.h:721
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:37
Definition kiid.h:49
A class to perform either relative or absolute display origin transforms for a single axis of a point...
T ToDisplayAbs(const T &aValue) const
Abstract dimension API.
EDA_UNITS GetUnits() const
bool m_autoUnits
If true, follow the currently selected UI units.
void 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)
wxString GetOverrideText() const
wxString GetSuffix() const
std::vector< std::shared_ptr< SHAPE > > m_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.
void Move(const VECTOR2I &offset) override
Move this object.
void SetUnitsFormat(const DIM_UNITS_FORMAT aFormat)
bool m_suppressZeroes
Suppress trailing zeroes.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
void SetUnits(EDA_UNITS aUnits)
DIM_PRECISION m_precision
Number of digits to display after decimal.
void addShape(const ShapeType &aShape)
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
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)
void SetSuppressZeroes(bool aSuppress)
bool m_inClearRenderCache
re-entrancy guard
PCB_DIMENSION_BASE(BOARD_ITEM *aParent, KICAD_T aType=PCB_DIMENSION_T)
int m_extensionOffset
Distance from feature points to extension line start.
void ChangeArrowDirection(const DIM_ARROW_DIRECTION &aDirection)
bool GetKeepTextAligned() const
void 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
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_UNITS_FORMAT GetUnitsFormat() const
void SetLineThickness(int aWidth)
void SetArrowLength(int aLength)
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
DIM_ARROW_DIRECTION GetArrowDirection() const
wxString m_valueString
Displayed value when m_overrideValue = true.
void ChangePrecision(DIM_PRECISION aPrecision)
virtual void SetEnd(const VECTOR2I &aPoint)
void SetPrecision(DIM_PRECISION aPrecision)
bool m_overrideTextEnabled
Manually specify the displayed measurement value.
virtual void SetStart(const VECTOR2I &aPoint)
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
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.
DIM_ARROW_DIRECTION m_arrowDirection
direction of dimension arrow.
void ChangeKeepTextAligned(bool aKeepAligned)
void ChangeUnitsFormat(const DIM_UNITS_FORMAT aFormat)
void ChangeSuppressZeroes(bool aSuppress)
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
double GetTextAngleDegreesProp() const
bool GetOverrideTextEnabled() const
void SetUnitsMode(DIM_UNITS_MODE aMode)
int m_arrowLength
Length of arrow shapes.
virtual const VECTOR2I & GetEnd() const
virtual void Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
VECTOR2I m_end
Internal cache of drawn shapes.
void ChangeUnitsMode(DIM_UNITS_MODE aMode)
void SetKeepTextAligned(bool aKeepAligned)
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
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 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.
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
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 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 Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void ChangeLeaderLength(int aLength)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
VECTOR2I GetKnee() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
Definition pcb_text.cpp:314
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition pcb_text.cpp:206
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition pcb_text.cpp:139
PCB_TEXT(BOARD_ITEM *parent, KICAD_T idtype=PCB_TEXT_T)
Definition pcb_text.cpp:49
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition pcb_text.cpp:369
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_text.cpp:483
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition property.h:287
Provide class metadata.Helper macro to map type hashes to names.
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:42
VECTOR2I A
Definition seg.h:49
VECTOR2I B
Definition seg.h:50
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
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:546
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:283
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:385
A type-safe container of any type.
Definition ki_any.h:93
void TransformCircleToPolygon(SHAPE_LINE_CHAIN &aBuffer, const VECTOR2I &aCenter, int aRadius, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a circle to a polygon, using multiple straight lines.
void TransformOvalToPolygon(SHAPE_POLY_SET &aBuffer, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, int aError, ERROR_LOC aErrorLoc, int aMinSegCount=0)
Convert a oblong shape to a polygon, using multiple segments.
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
@ DEGREES_T
Definition eda_angle.h:31
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:412
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
static constexpr EDA_ANGLE FULL_CIRCLE
Definition eda_angle.h:409
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
static constexpr EDA_ANGLE ANGLE_135
Definition eda_angle.h:414
#define PCB_EDIT_FRAME_NAME
EDA_UNITS
Definition eda_units.h:48
a few functions useful in geometry calculations.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:172
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:184
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ Dwgs_User
Definition layer_ids.h:107
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:45
FLIP_DIRECTION
Definition mirror.h:27
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:28
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:29
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 VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition api_utils.cpp:86
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput)
Definition api_utils.cpp:79
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
#define _HKI(x)
Definition page_info.cpp:44
static const int INWARD_ARROW_LENGTH_TO_HEAD_RATIO
static const EDA_ANGLE s_arrowAngle(27.5, DEGREES_T)
static struct DIMENSION_DESC _DIMENSION_DESC
static OPT_VECTOR2I segPolyIntersection(const SHAPE_POLY_SET &aPoly, const SEG &aSeg, bool aStart=true)
Find the intersection between a given segment and polygon outline.
static OPT_VECTOR2I segCircleIntersection(CIRCLE &aCircle, SEG &aSeg, bool aStart=true)
static void CollectKnockedOutSegments(const SHAPE_POLY_SET &aPoly, const SEG &aSeg, std::vector< std::shared_ptr< SHAPE > > &aSegmentsAfterKnockout)
Knockout a polygon from a segment.
DIM_TEXT_POSITION
Where to place the text on a dimension.
@ OUTSIDE
Text appears outside the dimension line (default)
@ INLINE
Text appears in line with the dimension line.
DIM_UNITS_FORMAT
How to display the units in a dimension's text.
DIM_UNITS_MODE
Used for storing the units selection in the file because EDA_UNITS alone doesn't cut it.
DIM_ARROW_DIRECTION
Used for dimension's arrow.
DIM_TEXT_BORDER
Frame to show around dimension text.
DIM_PRECISION
#define TYPE_HASH(x)
Definition property.h:74
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:823
@ 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)
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:39
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:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:106
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:103
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:104
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:105
constexpr int sign(T val)
Definition util.h:145
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694