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 const_cast<KIID&>( m_Uuid ) = 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
863void PCB_DIM_ALIGNED::Serialize( google::protobuf::Any &aContainer ) const
864{
865 using namespace kiapi::common;
866 kiapi::board::types::Dimension dimension;
867
868 PCB_DIMENSION_BASE::Serialize( aContainer );
869 aContainer.UnpackTo( &dimension );
870
871 PackVector2( *dimension.mutable_aligned()->mutable_start(), m_start );
872 PackVector2( *dimension.mutable_aligned()->mutable_end(), m_end );
873 dimension.mutable_aligned()->mutable_height()->set_value_nm( m_height );
874 dimension.mutable_aligned()->mutable_extension_height()->set_value_nm( m_extensionHeight );
875
876 aContainer.PackFrom( dimension );
877}
878
879
880bool PCB_DIM_ALIGNED::Deserialize( const google::protobuf::Any &aContainer )
881{
882 using namespace kiapi::common;
883
884 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
885 return false;
886
887 kiapi::board::types::Dimension dimension;
888 aContainer.UnpackTo( &dimension );
889
890 if( !dimension.has_aligned() )
891 return false;
892
893 SetStart( UnpackVector2( dimension.aligned().start() ) );
894 SetEnd( UnpackVector2( dimension.aligned().end() ) );
895 SetHeight( dimension.aligned().height().value_nm());
896 SetExtensionHeight( dimension.aligned().extension_height().value_nm() );
897
898 Update();
899
900 return true;
901}
902
903
905{
906 wxASSERT( aImage->Type() == Type() );
907
908 m_shapes.clear();
909 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
910
911 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
912
913 Update();
914}
915
916
917void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
918{
920 // Call this last for the Update()
921 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
922}
923
924
929
930
931void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
932{
933 VECTOR2D height( aCrossbarStart - GetStart() );
934 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
935
936 if( height.Cross( crossBar ) > 0 )
937 m_height = -height.EuclideanNorm();
938 else
939 m_height = height.EuclideanNorm();
940
941 Update();
942}
943
944
946{
947 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
948 return;
949
950 m_busy = true;
951
952 m_shapes.clear();
953
954 VECTOR2I dimension( m_end - m_start );
955
956 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
957
958 VECTOR2I extension;
959
960 if( m_height > 0 )
961 extension = VECTOR2I( -dimension.y, dimension.x );
962 else
963 extension = VECTOR2I( dimension.y, -dimension.x );
964
965 // Add extension lines
966 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
967
968 VECTOR2I extStart( m_start );
969 extStart += extension.Resize( m_extensionOffset );
970
971 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
972
973 extStart = VECTOR2I( m_end );
974 extStart += extension.Resize( m_extensionOffset );
975
976 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
977
978 // Add crossbar
979 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
980 m_crossBarStart = m_start + crossBarDistance;
981 m_crossBarEnd = m_end + crossBarDistance;
982
983 // Update text after calculating crossbar position but before adding crossbar lines
984 updateText();
985
986 // Now that we have the text updated, we can determine how to draw the crossbar.
987 // First we need to create an appropriate bounding polygon to collide with
988 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, - GetEffectiveTextPenWidth() );
989
990 SHAPE_POLY_SET polyBox;
991 polyBox.NewOutline();
992 polyBox.Append( textBox.GetOrigin() );
993 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
994 polyBox.Append( textBox.GetEnd() );
995 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
996 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
997
998 // The ideal crossbar, if the text doesn't collide
999 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1000
1001 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1002
1004 {
1005 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ),
1007 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ),
1009 }
1010 else
1011 {
1012 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ), 0 );
1013 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ), 0 );
1014 }
1015
1016 m_busy = false;
1017}
1018
1019
1021{
1022 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1023
1025 {
1026 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1027 EDA_ANGLE rotation;
1028
1029 if( crossbarCenter.x == 0 )
1030 rotation = ANGLE_90 * sign( -crossbarCenter.y );
1031 else if( crossbarCenter.x < 0 )
1032 rotation = -ANGLE_90;
1033 else
1034 rotation = ANGLE_90;
1035
1036 VECTOR2I textOffset = crossbarCenter;
1037 RotatePoint( textOffset, rotation );
1038 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
1039
1040 SetTextPos( m_crossBarStart + textOffset );
1041 }
1043 {
1044 SetTextPos( m_crossBarStart + crossbarCenter );
1045 }
1046
1047 if( m_keepTextAligned )
1048 {
1049 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
1050 textAngle.Normalize();
1051
1052 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1053 textAngle -= ANGLE_180;
1054
1055 SetTextAngle( textAngle );
1056 }
1057
1059}
1060
1061
1062void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1063{
1064 PCB_DIMENSION_BASE::GetMsgPanelInfo( aFrame, aList );
1065
1066 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
1067 // in frame's units.
1068 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
1069 unitsProvider.SetUserUnits( GetUnits() );
1070
1071 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
1072}
1073
1074
1077{
1078 // To preserve look of old dimensions, initialize extension height based on default arrow length
1079 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1081}
1082
1083
1085{
1086 return new PCB_DIM_ORTHOGONAL( *this );
1087}
1088
1089
1090void PCB_DIM_ORTHOGONAL::Serialize( google::protobuf::Any &aContainer ) const
1091{
1092 using namespace kiapi::common;
1093 kiapi::board::types::Dimension dimension;
1094
1095 PCB_DIMENSION_BASE::Serialize( aContainer );
1096 aContainer.UnpackTo( &dimension );
1097
1098 PackVector2( *dimension.mutable_orthogonal()->mutable_start(), m_start );
1099 PackVector2( *dimension.mutable_orthogonal()->mutable_end(), m_end );
1100 dimension.mutable_orthogonal()->mutable_height()->set_value_nm( m_height );
1101 dimension.mutable_orthogonal()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1102
1103 dimension.mutable_orthogonal()->set_alignment( m_orientation == DIR::VERTICAL
1104 ? types::AxisAlignment::AA_Y_AXIS
1105 : types::AxisAlignment::AA_X_AXIS );
1106 aContainer.PackFrom( dimension );
1107}
1108
1109
1110bool PCB_DIM_ORTHOGONAL::Deserialize( const google::protobuf::Any &aContainer )
1111{
1112 using namespace kiapi::common;
1113
1114 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1115 return false;
1116
1117 kiapi::board::types::Dimension dimension;
1118 aContainer.UnpackTo( &dimension );
1119
1120 if( !dimension.has_orthogonal() )
1121 return false;
1122
1123 SetStart( UnpackVector2( dimension.orthogonal().start() ) );
1124 SetEnd( UnpackVector2( dimension.orthogonal().end() ) );
1125 SetHeight( dimension.orthogonal().height().value_nm());
1126 SetExtensionHeight( dimension.orthogonal().extension_height().value_nm() );
1127 SetOrientation( dimension.orthogonal().alignment() == types::AxisAlignment::AA_Y_AXIS
1129 : DIR::HORIZONTAL );
1130
1131 Update();
1132
1133 return true;
1134}
1135
1136
1138{
1139 wxASSERT( aImage->Type() == Type() );
1140
1141 m_shapes.clear();
1142 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
1143
1144 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
1145 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
1146
1147 Update();
1148}
1149
1150
1151void PCB_DIM_ORTHOGONAL::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1152{
1153 // Only reverse the height if the height is aligned with the flip
1154 if( m_orientation == DIR::HORIZONTAL && aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
1155 m_height = -m_height;
1156 else if( m_orientation == DIR::VERTICAL && aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1157 m_height = -m_height;
1158
1159 // Call this last, as we need the Update()
1160 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1161}
1162
1163
1168
1169
1171{
1172 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1173 return;
1174
1175 m_busy = true;
1176 m_shapes.clear();
1177
1179 m_end.y - m_start.y );
1181
1182 VECTOR2I extension;
1183
1185 extension = VECTOR2I( 0, m_height );
1186 else
1187 extension = VECTOR2I( m_height, 0 );
1188
1189 // Add first extension line
1190 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1191
1192 VECTOR2I extStart( m_start );
1193 extStart += extension.Resize( m_extensionOffset );
1194
1195 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1196
1197 // Add crossbar
1198 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1199 m_crossBarStart = m_start + crossBarDistance;
1200
1203 else
1205
1206 // Add second extension line (m_end to crossbar end)
1208 extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y );
1209 else
1210 extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 );
1211
1212 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
1213
1214 extStart = VECTOR2I( m_crossBarEnd );
1215 extStart -= extension.Resize( m_extensionHeight );
1216
1217 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1218
1219 // Update text after calculating crossbar position but before adding crossbar lines
1220 updateText();
1221
1222 // Now that we have the text updated, we can determine how to draw the crossbar.
1223 // First we need to create an appropriate bounding polygon to collide with
1224 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1225
1226 SHAPE_POLY_SET polyBox;
1227 polyBox.NewOutline();
1228 polyBox.Append( textBox.GetOrigin() );
1229 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1230 polyBox.Append( textBox.GetEnd() );
1231 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1232 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1233
1234 // The ideal crossbar, if the text doesn't collide
1235 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1236
1237 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1238
1239 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
1240
1242 {
1243 // Arrows with fixed length.
1244 drawAnArrow( m_crossBarStart, crossBarAngle + EDA_ANGLE( 180 ),
1247 }
1248 else
1249 {
1250 drawAnArrow( m_crossBarStart, crossBarAngle, 0 );
1251 drawAnArrow( m_crossBarEnd, crossBarAngle + EDA_ANGLE( 180 ), 0 );
1252 }
1253
1254 m_busy = false;
1255}
1256
1257
1259{
1260 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1261
1263 {
1264 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1265
1266 VECTOR2I textOffset;
1267
1269 textOffset.y = -textOffsetDistance;
1270 else
1271 textOffset.x = -textOffsetDistance;
1272
1273 textOffset += crossbarCenter;
1274
1275 SetTextPos( m_crossBarStart + textOffset );
1276 }
1278 {
1279 SetTextPos( m_crossBarStart + crossbarCenter );
1280 }
1281
1282 if( m_keepTextAligned )
1283 {
1284 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
1286 else
1288 }
1289
1291}
1292
1293
1294void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1295{
1296 EDA_ANGLE angle( aAngle );
1297
1298 // restrict angle to -179.9 to 180.0 degrees
1299 angle.Normalize180();
1300
1301 // adjust orientation and height to new angle
1302 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
1303 // in the other cases we will use the nearest 90 degree angle to
1304 // choose at least an approximate axis for the target orientation
1305 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
1306 if( angle > ANGLE_45 && angle <= ANGLE_135 )
1307 {
1308 // about 90 degree
1310 {
1312 }
1313 else
1314 {
1316 m_height = -m_height;
1317 }
1318 }
1319 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
1320 {
1321 // about -90 degree
1323 {
1325 m_height = -m_height;
1326 }
1327 else
1328 {
1330 }
1331 }
1332 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
1333 {
1334 // about 180 degree
1335 m_height = -m_height;
1336 }
1337
1338 // this will update m_crossBarStart and m_crossbarEnd
1339 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
1340}
1341
1342
1353
1354
1355void PCB_DIM_LEADER::Serialize( google::protobuf::Any &aContainer ) const
1356{
1357 using namespace kiapi::common;
1358 kiapi::board::types::Dimension dimension;
1359
1360 PCB_DIMENSION_BASE::Serialize( aContainer );
1361 aContainer.UnpackTo( &dimension );
1362
1363 PackVector2( *dimension.mutable_leader()->mutable_start(), m_start );
1364 PackVector2( *dimension.mutable_leader()->mutable_end(), m_end );
1365 dimension.mutable_leader()->set_border_style(
1367 m_textBorder ) );
1368
1369 aContainer.PackFrom( dimension );
1370}
1371
1372
1373bool PCB_DIM_LEADER::Deserialize( const google::protobuf::Any &aContainer )
1374{
1375 using namespace kiapi::common;
1376
1377 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1378 return false;
1379
1380 kiapi::board::types::Dimension dimension;
1381 aContainer.UnpackTo( &dimension );
1382
1383 if( !dimension.has_leader() )
1384 return false;
1385
1386 SetStart( UnpackVector2( dimension.leader().start() ) );
1387 SetEnd( UnpackVector2( dimension.leader().end() ) );
1388 SetTextBorder( FromProtoEnum<DIM_TEXT_BORDER>( dimension.leader().border_style() ) );
1389
1390 Update();
1391
1392 return true;
1393}
1394
1395
1397{
1398 return new PCB_DIM_LEADER( *this );
1399}
1400
1401
1403{
1404 wxASSERT( aImage->Type() == Type() );
1405
1406 m_shapes.clear();
1407 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
1408
1409 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
1410
1411 Update();
1412}
1413
1414
1419
1420
1422{
1423 // Our geometry is dependent on the size of the text, so just update the whole shebang
1425}
1426
1427
1429{
1430 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1431 return;
1432
1433 m_busy = true;
1434
1435 m_shapes.clear();
1436
1438
1439 // Now that we have the text updated, we can determine how to draw the second line
1440 // First we need to create an appropriate bounding polygon to collide with
1441 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1442
1443 SHAPE_POLY_SET polyBox;
1444 polyBox.NewOutline();
1445 polyBox.Append( textBox.GetOrigin() );
1446 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1447 polyBox.Append( textBox.GetEnd() );
1448 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1449 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1450
1451 VECTOR2I firstLine( m_end - m_start );
1452 VECTOR2I start( m_start );
1453 start += firstLine.Resize( m_extensionOffset );
1454
1455 SEG arrowSeg( m_start, m_end );
1456 SEG textSeg( m_end, GetTextPos() );
1457 OPT_VECTOR2I arrowSegEnd;
1458 OPT_VECTOR2I textSegEnd;
1459
1461 {
1462 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1463 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1464 CIRCLE circle( textBox.GetCenter(), radius );
1465
1466 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1467 textSegEnd = segCircleIntersection( circle, textSeg );
1468 }
1469 else
1470 {
1471 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1472 textSegEnd = segPolyIntersection( polyBox, textSeg );
1473 }
1474
1475 if( !arrowSegEnd )
1476 arrowSegEnd = m_end;
1477
1478 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1479
1480 drawAnArrow( start, EDA_ANGLE( firstLine ), 0 );
1481
1482 if( !GetText().IsEmpty() )
1483 {
1484 switch( m_textBorder )
1485 {
1487 {
1488 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1489 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1490
1491 break;
1492 }
1493
1495 {
1496 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1497 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1498 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1499
1500 break;
1501 }
1502
1503 default:
1504 break;
1505 }
1506 }
1507
1508 if( textSegEnd && *arrowSegEnd == m_end )
1509 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, *textSegEnd ) );
1510
1511 m_busy = false;
1512}
1513
1514
1515void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1516{
1517 // Don't use GetShownText(); we want to see the variable references here
1518 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1519
1520 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
1521
1522 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1523 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1524 aFrame->MessageTextFromValue( startCoord.x ),
1525 aFrame->MessageTextFromValue( startCoord.y ) );
1526
1527 aList.emplace_back( start, wxEmptyString );
1528
1529 aList.emplace_back( _( "Layer" ), GetLayerName() );
1530}
1531
1532
1542
1543
1544void PCB_DIM_RADIAL::Serialize( google::protobuf::Any &aContainer ) const
1545{
1546 using namespace kiapi::common;
1547 kiapi::board::types::Dimension dimension;
1548
1549 PCB_DIMENSION_BASE::Serialize( aContainer );
1550 aContainer.UnpackTo( &dimension );
1551
1552 PackVector2( *dimension.mutable_radial()->mutable_center(), m_start );
1553 PackVector2( *dimension.mutable_radial()->mutable_radius_point(), m_end );
1554 dimension.mutable_radial()->mutable_leader_length()->set_value_nm( m_leaderLength );
1555
1556 aContainer.PackFrom( dimension );
1557}
1558
1559
1560bool PCB_DIM_RADIAL::Deserialize( const google::protobuf::Any &aContainer )
1561{
1562 using namespace kiapi::common;
1563
1564 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1565 return false;
1566
1567 kiapi::board::types::Dimension dimension;
1568 aContainer.UnpackTo( &dimension );
1569
1570 if( !dimension.has_radial() )
1571 return false;
1572
1573 SetStart( UnpackVector2( dimension.radial().center() ) );
1574 SetEnd( UnpackVector2( dimension.radial().radius_point() ) );
1575 SetLeaderLength( dimension.radial().leader_length().value_nm() );
1576
1577 Update();
1578
1579 return true;
1580}
1581
1582
1584{
1585 return new PCB_DIM_RADIAL( *this );
1586}
1587
1588
1590{
1591 wxASSERT( aImage->Type() == Type() );
1592
1593 m_shapes.clear();
1594 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1595
1596 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1597
1598 Update();
1599}
1600
1601
1606
1607
1609{
1610 VECTOR2I radial( m_end - m_start );
1611
1612 return m_end + radial.Resize( m_leaderLength );
1613}
1614
1615
1617{
1618 if( m_keepTextAligned )
1619 {
1620 VECTOR2I textLine( GetTextPos() - GetKnee() );
1621 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1622
1623 textAngle.Normalize();
1624
1625 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1626 textAngle -= ANGLE_180;
1627
1628 // Round to nearest degree
1629 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1630
1631 SetTextAngle( textAngle );
1632 }
1633
1635}
1636
1637
1639{
1640 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1641 return;
1642
1643 m_busy = true;
1644
1645 m_shapes.clear();
1646
1648 VECTOR2I centerArm( 0, m_arrowLength );
1649
1650 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1651
1652 RotatePoint( centerArm, -ANGLE_90 );
1653
1654 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1655
1657
1658 m_measuredValue = KiROUND( radius.EuclideanNorm() );
1659
1660 updateText();
1661
1662 // Now that we have the text updated, we can determine how to draw the second line
1663 // First we need to create an appropriate bounding polygon to collide with
1664 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1665
1666 SHAPE_POLY_SET polyBox;
1667 polyBox.NewOutline();
1668 polyBox.Append( textBox.GetOrigin() );
1669 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1670 polyBox.Append( textBox.GetEnd() );
1671 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1672 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1673
1674 VECTOR2I radial( m_end - m_start );
1675 radial = radial.Resize( m_leaderLength );
1676
1677 SEG arrowSeg( m_end, m_end + radial );
1678 SEG textSeg( arrowSeg.B, GetTextPos() );
1679
1680 CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
1681 CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
1682
1683 drawAnArrow( m_end, EDA_ANGLE( radial ), 0 );
1684
1685 m_busy = false;
1686}
1687
1688
1695
1696
1697void PCB_DIM_CENTER::Serialize( google::protobuf::Any &aContainer ) const
1698{
1699 using namespace kiapi::common;
1700 kiapi::board::types::Dimension dimension;
1701
1702 PCB_DIMENSION_BASE::Serialize( aContainer );
1703 aContainer.UnpackTo( &dimension );
1704
1705 PackVector2( *dimension.mutable_center()->mutable_center(), m_start );
1706 PackVector2( *dimension.mutable_center()->mutable_end(), m_end );
1707
1708 aContainer.PackFrom( dimension );
1709}
1710
1711
1712bool PCB_DIM_CENTER::Deserialize( const google::protobuf::Any &aContainer )
1713{
1714 using namespace kiapi::common;
1715
1716 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1717 return false;
1718
1719 kiapi::board::types::Dimension dimension;
1720 aContainer.UnpackTo( &dimension );
1721
1722 if( !dimension.has_center() )
1723 return false;
1724
1725 SetStart( UnpackVector2( dimension.center().center() ) );
1726 SetEnd( UnpackVector2( dimension.center().end() ) );
1727
1728 Update();
1729
1730 return true;
1731}
1732
1733
1735{
1736 return new PCB_DIM_CENTER( *this );
1737}
1738
1739
1741{
1742 wxASSERT( aImage->Type() == Type() );
1743
1744 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1745}
1746
1747
1752
1753
1755{
1756 BOX2I bBox;
1757 int xmin, xmax, ymin, ymax;
1758
1759 xmin = m_start.x;
1760 xmax = m_start.x;
1761 ymin = m_start.y;
1762 ymax = m_start.y;
1763
1764 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
1765 {
1766 BOX2I shapeBox = shape->BBox();
1767 shapeBox.Inflate( m_lineThickness / 2 );
1768
1769 xmin = std::min( xmin, shapeBox.GetOrigin().x );
1770 xmax = std::max( xmax, shapeBox.GetEnd().x );
1771 ymin = std::min( ymin, shapeBox.GetOrigin().y );
1772 ymax = std::max( ymax, shapeBox.GetEnd().y );
1773 }
1774
1775 bBox.SetX( xmin );
1776 bBox.SetY( ymin );
1777 bBox.SetWidth( xmax - xmin + 1 );
1778 bBox.SetHeight( ymax - ymin + 1 );
1779
1780 bBox.Normalize();
1781
1782 return bBox;
1783}
1784
1785
1787{
1788 return GetBoundingBox();
1789}
1790
1791
1793{
1794 // Even if PCB_DIM_CENTER has no text, we still need to update its text position
1795 // so GetTextPos() users get a valid value. Required at least for lasso hit-testing.
1797
1799}
1800
1801
1803{
1804 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1805 return;
1806
1807 m_busy = true;
1808
1809 m_shapes.clear();
1810
1812 VECTOR2I arm( m_end - m_start );
1813
1814 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1815
1816 RotatePoint( arm, -ANGLE_90 );
1817
1818 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1819
1820 updateText();
1821
1822 m_busy = false;
1823}
1824
1825
1826static struct DIMENSION_DESC
1827{
1829 {
1831 .Map( DIM_PRECISION::X, _HKI( "0" ) )
1832 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
1833 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
1834 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
1835 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
1836 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
1837 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
1838 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
1839 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
1840 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
1841
1843 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
1844 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
1845 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
1846
1848 .Map( DIM_UNITS_MODE::INCH, _HKI( "Inches" ) )
1849 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
1850 .Map( DIM_UNITS_MODE::MM, _HKI( "Millimeters" ) )
1851 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
1852
1854 .Map( DIM_ARROW_DIRECTION::INWARD, _HKI( "Inward" ) )
1855 .Map( DIM_ARROW_DIRECTION::OUTWARD, _HKI( "Outward" ) );
1856
1865
1866 propMgr.Mask( TYPE_HASH( PCB_DIMENSION_BASE ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
1867
1868 const wxString groupDimension = _HKI( "Dimension Properties" );
1869
1870 auto isLeader =
1871 []( INSPECTABLE* aItem ) -> bool
1872 {
1873 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
1874 };
1875
1876 auto isNotLeader =
1877 []( INSPECTABLE* aItem ) -> bool
1878 {
1879 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
1880 };
1881
1882 auto isMultiArrowDirection =
1883 []( INSPECTABLE* aItem ) -> bool
1884 {
1885 return dynamic_cast<PCB_DIM_ALIGNED*>( aItem ) != nullptr;
1886 };
1887
1890 groupDimension )
1891 .SetAvailableFunc( isNotLeader );
1894 groupDimension )
1895 .SetAvailableFunc( isNotLeader );
1896 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
1898 groupDimension )
1899 .SetAvailableFunc( isNotLeader );
1900
1903 groupDimension )
1904 .SetAvailableFunc( isLeader );
1905
1908 groupDimension )
1909 .SetAvailableFunc( isNotLeader );
1912 groupDimension )
1913 .SetAvailableFunc( isNotLeader );
1916 groupDimension )
1917 .SetAvailableFunc( isNotLeader );
1918 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
1920 groupDimension )
1921 .SetAvailableFunc( isNotLeader );
1922
1925 groupDimension )
1926 .SetAvailableFunc( isMultiArrowDirection );
1927
1928 const wxString groupText = _HKI( "Text Properties" );
1929
1930 const auto isTextOrientationWriteable =
1931 []( INSPECTABLE* aItem ) -> bool
1932 {
1933 return !static_cast<PCB_DIMENSION_BASE*>( aItem )->GetKeepTextAligned();
1934 };
1935
1936 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Keep Aligned with Dimension" ),
1939 groupText );
1940
1941 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, double>( _HKI( "Orientation" ),
1945 groupText )
1946 .SetWriteableFunc( isTextOrientationWriteable );
1947 }
1949
1954
1955
1957{
1959 {
1970
1971 const wxString groupDimension = _HKI( "Dimension Properties" );
1972
1973 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
1976 groupDimension );
1977 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
1980 groupDimension );
1981
1983 _HKI( "Text" ),
1984 []( INSPECTABLE* aItem ) { return false; } );
1986 _HKI( "Vertical Justification" ),
1987 []( INSPECTABLE* aItem ) { return false; } );
1989 _HKI( "Hyperlink" ),
1990 []( INSPECTABLE* aItem ) { return false; } );
1992 _HKI( "Knockout" ),
1993 []( INSPECTABLE* aItem ) { return false; } );
1994 }
1996
1997
1999{
2001 {
2014
2016 _HKI( "Text" ),
2017 []( INSPECTABLE* aItem ) { return false; } );
2019 _HKI( "Vertical Justification" ),
2020 []( INSPECTABLE* aItem ) { return false; } );
2022 _HKI( "Hyperlink" ),
2023 []( INSPECTABLE* aItem ) { return false; } );
2025 _HKI( "Knockout" ),
2026 []( INSPECTABLE* aItem ) { return false; } );
2027 }
2029
2030
2032{
2034 {
2045
2046 const wxString groupDimension = _HKI( "Dimension Properties" );
2047
2048 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
2051 groupDimension );
2052
2054 _HKI( "Text" ),
2055 []( INSPECTABLE* aItem ) { return false; } );
2057 _HKI( "Vertical Justification" ),
2058 []( INSPECTABLE* aItem ) { return false; } );
2060 _HKI( "Hyperlink" ),
2061 []( INSPECTABLE* aItem ) { return false; } );
2063 _HKI( "Knockout" ),
2064 []( INSPECTABLE* aItem ) { return false; } );
2065 }
2067
2068
2070{
2072 {
2074 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
2075 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
2076 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
2077
2088
2089 const wxString groupDimension = _HKI( "Dimension Properties" );
2090
2093 groupDimension );
2094
2096 _HKI( "Text" ),
2097 []( INSPECTABLE* aItem ) { return false; } );
2099 _HKI( "Vertical Justification" ),
2100 []( INSPECTABLE* aItem ) { return false; } );
2102 _HKI( "Hyperlink" ),
2103 []( INSPECTABLE* aItem ) { return false; } );
2105 _HKI( "Knockout" ),
2106 []( INSPECTABLE* aItem ) { return false; } );
2107 }
2109
2111
2112
2114{
2116 {
2127
2128
2130 _HKI( "Text" ),
2131 []( INSPECTABLE* aItem ) { return false; } );
2133 _HKI( "Vertical Justification" ),
2134 []( INSPECTABLE* aItem ) { return false; } );
2136 _HKI( "Hyperlink" ),
2137 []( INSPECTABLE* aItem ) { return false; } );
2139 _HKI( "Knockout" ),
2140 []( INSPECTABLE* aItem ) { return false; } );
2141 }
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
Definition api_enums.cpp:97
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:36
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:237
void SetLocked(bool aLocked) override
Definition board_item.h:328
PCB_LAYER_ID m_layer
Definition board_item.h:459
bool IsLocked() const override
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:285
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:811
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:99
const KIID m_Uuid
Definition eda_item.h:522
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:111
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:534
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:204
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:590
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition eda_text.cpp:238
KIFONT::FONT * GetFont() const
Definition eda_text.h:247
void SetMirrored(bool isMirrored)
Definition eda_text.cpp:407
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:608
double Similarity(const EDA_TEXT &aOther) const
virtual void ClearRenderCache()
Definition eda_text.cpp:683
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:479
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:284
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:313
int GetTextThickness() const
Definition eda_text.h:128
bool operator==(const EDA_TEXT &aRhs) const
Definition eda_text.h:398
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: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:142
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: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