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#include <properties/property.h>
50
51
53
54static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
55
56
65static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
66 bool aStart = true )
67{
68 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
69 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
70
71 if( aPoly.Contains( start ) )
72 return std::nullopt;
73
74 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
75 {
76 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
77 {
78 if( ( *intersection - start ).SquaredEuclideanNorm()
79 < ( endpoint - start ).SquaredEuclideanNorm() )
80 endpoint = *intersection;
81 }
82 }
83
84 if( start == endpoint )
85 return std::nullopt;
86
87 return OPT_VECTOR2I( endpoint );
88}
89
90
91static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true )
92{
93 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
94 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
95
96 if( aCircle.Contains( start ) )
97 return std::nullopt;
98
99 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
100
101 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
102 {
103 if( ( intersection - start ).SquaredEuclideanNorm()
104 < ( endpoint - start ).SquaredEuclideanNorm() )
105 endpoint = intersection;
106 }
107
108 if( start == endpoint )
109 return std::nullopt;
110
111 return OPT_VECTOR2I( endpoint );
112}
113
114
119static void CollectKnockedOutSegments( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
120 std::vector<std::shared_ptr<SHAPE>>& aSegmentsAfterKnockout )
121{
122 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
123 const bool containsA = aPoly.Contains( aSeg.A );
124 const bool containsB = aPoly.Contains( aSeg.B );
125
126 const OPT_VECTOR2I endpointA = segPolyIntersection( aPoly, aSeg );
127 const OPT_VECTOR2I endpointB = segPolyIntersection( aPoly, aSeg, false );
128
129 if( endpointA )
130 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg.A, *endpointA ) );
131
132 if( endpointB )
133 {
134 bool can_add = true;
135
136 if( endpointA )
137 {
138 if( ( *endpointB == aSeg.A && *endpointA == aSeg.B )
139 || ( *endpointA == *endpointB && aSeg.A == aSeg.B ) )
140 can_add = false;
141 }
142
143 if( can_add )
144 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( *endpointB, aSeg.B ) );
145 }
146
147 if( !containsA && !containsB && !endpointA && !endpointB )
148 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg ) );
149}
150
151
153 PCB_TEXT( aParent, aType ),
154 m_overrideTextEnabled( false ),
156 m_autoUnits( false ),
160 m_suppressZeroes( false ),
161 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
162 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
165 m_keepTextAligned( true ),
166 m_measuredValue( 0 ),
167 m_inClearRenderCache( false )
168{
170 m_busy = false;
171}
172
173
175{
176 if( Type() != aOther.Type() )
177 return false;
178
179 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
180
181 return *this == other;
182}
183
184
186{
187 if( m_textPosition != aOther.m_textPosition )
188 return false;
189
191 return false;
192
193 if( m_units != aOther.m_units )
194 return false;
195
196 if( m_autoUnits != aOther.m_autoUnits )
197 return false;
198
199 if( m_unitsFormat != aOther.m_unitsFormat )
200 return false;
201
202 if( m_precision != aOther.m_precision )
203 return false;
204
205 if( m_suppressZeroes != aOther.m_suppressZeroes )
206 return false;
207
208 if( m_lineThickness != aOther.m_lineThickness )
209 return false;
210
211 if( m_arrowLength != aOther.m_arrowLength )
212 return false;
213
215 return false;
216
217 if( m_measuredValue != aOther.m_measuredValue )
218 return false;
219
220 return EDA_TEXT::operator==( aOther );
221}
222
223
224double PCB_DIMENSION_BASE::Similarity( const BOARD_ITEM& aOther ) const
225{
226 if( m_Uuid == aOther.m_Uuid )
227 return 1.0;
228
229 if( Type() != aOther.Type() )
230 return 0.0;
231
232 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
233
234 double similarity = 1.0;
235
236 if( m_textPosition != other.m_textPosition )
237 similarity *= 0.9;
238
240 similarity *= 0.9;
241
242 if( m_units != other.m_units )
243 similarity *= 0.9;
244
245 if( m_autoUnits != other.m_autoUnits )
246 similarity *= 0.9;
247
248 if( m_unitsFormat != other.m_unitsFormat )
249 similarity *= 0.9;
250
251 if( m_precision != other.m_precision )
252 similarity *= 0.9;
253
255 similarity *= 0.9;
256
257 if( m_lineThickness != other.m_lineThickness )
258 similarity *= 0.9;
259
260 if( m_arrowLength != other.m_arrowLength )
261 similarity *= 0.9;
262
264 similarity *= 0.9;
265
266 if( m_measuredValue != other.m_measuredValue )
267 similarity *= 0.9;
268
269 similarity *= EDA_TEXT::Similarity( other );
270
271 return similarity;
272}
273
274
275void PCB_DIMENSION_BASE::Serialize( google::protobuf::Any &aContainer ) const
276{
277 using namespace kiapi::common;
278 using namespace kiapi::board::types;
279 Dimension dimension;
280
281 dimension.mutable_id()->set_value( m_Uuid.AsStdString() );
282 dimension.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
283 dimension.set_locked( IsLocked() ? types::LockedState::LS_LOCKED
284 : types::LockedState::LS_UNLOCKED );
285
286 google::protobuf::Any any;
288 any.UnpackTo( dimension.mutable_text() );
289
290 types::Text* text = dimension.mutable_text();
291 text->set_text( GetValueText() );
292
293 dimension.set_override_text_enabled( m_overrideTextEnabled );
294 dimension.set_override_text( m_valueString.ToUTF8() );
295 dimension.set_prefix( m_prefix.ToUTF8() );
296 dimension.set_suffix( m_suffix.ToUTF8() );
297
299 dimension.set_unit_format(
301 dimension.set_arrow_direction(
304 dimension.set_suppress_trailing_zeroes( m_suppressZeroes );
305
306 dimension.mutable_line_thickness()->set_value_nm( m_lineThickness );
307 dimension.mutable_arrow_length()->set_value_nm( m_arrowLength );
308 dimension.mutable_extension_offset()->set_value_nm( m_extensionOffset );
309 dimension.set_text_position(
311 dimension.set_keep_text_aligned( m_keepTextAligned );
312
313 aContainer.PackFrom( dimension );
314}
315
316
317bool PCB_DIMENSION_BASE::Deserialize( const google::protobuf::Any &aContainer )
318{
319 using namespace kiapi::common;
320 kiapi::board::types::Dimension dimension;
321
322 if( !aContainer.UnpackTo( &dimension ) )
323 return false;
324
326 SetUuidDirect( KIID( dimension.id().value() ) );
327 SetLocked( dimension.locked() == types::LockedState::LS_LOCKED );
328
329 google::protobuf::Any any;
330 any.PackFrom( dimension.text() );
332
333 SetOverrideTextEnabled( dimension.override_text_enabled() );
334 SetOverrideText( wxString::FromUTF8( dimension.override_text() ) );
335 SetPrefix( wxString::FromUTF8( dimension.prefix() ) );
336 SetSuffix( wxString::FromUTF8( dimension.suffix() ) );
337
338 SetUnitsMode( FromProtoEnum<DIM_UNITS_MODE>( dimension.unit() ) );
339 SetUnitsFormat( FromProtoEnum<DIM_UNITS_FORMAT>( dimension.unit_format() ) );
340 SetArrowDirection( FromProtoEnum<DIM_ARROW_DIRECTION>( dimension.arrow_direction() ) );
341 SetPrecision( FromProtoEnum<DIM_PRECISION>( dimension.precision() ) );
342 SetSuppressZeroes( dimension.suppress_trailing_zeroes() );
343
344 SetLineThickness( dimension.line_thickness().value_nm() );
345 SetArrowLength( dimension.arrow_length().value_nm() );
346 SetExtensionOffset( dimension.extension_offset().value_nm() );
347 SetTextPositionMode( FromProtoEnum<DIM_TEXT_POSITION>( dimension.text_position() ) );
348 SetKeepTextAligned( dimension.keep_text_aligned() );
349
350 Update();
351
352 return true;
353}
354
355
356void PCB_DIMENSION_BASE::drawAnArrow( VECTOR2I startPoint, EDA_ANGLE anAngle, int aLength )
357{
358 if( aLength )
359 {
360 VECTOR2I tailEnd( aLength, 0 );
361 RotatePoint( tailEnd, -anAngle );
362 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + tailEnd ) );
363 }
364
365 VECTOR2I arrowEndPos( m_arrowLength, 0 );
366 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
367
368 RotatePoint( arrowEndPos, -anAngle + s_arrowAngle );
369 RotatePoint( arrowEndNeg, -anAngle - s_arrowAngle );
370
371 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndPos ) );
372 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndNeg ) );
373}
374
375
377{
379
380 switch( m_unitsFormat )
381 {
382 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
383 break;
384
385 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
387 break;
388
389 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
390 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
391 break;
392 }
393
394 text.Prepend( m_prefix );
395 text.Append( m_suffix );
396
397 SetText( text );
398}
399
400
402{
404
405 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
406 // have changed and we may need to update the dimension text
407
409 {
411 Update();
412 m_inClearRenderCache = false;
413 }
414}
415
416
417template<typename ShapeType>
418void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
419{
420 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
421}
422
423
425{
426 struct lconv* lc = localeconv();
427 wxChar sep = lc->decimal_point[0];
428
429 int val = GetMeasuredValue();
430 int precision = static_cast<int>( m_precision );
431 wxString text;
432
433 if( precision >= 6 )
434 {
435 switch( m_units )
436 {
437 case EDA_UNITS::INCH: precision = precision - 4; break;
438 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
439 case EDA_UNITS::MM: precision = precision - 5; break;
440 default: precision = precision - 4; break;
441 }
442 }
443
444 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
445
446 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
447
448 if( m_suppressZeroes )
449 {
450 while( text.EndsWith( '0' ) )
451 {
452 text.RemoveLast();
453
454 if( text.EndsWith( '.' ) || text.EndsWith( sep ) )
455 {
456 text.RemoveLast();
457 break;
458 }
459 }
460 }
461
462 return text;
463}
464
465
466void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
467{
468 m_prefix = aPrefix;
469}
470
471
472void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
473{
474 m_suffix = aSuffix;
475}
476
477
479{
480 m_units = aUnits;
481}
482
483
485{
486 if( m_autoUnits )
487 {
489 }
490 else
491 {
492 switch( m_units )
493 {
494 default:
498 }
499 }
500}
501
502
504{
505 switch( aMode )
506 {
508 m_autoUnits = false;
510 break;
511
513 m_autoUnits = false;
515 break;
516
518 m_autoUnits = false;
520 break;
521
523 m_autoUnits = true;
525 break;
526 }
527}
528
529
531{
532 SetTextAngleDegrees( aDegrees );
533 // Create or repair any knockouts
534 Update();
535}
536
537
539{
540 SetKeepTextAligned( aKeepAligned );
541 // Re-align the text and repair any knockouts
542 Update();
543}
544
545
547{
548 PCB_TEXT::Offset( offset );
549
550 m_start += offset;
551 m_end += offset;
552
553 Update();
554}
555
556
557void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
558{
559 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
560
561 newAngle.Normalize();
562
563 SetTextAngle( newAngle );
564
565 VECTOR2I pt = GetTextPos();
566 RotatePoint( pt, aRotCentre, aAngle );
567 SetTextPos( pt );
568
569 RotatePoint( m_start, aRotCentre, aAngle );
570 RotatePoint( m_end, aRotCentre, aAngle );
571
572 Update();
573}
574
575
576void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
577{
578 Mirror( aCentre, aFlipDirection );
579
581}
582
583
584void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
585{
586 VECTOR2I newPos = GetTextPos();
587
588 MIRROR( newPos, axis_pos, aFlipDirection );
589
590 SetTextPos( newPos );
591
592 // invert angle
594
595 MIRROR( m_start, axis_pos, aFlipDirection );
596 MIRROR( m_end, axis_pos, aFlipDirection );
597
598 if( IsSideSpecific() )
600
601 Update();
602}
603
604
605void PCB_DIMENSION_BASE::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings, bool aCheckSide )
606{
607 PCB_TEXT::StyleFromSettings( settings, aCheckSide );
608
616
617 Update(); // refresh text & geometry
618
619}
620
621
623 std::vector<MSG_PANEL_ITEM>& aList )
624{
625 // for now, display only the text within the DIMENSION using class PCB_TEXT.
626 wxString msg;
627
628 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
629
630 // Don't use GetShownText(); we want to see the variable references here
631 aList.emplace_back( _( "Dimension" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
632
633 aList.emplace_back( _( "Prefix" ), GetPrefix() );
634
636 {
637 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
638 }
639 else
640 {
641 aList.emplace_back( _( "Value" ), GetValueText() );
642
643 switch( GetPrecision() )
644 {
645 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
646 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
647 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
648 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
649 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
650 }
651
652 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
653 }
654
655 aList.emplace_back( _( "Suffix" ), GetSuffix() );
656
657 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
658 // in frame's units.
659 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
660 unitsProvider.SetUserUnits( GetUnits() );
661
662 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
663
664 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
665 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
666 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
667 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
668
669 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
670
671 if( Type() == PCB_DIM_CENTER_T )
672 {
673 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
674 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
675 aFrame->MessageTextFromValue( startCoord.x ),
676 aFrame->MessageTextFromValue( startCoord.y ) );
677
678 aList.emplace_back( start, wxEmptyString );
679 }
680 else
681 {
682 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
683 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
684 aFrame->MessageTextFromValue( startCoord.x ),
685 aFrame->MessageTextFromValue( startCoord.y ) );
686 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
687 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
688 aFrame->MessageTextFromValue( endCoord.x ),
689 aFrame->MessageTextFromValue( endCoord.y ) );
690
691 aList.emplace_back( start, end );
692 }
693
694 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
695 aList.emplace_back( _( "Status" ), _( "Locked" ) );
696
697 aList.emplace_back( _( "Layer" ), GetLayerName() );
698}
699
700
701std::shared_ptr<SHAPE> PCB_DIMENSION_BASE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
702{
703 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
704
705 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
706
707 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
708 effectiveShape->AddShape( shape->Clone() );
709
710 return effectiveShape;
711}
712
713
714bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
715{
716 if( TextHitTest( aPosition ) )
717 return true;
718
719 int dist_max = aAccuracy + ( m_lineThickness / 2 );
720
721 // Locate SEGMENTS
722
723 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
724 {
725 if( shape->Collide( aPosition, dist_max ) )
726 return true;
727 }
728
729 return false;
730}
731
732
733bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
734{
735 BOX2I arect = aRect;
736 arect.Inflate( aAccuracy );
737
738 BOX2I rect = GetBoundingBox();
739
740 if( aAccuracy )
741 rect.Inflate( aAccuracy );
742
743 if( aContained )
744 return arect.Contains( rect );
745
746 return arect.Intersects( rect );
747}
748
749
750bool PCB_DIMENSION_BASE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
751{
752 // Note: Can't use GetEffectiveShape() because we want text as BoundingBox, not as graphics.
753 SHAPE_COMPOUND effShape;
754
755 // Add shapes
756 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
757 effShape.AddShape( shape );
758
759 if( aContained )
760 return TextHitTest( aPoly, aContained ) && KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
761 else
762 return TextHitTest( aPoly, aContained ) || KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
763}
764
765
767{
768 BOX2I bBox;
769 int xmin, xmax, ymin, ymax;
770
771 bBox = GetTextBox( nullptr );
772 xmin = bBox.GetX();
773 xmax = bBox.GetRight();
774 ymin = bBox.GetY();
775 ymax = bBox.GetBottom();
776
777 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
778 {
779 BOX2I shapeBox = shape->BBox();
780 shapeBox.Inflate( m_lineThickness / 2 );
781
782 xmin = std::min( xmin, shapeBox.GetOrigin().x );
783 xmax = std::max( xmax, shapeBox.GetEnd().x );
784 ymin = std::min( ymin, shapeBox.GetOrigin().y );
785 ymax = std::max( ymax, shapeBox.GetEnd().y );
786 }
787
788 bBox.SetX( xmin );
789 bBox.SetY( ymin );
790 bBox.SetWidth( xmax - xmin + 1 );
791 bBox.SetHeight( ymax - ymin + 1 );
792
793 bBox.Normalize();
794
795 return bBox;
796}
797
798
799wxString PCB_DIMENSION_BASE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
800{
801 return wxString::Format( _( "Dimension '%s' on %s" ),
802 aFull ? GetShownText( false ) : KIUI::EllipsizeMenuText( GetText() ),
803 GetLayerName() );
804}
805
806
807
809{
811 VECTOR2I( GetBoundingBox().GetSize() ) );
812 dimBBox.Merge( PCB_TEXT::ViewBBox() );
813
814 return dimBBox;
815}
816
817
819 int aClearance, int aError, ERROR_LOC aErrorLoc,
820 bool aIgnoreLineWidth ) const
821{
822 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
823
824 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
825 {
826 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
827 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
828
829 if( circle )
830 {
831 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
832 circle->GetRadius() + m_lineThickness / 2 + aClearance,
833 aError, aErrorLoc );
834 }
835 else if( seg )
836 {
837 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
838 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
839 }
840 else
841 {
842 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
843 }
844 }
845}
846
847
849 PCB_DIMENSION_BASE( aParent, aType ),
850 m_height( 0 )
851{
852 // To preserve look of old dimensions, initialize extension height based on default arrow length
853 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
854}
855
856
858{
859 return new PCB_DIM_ALIGNED( *this );
860}
861
862
864{
865 wxCHECK( aOther && aOther->Type() == PCB_DIM_ALIGNED_T, /* void */ );
866 *this = *static_cast<const PCB_DIM_ALIGNED*>( aOther );
867}
868
869void PCB_DIM_ALIGNED::Serialize( google::protobuf::Any &aContainer ) const
870{
871 using namespace kiapi::common;
872 kiapi::board::types::Dimension dimension;
873
874 PCB_DIMENSION_BASE::Serialize( aContainer );
875 aContainer.UnpackTo( &dimension );
876
877 PackVector2( *dimension.mutable_aligned()->mutable_start(), m_start );
878 PackVector2( *dimension.mutable_aligned()->mutable_end(), m_end );
879 dimension.mutable_aligned()->mutable_height()->set_value_nm( m_height );
880 dimension.mutable_aligned()->mutable_extension_height()->set_value_nm( m_extensionHeight );
881
882 aContainer.PackFrom( dimension );
883}
884
885
886bool PCB_DIM_ALIGNED::Deserialize( const google::protobuf::Any &aContainer )
887{
888 using namespace kiapi::common;
889
890 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
891 return false;
892
893 kiapi::board::types::Dimension dimension;
894 aContainer.UnpackTo( &dimension );
895
896 if( !dimension.has_aligned() )
897 return false;
898
899 SetStart( UnpackVector2( dimension.aligned().start() ) );
900 SetEnd( UnpackVector2( dimension.aligned().end() ) );
901 SetHeight( dimension.aligned().height().value_nm());
902 SetExtensionHeight( dimension.aligned().extension_height().value_nm() );
903
904 Update();
905
906 return true;
907}
908
909
911{
912 wxASSERT( aImage->Type() == Type() );
913
914 m_shapes.clear();
915 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
916
917 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
918
919 Update();
920}
921
922
923void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
924{
926 // Call this last for the Update()
927 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
928}
929
930
935
936
937void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
938{
939 VECTOR2D height( aCrossbarStart - GetStart() );
940 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
941
942 if( height.Cross( crossBar ) > 0 )
943 m_height = -height.EuclideanNorm();
944 else
945 m_height = height.EuclideanNorm();
946
947 Update();
948}
949
950
952{
953 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
954 return;
955
956 m_busy = true;
957
958 m_shapes.clear();
959
960 VECTOR2I dimension( m_end - m_start );
961
962 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
963
964 VECTOR2I extension;
965
966 if( m_height > 0 )
967 extension = VECTOR2I( -dimension.y, dimension.x );
968 else
969 extension = VECTOR2I( dimension.y, -dimension.x );
970
971 // Add extension lines
972 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
973
974 VECTOR2I extStart( m_start );
975 extStart += extension.Resize( m_extensionOffset );
976
977 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
978
979 extStart = VECTOR2I( m_end );
980 extStart += extension.Resize( m_extensionOffset );
981
982 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
983
984 // Add crossbar
985 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
986 m_crossBarStart = m_start + crossBarDistance;
987 m_crossBarEnd = m_end + crossBarDistance;
988
989 // Update text after calculating crossbar position but before adding crossbar lines
990 updateText();
991
992 // Now that we have the text updated, we can determine how to draw the crossbar.
993 // First we need to create an appropriate bounding polygon to collide with
994 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, - GetEffectiveTextPenWidth() );
995
996 SHAPE_POLY_SET polyBox;
997 polyBox.NewOutline();
998 polyBox.Append( textBox.GetOrigin() );
999 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1000 polyBox.Append( textBox.GetEnd() );
1001 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1002 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1003
1004 // The ideal crossbar, if the text doesn't collide
1005 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1006
1007 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1008
1010 {
1011 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ),
1013 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ),
1015 }
1016 else
1017 {
1018 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ), 0 );
1019 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ), 0 );
1020 }
1021
1022 m_busy = false;
1023}
1024
1025
1027{
1028 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1029
1031 {
1032 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1033 EDA_ANGLE rotation;
1034
1035 if( crossbarCenter.x == 0 )
1036 rotation = ANGLE_90 * sign( -crossbarCenter.y );
1037 else if( crossbarCenter.x < 0 )
1038 rotation = -ANGLE_90;
1039 else
1040 rotation = ANGLE_90;
1041
1042 VECTOR2I textOffset = crossbarCenter;
1043 RotatePoint( textOffset, rotation );
1044 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
1045
1046 SetTextPos( m_crossBarStart + textOffset );
1047 }
1049 {
1050 SetTextPos( m_crossBarStart + crossbarCenter );
1051 }
1052
1053 if( m_keepTextAligned )
1054 {
1055 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
1056 textAngle.Normalize();
1057
1058 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1059 textAngle -= ANGLE_180;
1060
1061 SetTextAngle( textAngle );
1062 }
1063
1065}
1066
1067
1068void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1069{
1070 PCB_DIMENSION_BASE::GetMsgPanelInfo( aFrame, aList );
1071
1072 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
1073 // in frame's units.
1074 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
1075 unitsProvider.SetUserUnits( GetUnits() );
1076
1077 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
1078}
1079
1080
1083{
1084 // To preserve look of old dimensions, initialize extension height based on default arrow length
1085 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1087}
1088
1089
1091{
1092 return new PCB_DIM_ORTHOGONAL( *this );
1093}
1094
1095
1097{
1098 wxCHECK( aOther && aOther->Type() == PCB_DIM_ORTHOGONAL_T, /* void */ );
1099 *this = *static_cast<const PCB_DIM_ORTHOGONAL*>( aOther );
1100}
1101
1102void PCB_DIM_ORTHOGONAL::Serialize( google::protobuf::Any &aContainer ) const
1103{
1104 using namespace kiapi::common;
1105 kiapi::board::types::Dimension dimension;
1106
1107 PCB_DIMENSION_BASE::Serialize( aContainer );
1108 aContainer.UnpackTo( &dimension );
1109
1110 PackVector2( *dimension.mutable_orthogonal()->mutable_start(), m_start );
1111 PackVector2( *dimension.mutable_orthogonal()->mutable_end(), m_end );
1112 dimension.mutable_orthogonal()->mutable_height()->set_value_nm( m_height );
1113 dimension.mutable_orthogonal()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1114
1115 dimension.mutable_orthogonal()->set_alignment( m_orientation == DIR::VERTICAL
1116 ? types::AxisAlignment::AA_Y_AXIS
1117 : types::AxisAlignment::AA_X_AXIS );
1118 aContainer.PackFrom( dimension );
1119}
1120
1121
1122bool PCB_DIM_ORTHOGONAL::Deserialize( const google::protobuf::Any &aContainer )
1123{
1124 using namespace kiapi::common;
1125
1126 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1127 return false;
1128
1129 kiapi::board::types::Dimension dimension;
1130 aContainer.UnpackTo( &dimension );
1131
1132 if( !dimension.has_orthogonal() )
1133 return false;
1134
1135 SetStart( UnpackVector2( dimension.orthogonal().start() ) );
1136 SetEnd( UnpackVector2( dimension.orthogonal().end() ) );
1137 SetHeight( dimension.orthogonal().height().value_nm());
1138 SetExtensionHeight( dimension.orthogonal().extension_height().value_nm() );
1139 SetOrientation( dimension.orthogonal().alignment() == types::AxisAlignment::AA_Y_AXIS
1141 : DIR::HORIZONTAL );
1142
1143 Update();
1144
1145 return true;
1146}
1147
1148
1150{
1151 wxASSERT( aImage->Type() == Type() );
1152
1153 m_shapes.clear();
1154 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
1155
1156 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
1157 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
1158
1159 Update();
1160}
1161
1162
1163void PCB_DIM_ORTHOGONAL::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1164{
1165 // Only reverse the height if the height is aligned with the flip
1166 if( m_orientation == DIR::HORIZONTAL && aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
1167 m_height = -m_height;
1168 else if( m_orientation == DIR::VERTICAL && aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1169 m_height = -m_height;
1170
1171 // Call this last, as we need the Update()
1172 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1173}
1174
1175
1180
1181
1183{
1184 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1185 return;
1186
1187 m_busy = true;
1188 m_shapes.clear();
1189
1191 m_end.y - m_start.y );
1193
1194 VECTOR2I extension;
1195
1197 extension = VECTOR2I( 0, m_height );
1198 else
1199 extension = VECTOR2I( m_height, 0 );
1200
1201 // Add first extension line
1202 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1203
1204 VECTOR2I extStart( m_start );
1205 extStart += extension.Resize( m_extensionOffset );
1206
1207 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1208
1209 // Add crossbar
1210 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1211 m_crossBarStart = m_start + crossBarDistance;
1212
1215 else
1217
1218 // Add second extension line (m_end to crossbar end)
1220 extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y );
1221 else
1222 extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 );
1223
1224 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
1225
1226 extStart = VECTOR2I( m_crossBarEnd );
1227 extStart -= extension.Resize( m_extensionHeight );
1228
1229 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1230
1231 // Update text after calculating crossbar position but before adding crossbar lines
1232 updateText();
1233
1234 // Now that we have the text updated, we can determine how to draw the crossbar.
1235 // First we need to create an appropriate bounding polygon to collide with
1236 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1237
1238 SHAPE_POLY_SET polyBox;
1239 polyBox.NewOutline();
1240 polyBox.Append( textBox.GetOrigin() );
1241 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1242 polyBox.Append( textBox.GetEnd() );
1243 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1244 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1245
1246 // The ideal crossbar, if the text doesn't collide
1247 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1248
1249 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1250
1251 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
1252
1254 {
1255 // Arrows with fixed length.
1256 drawAnArrow( m_crossBarStart, crossBarAngle + EDA_ANGLE( 180 ),
1259 }
1260 else
1261 {
1262 drawAnArrow( m_crossBarStart, crossBarAngle, 0 );
1263 drawAnArrow( m_crossBarEnd, crossBarAngle + EDA_ANGLE( 180 ), 0 );
1264 }
1265
1266 m_busy = false;
1267}
1268
1269
1271{
1272 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1273
1275 {
1276 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1277
1278 VECTOR2I textOffset;
1279
1281 textOffset.y = -textOffsetDistance;
1282 else
1283 textOffset.x = -textOffsetDistance;
1284
1285 textOffset += crossbarCenter;
1286
1287 SetTextPos( m_crossBarStart + textOffset );
1288 }
1290 {
1291 SetTextPos( m_crossBarStart + crossbarCenter );
1292 }
1293
1294 if( m_keepTextAligned )
1295 {
1296 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
1298 else
1300 }
1301
1303}
1304
1305
1306void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1307{
1308 EDA_ANGLE angle( aAngle );
1309
1310 // restrict angle to -179.9 to 180.0 degrees
1311 angle.Normalize180();
1312
1313 // adjust orientation and height to new angle
1314 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
1315 // in the other cases we will use the nearest 90 degree angle to
1316 // choose at least an approximate axis for the target orientation
1317 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
1318 if( angle > ANGLE_45 && angle <= ANGLE_135 )
1319 {
1320 // about 90 degree
1322 {
1324 }
1325 else
1326 {
1328 m_height = -m_height;
1329 }
1330 }
1331 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
1332 {
1333 // about -90 degree
1335 {
1337 m_height = -m_height;
1338 }
1339 else
1340 {
1342 }
1343 }
1344 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
1345 {
1346 // about 180 degree
1347 m_height = -m_height;
1348 }
1349
1350 // this will update m_crossBarStart and m_crossbarEnd
1351 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
1352}
1353
1354
1365
1366
1368{
1369 wxCHECK( aOther && aOther->Type() == PCB_DIM_LEADER_T, /* void */ );
1370 *this = *static_cast<const PCB_DIM_LEADER*>( aOther );
1371}
1372
1373void PCB_DIM_LEADER::Serialize( google::protobuf::Any &aContainer ) const
1374{
1375 using namespace kiapi::common;
1376 kiapi::board::types::Dimension dimension;
1377
1378 PCB_DIMENSION_BASE::Serialize( aContainer );
1379 aContainer.UnpackTo( &dimension );
1380
1381 PackVector2( *dimension.mutable_leader()->mutable_start(), m_start );
1382 PackVector2( *dimension.mutable_leader()->mutable_end(), m_end );
1383 dimension.mutable_leader()->set_border_style(
1385 m_textBorder ) );
1386
1387 aContainer.PackFrom( dimension );
1388}
1389
1390
1391bool PCB_DIM_LEADER::Deserialize( const google::protobuf::Any &aContainer )
1392{
1393 using namespace kiapi::common;
1394
1395 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1396 return false;
1397
1398 kiapi::board::types::Dimension dimension;
1399 aContainer.UnpackTo( &dimension );
1400
1401 if( !dimension.has_leader() )
1402 return false;
1403
1404 SetStart( UnpackVector2( dimension.leader().start() ) );
1405 SetEnd( UnpackVector2( dimension.leader().end() ) );
1406 SetTextBorder( FromProtoEnum<DIM_TEXT_BORDER>( dimension.leader().border_style() ) );
1407
1408 Update();
1409
1410 return true;
1411}
1412
1413
1415{
1416 return new PCB_DIM_LEADER( *this );
1417}
1418
1419
1421{
1422 wxASSERT( aImage->Type() == Type() );
1423
1424 m_shapes.clear();
1425 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
1426
1427 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
1428
1429 Update();
1430}
1431
1432
1437
1438
1440{
1441 // Our geometry is dependent on the size of the text, so just update the whole shebang
1443}
1444
1445
1447{
1448 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1449 return;
1450
1451 m_busy = true;
1452
1453 m_shapes.clear();
1454
1456
1457 // Now that we have the text updated, we can determine how to draw the second line
1458 // First we need to create an appropriate bounding polygon to collide with
1459 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1460
1461 SHAPE_POLY_SET polyBox;
1462 polyBox.NewOutline();
1463 polyBox.Append( textBox.GetOrigin() );
1464 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1465 polyBox.Append( textBox.GetEnd() );
1466 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1467 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1468
1469 VECTOR2I firstLine( m_end - m_start );
1470 VECTOR2I start( m_start );
1471 start += firstLine.Resize( m_extensionOffset );
1472
1473 SEG arrowSeg( m_start, m_end );
1474 SEG textSeg( m_end, GetTextPos() );
1475 OPT_VECTOR2I arrowSegEnd;
1476 OPT_VECTOR2I textSegEnd;
1477
1479 {
1480 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1481 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1482 CIRCLE circle( textBox.GetCenter(), radius );
1483
1484 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1485 textSegEnd = segCircleIntersection( circle, textSeg );
1486 }
1487 else
1488 {
1489 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1490 textSegEnd = segPolyIntersection( polyBox, textSeg );
1491 }
1492
1493 if( !arrowSegEnd )
1494 arrowSegEnd = m_end;
1495
1496 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1497
1498 drawAnArrow( start, EDA_ANGLE( firstLine ), 0 );
1499
1500 if( !GetText().IsEmpty() )
1501 {
1502 switch( m_textBorder )
1503 {
1505 {
1506 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1507 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1508
1509 break;
1510 }
1511
1513 {
1514 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1515 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1516 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1517
1518 break;
1519 }
1520
1521 default:
1522 break;
1523 }
1524 }
1525
1526 if( textSegEnd && *arrowSegEnd == m_end )
1527 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, *textSegEnd ) );
1528
1529 m_busy = false;
1530}
1531
1532
1533void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1534{
1535 // Don't use GetShownText(); we want to see the variable references here
1536 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1537
1538 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
1539
1540 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1541 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1542 aFrame->MessageTextFromValue( startCoord.x ),
1543 aFrame->MessageTextFromValue( startCoord.y ) );
1544
1545 aList.emplace_back( start, wxEmptyString );
1546
1547 aList.emplace_back( _( "Layer" ), GetLayerName() );
1548}
1549
1550
1560
1562{
1563 wxCHECK( aOther && aOther->Type() == PCB_DIM_RADIAL_T, /* void */ );
1564 *this = *static_cast<const PCB_DIM_RADIAL*>( aOther );
1565}
1566
1567void PCB_DIM_RADIAL::Serialize( google::protobuf::Any &aContainer ) const
1568{
1569 using namespace kiapi::common;
1570 kiapi::board::types::Dimension dimension;
1571
1572 PCB_DIMENSION_BASE::Serialize( aContainer );
1573 aContainer.UnpackTo( &dimension );
1574
1575 PackVector2( *dimension.mutable_radial()->mutable_center(), m_start );
1576 PackVector2( *dimension.mutable_radial()->mutable_radius_point(), m_end );
1577 dimension.mutable_radial()->mutable_leader_length()->set_value_nm( m_leaderLength );
1578
1579 aContainer.PackFrom( dimension );
1580}
1581
1582
1583bool PCB_DIM_RADIAL::Deserialize( const google::protobuf::Any &aContainer )
1584{
1585 using namespace kiapi::common;
1586
1587 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1588 return false;
1589
1590 kiapi::board::types::Dimension dimension;
1591 aContainer.UnpackTo( &dimension );
1592
1593 if( !dimension.has_radial() )
1594 return false;
1595
1596 SetStart( UnpackVector2( dimension.radial().center() ) );
1597 SetEnd( UnpackVector2( dimension.radial().radius_point() ) );
1598 SetLeaderLength( dimension.radial().leader_length().value_nm() );
1599
1600 Update();
1601
1602 return true;
1603}
1604
1605
1607{
1608 return new PCB_DIM_RADIAL( *this );
1609}
1610
1611
1613{
1614 wxASSERT( aImage->Type() == Type() );
1615
1616 m_shapes.clear();
1617 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1618
1619 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1620
1621 Update();
1622}
1623
1624
1629
1630
1632{
1633 VECTOR2I radial( m_end - m_start );
1634
1635 return m_end + radial.Resize( m_leaderLength );
1636}
1637
1638
1640{
1641 if( m_keepTextAligned )
1642 {
1643 VECTOR2I textLine( GetTextPos() - GetKnee() );
1644 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1645
1646 textAngle.Normalize();
1647
1648 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1649 textAngle -= ANGLE_180;
1650
1651 // Round to nearest degree
1652 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1653
1654 SetTextAngle( textAngle );
1655 }
1656
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 VECTOR2I centerArm( 0, m_arrowLength );
1672
1673 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1674
1675 RotatePoint( centerArm, -ANGLE_90 );
1676
1677 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1678
1680
1681 m_measuredValue = KiROUND( radius.EuclideanNorm() );
1682
1683 updateText();
1684
1685 // Now that we have the text updated, we can determine how to draw the second line
1686 // First we need to create an appropriate bounding polygon to collide with
1687 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1688
1689 SHAPE_POLY_SET polyBox;
1690 polyBox.NewOutline();
1691 polyBox.Append( textBox.GetOrigin() );
1692 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1693 polyBox.Append( textBox.GetEnd() );
1694 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1695 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1696
1697 VECTOR2I radial( m_end - m_start );
1698 radial = radial.Resize( m_leaderLength );
1699
1700 SEG arrowSeg( m_end, m_end + radial );
1701 SEG textSeg( arrowSeg.B, GetTextPos() );
1702
1703 CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
1704 CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
1705
1706 drawAnArrow( m_end, EDA_ANGLE( radial ), 0 );
1707
1708 m_busy = false;
1709}
1710
1711
1718
1720{
1721 wxCHECK( aOther && aOther->Type() == PCB_DIM_CENTER_T, /* void */ );
1722 *this = *static_cast<const PCB_DIM_CENTER*>( aOther );
1723}
1724
1725void PCB_DIM_CENTER::Serialize( google::protobuf::Any &aContainer ) const
1726{
1727 using namespace kiapi::common;
1728 kiapi::board::types::Dimension dimension;
1729
1730 PCB_DIMENSION_BASE::Serialize( aContainer );
1731 aContainer.UnpackTo( &dimension );
1732
1733 PackVector2( *dimension.mutable_center()->mutable_center(), m_start );
1734 PackVector2( *dimension.mutable_center()->mutable_end(), m_end );
1735
1736 aContainer.PackFrom( dimension );
1737}
1738
1739
1740bool PCB_DIM_CENTER::Deserialize( const google::protobuf::Any &aContainer )
1741{
1742 using namespace kiapi::common;
1743
1744 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1745 return false;
1746
1747 kiapi::board::types::Dimension dimension;
1748 aContainer.UnpackTo( &dimension );
1749
1750 if( !dimension.has_center() )
1751 return false;
1752
1753 SetStart( UnpackVector2( dimension.center().center() ) );
1754 SetEnd( UnpackVector2( dimension.center().end() ) );
1755
1756 Update();
1757
1758 return true;
1759}
1760
1761
1763{
1764 return new PCB_DIM_CENTER( *this );
1765}
1766
1767
1769{
1770 wxASSERT( aImage->Type() == Type() );
1771
1772 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1773}
1774
1775
1780
1781
1783{
1784 BOX2I bBox;
1785 int xmin, xmax, ymin, ymax;
1786
1787 xmin = m_start.x;
1788 xmax = m_start.x;
1789 ymin = m_start.y;
1790 ymax = m_start.y;
1791
1792 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
1793 {
1794 BOX2I shapeBox = shape->BBox();
1795 shapeBox.Inflate( m_lineThickness / 2 );
1796
1797 xmin = std::min( xmin, shapeBox.GetOrigin().x );
1798 xmax = std::max( xmax, shapeBox.GetEnd().x );
1799 ymin = std::min( ymin, shapeBox.GetOrigin().y );
1800 ymax = std::max( ymax, shapeBox.GetEnd().y );
1801 }
1802
1803 bBox.SetX( xmin );
1804 bBox.SetY( ymin );
1805 bBox.SetWidth( xmax - xmin + 1 );
1806 bBox.SetHeight( ymax - ymin + 1 );
1807
1808 bBox.Normalize();
1809
1810 return bBox;
1811}
1812
1813
1815{
1816 return GetBoundingBox();
1817}
1818
1819
1821{
1822 // Even if PCB_DIM_CENTER has no text, we still need to update its text position
1823 // so GetTextPos() users get a valid value. Required at least for lasso hit-testing.
1825
1827}
1828
1829
1831{
1832 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1833 return;
1834
1835 m_busy = true;
1836
1837 m_shapes.clear();
1838
1840 VECTOR2I arm( m_end - m_start );
1841
1842 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1843
1844 RotatePoint( arm, -ANGLE_90 );
1845
1846 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1847
1848 updateText();
1849
1850 m_busy = false;
1851}
1852
1853
1854static struct DIMENSION_DESC
1855{
1857 {
1859 .Map( DIM_PRECISION::X, _HKI( "0" ) )
1860 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
1861 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
1862 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
1863 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
1864 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
1865 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
1866 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
1867 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
1868 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
1869
1871 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
1872 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
1873 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
1874
1876 .Map( DIM_UNITS_MODE::INCH, _HKI( "Inches" ) )
1877 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
1878 .Map( DIM_UNITS_MODE::MM, _HKI( "Millimeters" ) )
1879 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
1880
1882 .Map( DIM_ARROW_DIRECTION::INWARD, _HKI( "Inward" ) )
1883 .Map( DIM_ARROW_DIRECTION::OUTWARD, _HKI( "Outward" ) );
1884
1893
1894 propMgr.Mask( TYPE_HASH( PCB_DIMENSION_BASE ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
1895
1896 const wxString groupDimension = _HKI( "Dimension Properties" );
1897
1898 auto isLeader =
1899 []( INSPECTABLE* aItem ) -> bool
1900 {
1901 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
1902 };
1903
1904 auto isNotLeader =
1905 []( INSPECTABLE* aItem ) -> bool
1906 {
1907 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
1908 };
1909
1910 auto isMultiArrowDirection =
1911 []( INSPECTABLE* aItem ) -> bool
1912 {
1913 return dynamic_cast<PCB_DIM_ALIGNED*>( aItem ) != nullptr;
1914 };
1915
1918 groupDimension )
1919 .SetAvailableFunc( isNotLeader );
1922 groupDimension )
1923 .SetAvailableFunc( isNotLeader );
1924 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
1926 groupDimension )
1927 .SetAvailableFunc( isNotLeader );
1928
1931 groupDimension )
1932 .SetAvailableFunc( isLeader );
1933
1936 groupDimension )
1937 .SetAvailableFunc( isNotLeader );
1940 groupDimension )
1941 .SetAvailableFunc( isNotLeader );
1944 groupDimension )
1945 .SetAvailableFunc( isNotLeader );
1946 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
1948 groupDimension )
1949 .SetAvailableFunc( isNotLeader );
1950
1953 groupDimension )
1954 .SetAvailableFunc( isMultiArrowDirection );
1955
1956 const wxString groupText = _HKI( "Text Properties" );
1957
1958 const auto isTextOrientationWriteable =
1959 []( INSPECTABLE* aItem ) -> bool
1960 {
1961 return !static_cast<PCB_DIMENSION_BASE*>( aItem )->GetKeepTextAligned();
1962 };
1963
1964 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Keep Aligned with Dimension" ),
1967 groupText );
1968
1969 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, double>( _HKI( "Orientation" ),
1973 groupText )
1974 .SetWriteableFunc( isTextOrientationWriteable );
1975 }
1977
1982
1983
1985{
1987 {
1998
1999 const wxString groupDimension = _HKI( "Dimension Properties" );
2000
2001 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
2004 groupDimension );
2005 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
2008 groupDimension );
2009
2011 _HKI( "Text" ),
2012 []( INSPECTABLE* aItem ) { return false; } );
2014 _HKI( "Vertical Justification" ),
2015 []( INSPECTABLE* aItem ) { return false; } );
2017 _HKI( "Hyperlink" ),
2018 []( INSPECTABLE* aItem ) { return false; } );
2020 _HKI( "Knockout" ),
2021 []( INSPECTABLE* aItem ) { return false; } );
2022 }
2024
2025
2027{
2029 {
2042
2044 _HKI( "Text" ),
2045 []( INSPECTABLE* aItem ) { return false; } );
2047 _HKI( "Vertical Justification" ),
2048 []( INSPECTABLE* aItem ) { return false; } );
2050 _HKI( "Hyperlink" ),
2051 []( INSPECTABLE* aItem ) { return false; } );
2053 _HKI( "Knockout" ),
2054 []( INSPECTABLE* aItem ) { return false; } );
2055 }
2057
2058
2060{
2062 {
2073
2074 const wxString groupDimension = _HKI( "Dimension Properties" );
2075
2076 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
2079 groupDimension );
2080
2082 _HKI( "Text" ),
2083 []( INSPECTABLE* aItem ) { return false; } );
2085 _HKI( "Vertical Justification" ),
2086 []( INSPECTABLE* aItem ) { return false; } );
2088 _HKI( "Hyperlink" ),
2089 []( INSPECTABLE* aItem ) { return false; } );
2091 _HKI( "Knockout" ),
2092 []( INSPECTABLE* aItem ) { return false; } );
2093 }
2095
2096
2098{
2100 {
2102 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
2103 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
2104 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
2105
2116
2117 const wxString groupDimension = _HKI( "Dimension Properties" );
2118
2121 groupDimension );
2122
2124 _HKI( "Text" ),
2125 []( INSPECTABLE* aItem ) { return false; } );
2127 _HKI( "Vertical Justification" ),
2128 []( INSPECTABLE* aItem ) { return false; } );
2130 _HKI( "Hyperlink" ),
2131 []( INSPECTABLE* aItem ) { return false; } );
2133 _HKI( "Knockout" ),
2134 []( INSPECTABLE* aItem ) { return false; } );
2135 }
2137
2139
2140
2142{
2144 {
2155
2156
2158 _HKI( "Text" ),
2159 []( INSPECTABLE* aItem ) { return false; } );
2161 _HKI( "Vertical Justification" ),
2162 []( INSPECTABLE* aItem ) { return false; } );
2164 _HKI( "Hyperlink" ),
2165 []( INSPECTABLE* aItem ) { return false; } );
2167 _HKI( "Knockout" ),
2168 []( INSPECTABLE* aItem ) { return false; } );
2169 }
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:41
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:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:268
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
void SetLocked(bool aLocked) override
Definition board_item.h:359
PCB_LAYER_ID m_layer
Definition board_item.h:490
bool IsLocked() const override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:316
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:819
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:100
const KIID m_Uuid
Definition eda_item.h:528
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:540
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:91
int GetTextHeight() const
Definition eda_text.h:278
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition eda_text.cpp:174
const VECTOR2I & GetTextPos() const
Definition eda_text.h:284
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:158
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:109
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:560
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition eda_text.cpp:208
KIFONT::FONT * GetFont() const
Definition eda_text.h:258
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:377
int GetTextWidth() const
Definition eda_text.h:275
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:739
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:578
double Similarity(const EDA_TEXT &aOther) const
virtual void ClearRenderCache()
Definition eda_text.cpp:656
bool IsMirrored() const
Definition eda_text.h:201
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:449
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:161
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:254
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:283
int GetTextThickness() const
Definition eda_text.h:139
bool operator==(const EDA_TEXT &aRhs) const
Definition eda_text.h:409
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:38
Definition kiid.h:48
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 CopyFrom(const BOARD_ITEM *aOther) override
void SetHeight(int aHeight)
Set the distance from the feature points to the crossbar line.
VECTOR2I m_crossBarEnd
Crossbar end control point.
PCB_DIM_ALIGNED(BOARD_ITEM *aParent, KICAD_T aType=PCB_DIM_ALIGNED_T)
void ChangeHeight(int aHeight)
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
int GetExtensionHeight() const
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Mark the center of a circle or arc with a cross shape.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void CopyFrom(const BOARD_ITEM *aOther) override
virtual void swapData(BOARD_ITEM *aImage) override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
PCB_DIM_CENTER(BOARD_ITEM *aParent)
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
A leader is a dimension-like object pointing to a specific point.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
DIM_TEXT_BORDER m_textBorder
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
DIM_TEXT_BORDER GetTextBorder() const
void CopyFrom(const BOARD_ITEM *aOther) override
virtual void swapData(BOARD_ITEM *aImage) override
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
void SetTextBorder(DIM_TEXT_BORDER aBorder)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
PCB_DIM_LEADER(BOARD_ITEM *aParent)
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void ChangeTextBorder(DIM_TEXT_BORDER aBorder)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
void swapData(BOARD_ITEM *aImage) override
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
void CopyFrom(const BOARD_ITEM *aOther) override
void SetOrientation(DIR aOrientation)
Set the orientation of the dimension line (so, perpendicular to the feature lines).
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
DIR m_orientation
What axis to lock the dimension line to.
void Mirror(const VECTOR2I &axis_pos, FLIP_DIRECTION aFlipDirection) override
Mirror the dimension relative to a given horizontal axis.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
PCB_DIM_ORTHOGONAL(BOARD_ITEM *aParent)
A radial dimension indicates either the radius or diameter of an arc or circle.
int GetLeaderLength() const
PCB_DIM_RADIAL(BOARD_ITEM *aParent)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
virtual void swapData(BOARD_ITEM *aImage) override
void SetLeaderLength(int aLength)
void CopyFrom(const BOARD_ITEM *aOther) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
void updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void ChangeLeaderLength(int aLength)
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
VECTOR2I GetKnee() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
Definition pcb_text.cpp:350
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition pcb_text.cpp:226
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition pcb_text.cpp:162
PCB_TEXT(BOARD_ITEM *parent, KICAD_T idtype=PCB_TEXT_T)
Definition pcb_text.cpp:53
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition pcb_text.cpp:405
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition pcb_text.cpp:519
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:538
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:173
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:75
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:103
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:100
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:101
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:99
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:102
constexpr int sign(T val)
Definition util.h:145
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686