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>
39#include <geometry/shape_rect.h>
43#include <trigo.h>
44#include <api/api_enums.h>
45#include <api/api_utils.h>
46#include <api/board/board_types.pb.h>
47
48
50
51static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
52
53
62static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
63 bool aStart = true )
64{
65 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
66 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
67
68 if( aPoly.Contains( start ) )
69 return std::nullopt;
70
71 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
72 {
73 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
74 {
75 if( ( *intersection - start ).SquaredEuclideanNorm()
76 < ( endpoint - start ).SquaredEuclideanNorm() )
77 endpoint = *intersection;
78 }
79 }
80
81 if( start == endpoint )
82 return std::nullopt;
83
84 return OPT_VECTOR2I( endpoint );
85}
86
87
88static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true )
89{
90 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
91 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
92
93 if( aCircle.Contains( start ) )
94 return std::nullopt;
95
96 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
97
98 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
99 {
100 if( ( intersection - start ).SquaredEuclideanNorm()
101 < ( endpoint - start ).SquaredEuclideanNorm() )
102 endpoint = intersection;
103 }
104
105 if( start == endpoint )
106 return std::nullopt;
107
108 return OPT_VECTOR2I( endpoint );
109}
110
111
116static void CollectKnockedOutSegments( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
117 std::vector<std::shared_ptr<SHAPE>>& aSegmentsAfterKnockout )
118{
119 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
120 const bool containsA = aPoly.Contains( aSeg.A );
121 const bool containsB = aPoly.Contains( aSeg.B );
122
123 const OPT_VECTOR2I endpointA = segPolyIntersection( aPoly, aSeg );
124 const OPT_VECTOR2I endpointB = segPolyIntersection( aPoly, aSeg, false );
125
126 if( endpointA )
127 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg.A, *endpointA ) );
128
129 if( endpointB )
130 {
131 bool can_add = true;
132
133 if( endpointA )
134 {
135 if( ( *endpointB == aSeg.A && *endpointA == aSeg.B )
136 || ( *endpointA == *endpointB && aSeg.A == aSeg.B ) )
137 can_add = false;
138 }
139
140 if( can_add )
141 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( *endpointB, aSeg.B ) );
142 }
143
144 if( !containsA && !containsB && !endpointA && !endpointB )
145 aSegmentsAfterKnockout.emplace_back( new SHAPE_SEGMENT( aSeg ) );
146}
147
148
150 PCB_TEXT( aParent, aType ),
151 m_overrideTextEnabled( false ),
152 m_units( EDA_UNITS::INCH ),
153 m_autoUnits( false ),
154 m_unitsFormat( DIM_UNITS_FORMAT::BARE_SUFFIX ),
155 m_arrowDirection( DIM_ARROW_DIRECTION::OUTWARD ),
156 m_precision( DIM_PRECISION::X_XXXX ),
157 m_suppressZeroes( false ),
158 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
159 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
160 m_extensionOffset( 0 ),
161 m_textPosition( DIM_TEXT_POSITION::OUTSIDE ),
162 m_keepTextAligned( true ),
163 m_measuredValue( 0 ),
164 m_inClearRenderCache( false )
165{
167 m_busy = false;
168}
169
170
172{
173 if( Type() != aOther.Type() )
174 return false;
175
176 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
177
178 return *this == other;
179}
180
181
183{
184 if( m_textPosition != aOther.m_textPosition )
185 return false;
186
188 return false;
189
190 if( m_units != aOther.m_units )
191 return false;
192
193 if( m_autoUnits != aOther.m_autoUnits )
194 return false;
195
196 if( m_unitsFormat != aOther.m_unitsFormat )
197 return false;
198
199 if( m_precision != aOther.m_precision )
200 return false;
201
202 if( m_suppressZeroes != aOther.m_suppressZeroes )
203 return false;
204
205 if( m_lineThickness != aOther.m_lineThickness )
206 return false;
207
208 if( m_arrowLength != aOther.m_arrowLength )
209 return false;
210
212 return false;
213
214 if( m_measuredValue != aOther.m_measuredValue )
215 return false;
216
217 return EDA_TEXT::operator==( aOther );
218}
219
220
221double PCB_DIMENSION_BASE::Similarity( const BOARD_ITEM& aOther ) const
222{
223 if( m_Uuid == aOther.m_Uuid )
224 return 1.0;
225
226 if( Type() != aOther.Type() )
227 return 0.0;
228
229 const PCB_DIMENSION_BASE& other = static_cast<const PCB_DIMENSION_BASE&>( aOther );
230
231 double similarity = 1.0;
232
233 if( m_textPosition != other.m_textPosition )
234 similarity *= 0.9;
235
237 similarity *= 0.9;
238
239 if( m_units != other.m_units )
240 similarity *= 0.9;
241
242 if( m_autoUnits != other.m_autoUnits )
243 similarity *= 0.9;
244
245 if( m_unitsFormat != other.m_unitsFormat )
246 similarity *= 0.9;
247
248 if( m_precision != other.m_precision )
249 similarity *= 0.9;
250
252 similarity *= 0.9;
253
254 if( m_lineThickness != other.m_lineThickness )
255 similarity *= 0.9;
256
257 if( m_arrowLength != other.m_arrowLength )
258 similarity *= 0.9;
259
261 similarity *= 0.9;
262
263 if( m_measuredValue != other.m_measuredValue )
264 similarity *= 0.9;
265
266 similarity *= EDA_TEXT::Similarity( other );
267
268 return similarity;
269}
270
271
272void PCB_DIMENSION_BASE::Serialize( google::protobuf::Any &aContainer ) const
273{
274 using namespace kiapi::common;
275 using namespace kiapi::board::types;
276 Dimension dimension;
277
278 dimension.mutable_id()->set_value( m_Uuid.AsStdString() );
279 dimension.set_layer( ToProtoEnum<PCB_LAYER_ID, BoardLayer>( GetLayer() ) );
280 dimension.set_locked( IsLocked() ? types::LockedState::LS_LOCKED
281 : types::LockedState::LS_UNLOCKED );
282
283 google::protobuf::Any any;
284 EDA_TEXT::Serialize( any );
285 any.UnpackTo( dimension.mutable_text() );
286
287 types::Text* text = dimension.mutable_text();
288 text->set_text( GetValueText() );
289
290 dimension.set_override_text_enabled( m_overrideTextEnabled );
291 dimension.set_override_text( m_valueString.ToUTF8() );
292 dimension.set_prefix( m_prefix.ToUTF8() );
293 dimension.set_suffix( m_suffix.ToUTF8() );
294
295 dimension.set_unit( ToProtoEnum<DIM_UNITS_MODE, DimensionUnit>( GetUnitsMode() ) );
296 dimension.set_unit_format(
297 ToProtoEnum<DIM_UNITS_FORMAT, DimensionUnitFormat>( m_unitsFormat ) );
298 dimension.set_arrow_direction(
299 ToProtoEnum<DIM_ARROW_DIRECTION, DimensionArrowDirection>( m_arrowDirection ) );
300 dimension.set_precision( ToProtoEnum<DIM_PRECISION, DimensionPrecision>( m_precision ) );
301 dimension.set_suppress_trailing_zeroes( m_suppressZeroes );
302
303 dimension.mutable_line_thickness()->set_value_nm( m_lineThickness );
304 dimension.mutable_arrow_length()->set_value_nm( m_arrowLength );
305 dimension.mutable_extension_offset()->set_value_nm( m_extensionOffset );
306 dimension.set_text_position(
307 ToProtoEnum<DIM_TEXT_POSITION, DimensionTextPosition>( m_textPosition ) );
308 dimension.set_keep_text_aligned( m_keepTextAligned );
309
310 aContainer.PackFrom( dimension );
311}
312
313
314bool PCB_DIMENSION_BASE::Deserialize( const google::protobuf::Any &aContainer )
315{
316 using namespace kiapi::common;
317 kiapi::board::types::Dimension dimension;
318
319 if( !aContainer.UnpackTo( &dimension ) )
320 return false;
321
322 SetLayer( FromProtoEnum<PCB_LAYER_ID, kiapi::board::types::BoardLayer>( dimension.layer() ) );
323 const_cast<KIID&>( m_Uuid ) = KIID( dimension.id().value() );
324 SetLocked( dimension.locked() == types::LockedState::LS_LOCKED );
325
326 google::protobuf::Any any;
327 any.PackFrom( dimension.text() );
329
330 SetOverrideTextEnabled( dimension.override_text_enabled() );
331 SetOverrideText( wxString::FromUTF8( dimension.override_text() ) );
332 SetPrefix( wxString::FromUTF8( dimension.prefix() ) );
333 SetSuffix( wxString::FromUTF8( dimension.suffix() ) );
334
335 SetUnitsMode( FromProtoEnum<DIM_UNITS_MODE>( dimension.unit() ) );
336 SetUnitsFormat( FromProtoEnum<DIM_UNITS_FORMAT>( dimension.unit_format() ) );
337 SetArrowDirection( FromProtoEnum<DIM_ARROW_DIRECTION>( dimension.arrow_direction() ) );
338 SetPrecision( FromProtoEnum<DIM_PRECISION>( dimension.precision() ) );
339 SetSuppressZeroes( dimension.suppress_trailing_zeroes() );
340
341 SetLineThickness( dimension.line_thickness().value_nm() );
342 SetArrowLength( dimension.arrow_length().value_nm() );
343 SetExtensionOffset( dimension.extension_offset().value_nm() );
344 SetTextPositionMode( FromProtoEnum<DIM_TEXT_POSITION>( dimension.text_position() ) );
345 SetKeepTextAligned( dimension.keep_text_aligned() );
346
347 Update();
348
349 return true;
350}
351
352
353void PCB_DIMENSION_BASE::drawAnArrow( VECTOR2I startPoint, EDA_ANGLE anAngle, int aLength )
354{
355 if( aLength )
356 {
357 VECTOR2I tailEnd( aLength, 0 );
358 RotatePoint( tailEnd, -anAngle );
359 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + tailEnd ) );
360 }
361
362 VECTOR2I arrowEndPos( m_arrowLength, 0 );
363 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
364
365 RotatePoint( arrowEndPos, -anAngle + s_arrowAngle );
366 RotatePoint( arrowEndNeg, -anAngle - s_arrowAngle );
367
368 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndPos ) );
369 m_shapes.emplace_back( new SHAPE_SEGMENT( startPoint, startPoint + arrowEndNeg ) );
370}
371
372
374{
376
377 switch( m_unitsFormat )
378 {
379 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
380 break;
381
382 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
384 break;
385
386 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
387 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
388 break;
389 }
390
391 text.Prepend( m_prefix );
392 text.Append( m_suffix );
393
394 SetText( text );
395}
396
397
399{
401
402 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
403 // have changed and we may need to update the dimension text
404
406 {
408 Update();
409 m_inClearRenderCache = false;
410 }
411}
412
413
414template<typename ShapeType>
415void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
416{
417 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
418}
419
420
422{
423 struct lconv* lc = localeconv();
424 wxChar sep = lc->decimal_point[0];
425
426 int val = GetMeasuredValue();
427 int precision = static_cast<int>( m_precision );
428 wxString text;
429
430 if( precision >= 6 )
431 {
432 switch( m_units )
433 {
434 case EDA_UNITS::INCH: precision = precision - 4; break;
435 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
436 case EDA_UNITS::MM: precision = precision - 5; break;
437 default: precision = precision - 4; break;
438 }
439 }
440
441 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
442
443 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
444
445 if( m_suppressZeroes )
446 {
447 while( text.EndsWith( '0' ) )
448 {
449 text.RemoveLast();
450
451 if( text.EndsWith( '.' ) || text.EndsWith( sep ) )
452 {
453 text.RemoveLast();
454 break;
455 }
456 }
457 }
458
459 return text;
460}
461
462
463void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
464{
465 m_prefix = aPrefix;
466}
467
468
469void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
470{
471 m_suffix = aSuffix;
472}
473
474
476{
477 m_units = aUnits;
478}
479
480
482{
483 if( m_autoUnits )
484 {
485 return DIM_UNITS_MODE::AUTOMATIC;
486 }
487 else
488 {
489 switch( m_units )
490 {
491 default:
492 case EDA_UNITS::INCH: return DIM_UNITS_MODE::INCH;
493 case EDA_UNITS::MM: return DIM_UNITS_MODE::MM;
494 case EDA_UNITS::MILS: return DIM_UNITS_MODE::MILS;
495 }
496 }
497}
498
499
501{
502 switch( aMode )
503 {
504 case DIM_UNITS_MODE::INCH:
505 m_autoUnits = false;
506 m_units = EDA_UNITS::INCH;
507 break;
508
509 case DIM_UNITS_MODE::MILS:
510 m_autoUnits = false;
511 m_units = EDA_UNITS::MILS;
512 break;
513
514 case DIM_UNITS_MODE::MM:
515 m_autoUnits = false;
516 m_units = EDA_UNITS::MM;
517 break;
518
519 case DIM_UNITS_MODE::AUTOMATIC:
520 m_autoUnits = true;
521 m_units = GetBoard() ? GetBoard()->GetUserUnits() : EDA_UNITS::MM;
522 break;
523 }
524}
525
526
528{
529 SetTextAngleDegrees( aDegrees );
530 // Create or repair any knockouts
531 Update();
532}
533
534
536{
537 SetKeepTextAligned( aKeepAligned );
538 // Re-align the text and repair any knockouts
539 Update();
540}
541
542
544{
545 PCB_TEXT::Offset( offset );
546
547 m_start += offset;
548 m_end += offset;
549
550 Update();
551}
552
553
554void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
555{
556 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
557
558 newAngle.Normalize();
559
560 SetTextAngle( newAngle );
561
562 VECTOR2I pt = GetTextPos();
563 RotatePoint( pt, aRotCentre, aAngle );
564 SetTextPos( pt );
565
566 RotatePoint( m_start, aRotCentre, aAngle );
567 RotatePoint( m_end, aRotCentre, aAngle );
568
569 Update();
570}
571
572
573void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
574{
575 Mirror( aCentre, aFlipDirection );
576
578}
579
580
581void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
582{
583 VECTOR2I newPos = GetTextPos();
584
585 MIRROR( newPos, axis_pos, aFlipDirection );
586
587 SetTextPos( newPos );
588
589 // invert angle
591
592 MIRROR( m_start, axis_pos, aFlipDirection );
593 MIRROR( m_end, axis_pos, aFlipDirection );
594
595 if( IsSideSpecific() )
597
598 Update();
599}
600
601
603 std::vector<MSG_PANEL_ITEM>& aList )
604{
605 // for now, display only the text within the DIMENSION using class PCB_TEXT.
606 wxString msg;
607
608 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
609
610 // Don't use GetShownText(); we want to see the variable references here
611 aList.emplace_back( _( "Dimension" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
612
613 aList.emplace_back( _( "Prefix" ), GetPrefix() );
614
616 {
617 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
618 }
619 else
620 {
621 aList.emplace_back( _( "Value" ), GetValueText() );
622
623 switch( GetPrecision() )
624 {
625 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
626 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
627 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
628 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
629 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
630 }
631
632 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
633 }
634
635 aList.emplace_back( _( "Suffix" ), GetSuffix() );
636
637 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
638 // in frame's units.
639 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
640 unitsProvider.SetUserUnits( GetUnits() );
641
642 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
643
644 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
645 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
646 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
647 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
648
649 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
650
651 if( Type() == PCB_DIM_CENTER_T )
652 {
653 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
654 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
655 aFrame->MessageTextFromValue( startCoord.x ),
656 aFrame->MessageTextFromValue( startCoord.y ) );
657
658 aList.emplace_back( start, wxEmptyString );
659 }
660 else
661 {
662 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
663 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
664 aFrame->MessageTextFromValue( startCoord.x ),
665 aFrame->MessageTextFromValue( startCoord.y ) );
666 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
667 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
668 aFrame->MessageTextFromValue( endCoord.x ),
669 aFrame->MessageTextFromValue( endCoord.y ) );
670
671 aList.emplace_back( start, end );
672 }
673
674 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
675 aList.emplace_back( _( "Status" ), _( "Locked" ) );
676
677 aList.emplace_back( _( "Layer" ), GetLayerName() );
678}
679
680
681std::shared_ptr<SHAPE> PCB_DIMENSION_BASE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
682{
683 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
684
685 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
686
687 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
688 effectiveShape->AddShape( shape->Clone() );
689
690 return effectiveShape;
691}
692
693
694bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
695{
696 if( TextHitTest( aPosition ) )
697 return true;
698
699 int dist_max = aAccuracy + ( m_lineThickness / 2 );
700
701 // Locate SEGMENTS
702
703 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
704 {
705 if( shape->Collide( aPosition, dist_max ) )
706 return true;
707 }
708
709 return false;
710}
711
712
713bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
714{
715 BOX2I arect = aRect;
716 arect.Inflate( aAccuracy );
717
718 BOX2I rect = GetBoundingBox();
719
720 if( aAccuracy )
721 rect.Inflate( aAccuracy );
722
723 if( aContained )
724 return arect.Contains( rect );
725
726 return arect.Intersects( rect );
727}
728
729
730bool PCB_DIMENSION_BASE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
731{
732 // Note: Can't use GetEffectiveShape() because we want text as BoundingBox, not as graphics.
733 SHAPE_COMPOUND effShape;
734
735 // Add shapes
736 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
737 effShape.AddShape( shape );
738
739 if( aContained )
740 return TextHitTest( aPoly, aContained ) && KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
741 else
742 return TextHitTest( aPoly, aContained ) || KIGEOM::ShapeHitTest( aPoly, effShape, aContained );
743}
744
745
747{
748 BOX2I bBox;
749 int xmin, xmax, ymin, ymax;
750
751 bBox = GetTextBox( nullptr );
752 xmin = bBox.GetX();
753 xmax = bBox.GetRight();
754 ymin = bBox.GetY();
755 ymax = bBox.GetBottom();
756
757 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
758 {
759 BOX2I shapeBox = shape->BBox();
760 shapeBox.Inflate( m_lineThickness / 2 );
761
762 xmin = std::min( xmin, shapeBox.GetOrigin().x );
763 xmax = std::max( xmax, shapeBox.GetEnd().x );
764 ymin = std::min( ymin, shapeBox.GetOrigin().y );
765 ymax = std::max( ymax, shapeBox.GetEnd().y );
766 }
767
768 bBox.SetX( xmin );
769 bBox.SetY( ymin );
770 bBox.SetWidth( xmax - xmin + 1 );
771 bBox.SetHeight( ymax - ymin + 1 );
772
773 bBox.Normalize();
774
775 return bBox;
776}
777
778
779wxString PCB_DIMENSION_BASE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
780{
781 return wxString::Format( _( "Dimension '%s' on %s" ),
782 aFull ? GetShownText( false ) : KIUI::EllipsizeMenuText( GetText() ),
783 GetLayerName() );
784}
785
786
787
789{
791 VECTOR2I( GetBoundingBox().GetSize() ) );
792 dimBBox.Merge( PCB_TEXT::ViewBBox() );
793
794 return dimBBox;
795}
796
797
799 int aClearance, int aError, ERROR_LOC aErrorLoc,
800 bool aIgnoreLineWidth ) const
801{
802 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
803
804 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
805 {
806 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
807 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
808
809 if( circle )
810 {
812 circle->GetRadius() + m_lineThickness / 2 + aClearance,
813 aError, aErrorLoc );
814 }
815 else if( seg )
816 {
817 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
818 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
819 }
820 else
821 {
822 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
823 }
824 }
825}
826
827
829 PCB_DIMENSION_BASE( aParent, aType ),
830 m_height( 0 )
831{
832 // To preserve look of old dimensions, initialize extension height based on default arrow length
833 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
834}
835
836
838{
839 return new PCB_DIM_ALIGNED( *this );
840}
841
842
843void PCB_DIM_ALIGNED::Serialize( google::protobuf::Any &aContainer ) const
844{
845 using namespace kiapi::common;
846 kiapi::board::types::Dimension dimension;
847
848 PCB_DIMENSION_BASE::Serialize( aContainer );
849 aContainer.UnpackTo( &dimension );
850
851 PackVector2( *dimension.mutable_aligned()->mutable_start(), m_start );
852 PackVector2( *dimension.mutable_aligned()->mutable_end(), m_end );
853 dimension.mutable_aligned()->mutable_height()->set_value_nm( m_height );
854 dimension.mutable_aligned()->mutable_extension_height()->set_value_nm( m_extensionHeight );
855
856 aContainer.PackFrom( dimension );
857}
858
859
860bool PCB_DIM_ALIGNED::Deserialize( const google::protobuf::Any &aContainer )
861{
862 using namespace kiapi::common;
863
864 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
865 return false;
866
867 kiapi::board::types::Dimension dimension;
868 aContainer.UnpackTo( &dimension );
869
870 if( !dimension.has_aligned() )
871 return false;
872
873 SetStart( UnpackVector2( dimension.aligned().start() ) );
874 SetEnd( UnpackVector2( dimension.aligned().end() ) );
875 SetHeight( dimension.aligned().height().value_nm());
876 SetExtensionHeight( dimension.aligned().extension_height().value_nm() );
877
878 Update();
879
880 return true;
881}
882
883
885{
886 wxASSERT( aImage->Type() == Type() );
887
888 m_shapes.clear();
889 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
890
891 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
892
893 Update();
894}
895
896
897void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
898{
900 // Call this last for the Update()
901 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
902}
903
904
906{
907 return BITMAPS::add_aligned_dimension;
908}
909
910
911void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
912{
913 VECTOR2D height( aCrossbarStart - GetStart() );
914 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
915
916 if( height.Cross( crossBar ) > 0 )
917 m_height = -height.EuclideanNorm();
918 else
919 m_height = height.EuclideanNorm();
920
921 Update();
922}
923
924
926{
927 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
928 return;
929
930 m_busy = true;
931
932 m_shapes.clear();
933
934 VECTOR2I dimension( m_end - m_start );
935
936 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
937
938 VECTOR2I extension;
939
940 if( m_height > 0 )
941 extension = VECTOR2I( -dimension.y, dimension.x );
942 else
943 extension = VECTOR2I( dimension.y, -dimension.x );
944
945 // Add extension lines
946 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
947
948 VECTOR2I extStart( m_start );
949 extStart += extension.Resize( m_extensionOffset );
950
951 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
952
953 extStart = VECTOR2I( m_end );
954 extStart += extension.Resize( m_extensionOffset );
955
956 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
957
958 // Add crossbar
959 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
960 m_crossBarStart = m_start + crossBarDistance;
961 m_crossBarEnd = m_end + crossBarDistance;
962
963 // Update text after calculating crossbar position but before adding crossbar lines
964 updateText();
965
966 // Now that we have the text updated, we can determine how to draw the crossbar.
967 // First we need to create an appropriate bounding polygon to collide with
968 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, - GetEffectiveTextPenWidth() );
969
970 SHAPE_POLY_SET polyBox;
971 polyBox.NewOutline();
972 polyBox.Append( textBox.GetOrigin() );
973 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
974 polyBox.Append( textBox.GetEnd() );
975 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
976 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
977
978 // The ideal crossbar, if the text doesn't collide
979 SEG crossbar( m_crossBarStart, m_crossBarEnd );
980
981 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
982
983 if( m_arrowDirection == DIM_ARROW_DIRECTION::INWARD )
984 {
985 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ),
987 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ),
989 }
990 else
991 {
992 drawAnArrow( m_crossBarStart, EDA_ANGLE( dimension ), 0 );
993 drawAnArrow( m_crossBarEnd, EDA_ANGLE( dimension ) + EDA_ANGLE( 180 ), 0 );
994 }
995
996 m_busy = false;
997}
998
999
1001{
1002 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1003
1004 if( m_textPosition == DIM_TEXT_POSITION::OUTSIDE )
1005 {
1006 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1007 EDA_ANGLE rotation;
1008
1009 if( crossbarCenter.x == 0 )
1010 rotation = ANGLE_90 * sign( -crossbarCenter.y );
1011 else if( crossbarCenter.x < 0 )
1012 rotation = -ANGLE_90;
1013 else
1014 rotation = ANGLE_90;
1015
1016 VECTOR2I textOffset = crossbarCenter;
1017 RotatePoint( textOffset, rotation );
1018 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
1019
1020 SetTextPos( m_crossBarStart + textOffset );
1021 }
1022 else if( m_textPosition == DIM_TEXT_POSITION::INLINE )
1023 {
1024 SetTextPos( m_crossBarStart + crossbarCenter );
1025 }
1026
1027 if( m_keepTextAligned )
1028 {
1029 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
1030 textAngle.Normalize();
1031
1032 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1033 textAngle -= ANGLE_180;
1034
1035 SetTextAngle( textAngle );
1036 }
1037
1039}
1040
1041
1042void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1043{
1044 PCB_DIMENSION_BASE::GetMsgPanelInfo( aFrame, aList );
1045
1046 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
1047 // in frame's units.
1048 UNITS_PROVIDER unitsProvider( pcbIUScale, EDA_UNITS::MM );
1049 unitsProvider.SetUserUnits( GetUnits() );
1050
1051 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
1052}
1053
1054
1057{
1058 // To preserve look of old dimensions, initialize extension height based on default arrow length
1059 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
1061}
1062
1063
1065{
1066 return new PCB_DIM_ORTHOGONAL( *this );
1067}
1068
1069
1070void PCB_DIM_ORTHOGONAL::Serialize( google::protobuf::Any &aContainer ) const
1071{
1072 using namespace kiapi::common;
1073 kiapi::board::types::Dimension dimension;
1074
1075 PCB_DIMENSION_BASE::Serialize( aContainer );
1076 aContainer.UnpackTo( &dimension );
1077
1078 PackVector2( *dimension.mutable_orthogonal()->mutable_start(), m_start );
1079 PackVector2( *dimension.mutable_orthogonal()->mutable_end(), m_end );
1080 dimension.mutable_orthogonal()->mutable_height()->set_value_nm( m_height );
1081 dimension.mutable_orthogonal()->mutable_extension_height()->set_value_nm( m_extensionHeight );
1082
1083 dimension.mutable_orthogonal()->set_alignment( m_orientation == DIR::VERTICAL
1084 ? types::AxisAlignment::AA_Y_AXIS
1085 : types::AxisAlignment::AA_X_AXIS );
1086 aContainer.PackFrom( dimension );
1087}
1088
1089
1090bool PCB_DIM_ORTHOGONAL::Deserialize( const google::protobuf::Any &aContainer )
1091{
1092 using namespace kiapi::common;
1093
1094 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1095 return false;
1096
1097 kiapi::board::types::Dimension dimension;
1098 aContainer.UnpackTo( &dimension );
1099
1100 if( !dimension.has_orthogonal() )
1101 return false;
1102
1103 SetStart( UnpackVector2( dimension.orthogonal().start() ) );
1104 SetEnd( UnpackVector2( dimension.orthogonal().end() ) );
1105 SetHeight( dimension.orthogonal().height().value_nm());
1106 SetExtensionHeight( dimension.orthogonal().extension_height().value_nm() );
1107 SetOrientation( dimension.orthogonal().alignment() == types::AxisAlignment::AA_Y_AXIS
1109 : DIR::HORIZONTAL );
1110
1111 Update();
1112
1113 return true;
1114}
1115
1116
1118{
1119 wxASSERT( aImage->Type() == Type() );
1120
1121 m_shapes.clear();
1122 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
1123
1124 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
1125 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
1126
1127 Update();
1128}
1129
1130
1131void PCB_DIM_ORTHOGONAL::Mirror( const VECTOR2I& axis_pos, FLIP_DIRECTION aFlipDirection )
1132{
1133 // Only reverse the height if the height is aligned with the flip
1134 if( m_orientation == DIR::HORIZONTAL && aFlipDirection == FLIP_DIRECTION::TOP_BOTTOM )
1135 m_height = -m_height;
1136 else if( m_orientation == DIR::VERTICAL && aFlipDirection == FLIP_DIRECTION::LEFT_RIGHT )
1137 m_height = -m_height;
1138
1139 // Call this last, as we need the Update()
1140 PCB_DIMENSION_BASE::Mirror( axis_pos, aFlipDirection );
1141}
1142
1143
1145{
1146 return BITMAPS::add_orthogonal_dimension;
1147}
1148
1149
1151{
1152 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1153 return;
1154
1155 m_busy = true;
1156 m_shapes.clear();
1157
1159 m_end.y - m_start.y );
1161
1162 VECTOR2I extension;
1163
1165 extension = VECTOR2I( 0, m_height );
1166 else
1167 extension = VECTOR2I( m_height, 0 );
1168
1169 // Add first extension line
1170 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
1171
1172 VECTOR2I extStart( m_start );
1173 extStart += extension.Resize( m_extensionOffset );
1174
1175 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1176
1177 // Add crossbar
1178 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
1179 m_crossBarStart = m_start + crossBarDistance;
1180
1183 else
1185
1186 // Add second extension line (m_end to crossbar end)
1188 extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y );
1189 else
1190 extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 );
1191
1192 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
1193
1194 extStart = VECTOR2I( m_crossBarEnd );
1195 extStart -= extension.Resize( m_extensionHeight );
1196
1197 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
1198
1199 // Update text after calculating crossbar position but before adding crossbar lines
1200 updateText();
1201
1202 // Now that we have the text updated, we can determine how to draw the crossbar.
1203 // First we need to create an appropriate bounding polygon to collide with
1204 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1205
1206 SHAPE_POLY_SET polyBox;
1207 polyBox.NewOutline();
1208 polyBox.Append( textBox.GetOrigin() );
1209 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1210 polyBox.Append( textBox.GetEnd() );
1211 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1212 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1213
1214 // The ideal crossbar, if the text doesn't collide
1215 SEG crossbar( m_crossBarStart, m_crossBarEnd );
1216
1217 CollectKnockedOutSegments( polyBox, crossbar, m_shapes );
1218
1219 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
1220
1221 if( m_arrowDirection == DIM_ARROW_DIRECTION::INWARD )
1222 {
1223 // Arrows with fixed length.
1224 drawAnArrow( m_crossBarStart, crossBarAngle + EDA_ANGLE( 180 ),
1227 }
1228 else
1229 {
1230 drawAnArrow( m_crossBarStart, crossBarAngle, 0 );
1231 drawAnArrow( m_crossBarEnd, crossBarAngle + EDA_ANGLE( 180 ), 0 );
1232 }
1233
1234 m_busy = false;
1235}
1236
1237
1239{
1240 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
1241
1242 if( m_textPosition == DIM_TEXT_POSITION::OUTSIDE )
1243 {
1244 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
1245
1246 VECTOR2I textOffset;
1247
1249 textOffset.y = -textOffsetDistance;
1250 else
1251 textOffset.x = -textOffsetDistance;
1252
1253 textOffset += crossbarCenter;
1254
1255 SetTextPos( m_crossBarStart + textOffset );
1256 }
1257 else if( m_textPosition == DIM_TEXT_POSITION::INLINE )
1258 {
1259 SetTextPos( m_crossBarStart + crossbarCenter );
1260 }
1261
1262 if( m_keepTextAligned )
1263 {
1264 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
1266 else
1268 }
1269
1271}
1272
1273
1274void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
1275{
1276 EDA_ANGLE angle( aAngle );
1277
1278 // restrict angle to -179.9 to 180.0 degrees
1279 angle.Normalize180();
1280
1281 // adjust orientation and height to new angle
1282 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
1283 // in the other cases we will use the nearest 90 degree angle to
1284 // choose at least an approximate axis for the target orientation
1285 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
1286 if( angle > ANGLE_45 && angle <= ANGLE_135 )
1287 {
1288 // about 90 degree
1290 {
1292 }
1293 else
1294 {
1296 m_height = -m_height;
1297 }
1298 }
1299 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
1300 {
1301 // about -90 degree
1303 {
1305 m_height = -m_height;
1306 }
1307 else
1308 {
1310 }
1311 }
1312 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
1313 {
1314 // about 180 degree
1315 m_height = -m_height;
1316 }
1317
1318 // this will update m_crossBarStart and m_crossbarEnd
1319 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
1320}
1321
1322
1325 m_textBorder( DIM_TEXT_BORDER::NONE )
1326{
1327 m_unitsFormat = DIM_UNITS_FORMAT::NO_SUFFIX;
1328 m_overrideTextEnabled = true;
1329 m_keepTextAligned = false;
1330
1331 SetOverrideText( _( "Leader" ) );
1332}
1333
1334
1335void PCB_DIM_LEADER::Serialize( google::protobuf::Any &aContainer ) const
1336{
1337 using namespace kiapi::common;
1338 kiapi::board::types::Dimension dimension;
1339
1340 PCB_DIMENSION_BASE::Serialize( aContainer );
1341 aContainer.UnpackTo( &dimension );
1342
1343 PackVector2( *dimension.mutable_leader()->mutable_start(), m_start );
1344 PackVector2( *dimension.mutable_leader()->mutable_end(), m_end );
1345 dimension.mutable_leader()->set_border_style(
1346 ToProtoEnum<DIM_TEXT_BORDER, kiapi::board::types::DimensionTextBorderStyle>(
1347 m_textBorder ) );
1348
1349 aContainer.PackFrom( dimension );
1350}
1351
1352
1353bool PCB_DIM_LEADER::Deserialize( const google::protobuf::Any &aContainer )
1354{
1355 using namespace kiapi::common;
1356
1357 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1358 return false;
1359
1360 kiapi::board::types::Dimension dimension;
1361 aContainer.UnpackTo( &dimension );
1362
1363 if( !dimension.has_leader() )
1364 return false;
1365
1366 SetStart( UnpackVector2( dimension.leader().start() ) );
1367 SetEnd( UnpackVector2( dimension.leader().end() ) );
1368 SetTextBorder( FromProtoEnum<DIM_TEXT_BORDER>( dimension.leader().border_style() ) );
1369
1370 Update();
1371
1372 return true;
1373}
1374
1375
1377{
1378 return new PCB_DIM_LEADER( *this );
1379}
1380
1381
1383{
1384 wxASSERT( aImage->Type() == Type() );
1385
1386 m_shapes.clear();
1387 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
1388
1389 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
1390
1391 Update();
1392}
1393
1394
1396{
1397 return BITMAPS::add_leader;
1398}
1399
1400
1402{
1403 // Our geometry is dependent on the size of the text, so just update the whole shebang
1405}
1406
1407
1409{
1410 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1411 return;
1412
1413 m_busy = true;
1414
1415 m_shapes.clear();
1416
1418
1419 // Now that we have the text updated, we can determine how to draw the second line
1420 // First we need to create an appropriate bounding polygon to collide with
1421 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1422
1423 SHAPE_POLY_SET polyBox;
1424 polyBox.NewOutline();
1425 polyBox.Append( textBox.GetOrigin() );
1426 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1427 polyBox.Append( textBox.GetEnd() );
1428 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1429 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1430
1431 VECTOR2I firstLine( m_end - m_start );
1432 VECTOR2I start( m_start );
1433 start += firstLine.Resize( m_extensionOffset );
1434
1435 SEG arrowSeg( m_start, m_end );
1436 SEG textSeg( m_end, GetTextPos() );
1437 OPT_VECTOR2I arrowSegEnd;
1438 OPT_VECTOR2I textSegEnd;
1439
1440 if( m_textBorder == DIM_TEXT_BORDER::CIRCLE )
1441 {
1442 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1443 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1444 CIRCLE circle( textBox.GetCenter(), radius );
1445
1446 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1447 textSegEnd = segCircleIntersection( circle, textSeg );
1448 }
1449 else
1450 {
1451 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1452 textSegEnd = segPolyIntersection( polyBox, textSeg );
1453 }
1454
1455 if( !arrowSegEnd )
1456 arrowSegEnd = m_end;
1457
1458 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1459
1460 drawAnArrow( start, EDA_ANGLE( firstLine ), 0 );
1461
1462 if( !GetText().IsEmpty() )
1463 {
1464 switch( m_textBorder )
1465 {
1466 case DIM_TEXT_BORDER::RECTANGLE:
1467 {
1468 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1469 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1470
1471 break;
1472 }
1473
1474 case DIM_TEXT_BORDER::CIRCLE:
1475 {
1476 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1477 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1478 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1479
1480 break;
1481 }
1482
1483 default:
1484 break;
1485 }
1486 }
1487
1488 if( textSegEnd && *arrowSegEnd == m_end )
1489 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, *textSegEnd ) );
1490
1491 m_busy = false;
1492}
1493
1494
1495void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1496{
1497 // Don't use GetShownText(); we want to see the variable references here
1498 aList.emplace_back( _( "Leader" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
1499
1500 ORIGIN_TRANSFORMS& originTransforms = aFrame->GetOriginTransforms();
1501
1502 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1503 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1504 aFrame->MessageTextFromValue( startCoord.x ),
1505 aFrame->MessageTextFromValue( startCoord.y ) );
1506
1507 aList.emplace_back( start, wxEmptyString );
1508
1509 aList.emplace_back( _( "Layer" ), GetLayerName() );
1510}
1511
1512
1515{
1516 m_unitsFormat = DIM_UNITS_FORMAT::NO_SUFFIX;
1517 m_overrideTextEnabled = false;
1518 m_keepTextAligned = true;
1519 m_prefix = "R ";
1521}
1522
1523
1524void PCB_DIM_RADIAL::Serialize( google::protobuf::Any &aContainer ) const
1525{
1526 using namespace kiapi::common;
1527 kiapi::board::types::Dimension dimension;
1528
1529 PCB_DIMENSION_BASE::Serialize( aContainer );
1530 aContainer.UnpackTo( &dimension );
1531
1532 PackVector2( *dimension.mutable_radial()->mutable_center(), m_start );
1533 PackVector2( *dimension.mutable_radial()->mutable_radius_point(), m_end );
1534 dimension.mutable_radial()->mutable_leader_length()->set_value_nm( m_leaderLength );
1535
1536 aContainer.PackFrom( dimension );
1537}
1538
1539
1540bool PCB_DIM_RADIAL::Deserialize( const google::protobuf::Any &aContainer )
1541{
1542 using namespace kiapi::common;
1543
1544 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1545 return false;
1546
1547 kiapi::board::types::Dimension dimension;
1548 aContainer.UnpackTo( &dimension );
1549
1550 if( !dimension.has_radial() )
1551 return false;
1552
1553 SetStart( UnpackVector2( dimension.radial().center() ) );
1554 SetEnd( UnpackVector2( dimension.radial().radius_point() ) );
1555 SetLeaderLength( dimension.radial().leader_length().value_nm() );
1556
1557 Update();
1558
1559 return true;
1560}
1561
1562
1564{
1565 return new PCB_DIM_RADIAL( *this );
1566}
1567
1568
1570{
1571 wxASSERT( aImage->Type() == Type() );
1572
1573 m_shapes.clear();
1574 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1575
1576 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1577
1578 Update();
1579}
1580
1581
1583{
1584 return BITMAPS::add_radial_dimension;
1585}
1586
1587
1589{
1590 VECTOR2I radial( m_end - m_start );
1591
1592 return m_end + radial.Resize( m_leaderLength );
1593}
1594
1595
1597{
1598 if( m_keepTextAligned )
1599 {
1600 VECTOR2I textLine( GetTextPos() - GetKnee() );
1601 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1602
1603 textAngle.Normalize();
1604
1605 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1606 textAngle -= ANGLE_180;
1607
1608 // Round to nearest degree
1609 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1610
1611 SetTextAngle( textAngle );
1612 }
1613
1615}
1616
1617
1619{
1620 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1621 return;
1622
1623 m_busy = true;
1624
1625 m_shapes.clear();
1626
1628 VECTOR2I centerArm( 0, m_arrowLength );
1629
1630 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1631
1632 RotatePoint( centerArm, -ANGLE_90 );
1633
1634 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1635
1637
1638 m_measuredValue = KiROUND( radius.EuclideanNorm() );
1639
1640 updateText();
1641
1642 // Now that we have the text updated, we can determine how to draw the second line
1643 // First we need to create an appropriate bounding polygon to collide with
1644 BOX2I textBox = GetTextBox( nullptr ).Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() );
1645
1646 SHAPE_POLY_SET polyBox;
1647 polyBox.NewOutline();
1648 polyBox.Append( textBox.GetOrigin() );
1649 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1650 polyBox.Append( textBox.GetEnd() );
1651 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1652 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1653
1654 VECTOR2I radial( m_end - m_start );
1655 radial = radial.Resize( m_leaderLength );
1656
1657 SEG arrowSeg( m_end, m_end + radial );
1658 SEG textSeg( arrowSeg.B, GetTextPos() );
1659
1660 CollectKnockedOutSegments( polyBox, arrowSeg, m_shapes );
1661 CollectKnockedOutSegments( polyBox, textSeg, m_shapes );
1662
1663 drawAnArrow( m_end, EDA_ANGLE( radial ), 0 );
1664
1665 m_busy = false;
1666}
1667
1668
1671{
1672 m_unitsFormat = DIM_UNITS_FORMAT::NO_SUFFIX;
1673 m_overrideTextEnabled = true;
1674}
1675
1676
1677void PCB_DIM_CENTER::Serialize( google::protobuf::Any &aContainer ) const
1678{
1679 using namespace kiapi::common;
1680 kiapi::board::types::Dimension dimension;
1681
1682 PCB_DIMENSION_BASE::Serialize( aContainer );
1683 aContainer.UnpackTo( &dimension );
1684
1685 PackVector2( *dimension.mutable_center()->mutable_center(), m_start );
1686 PackVector2( *dimension.mutable_center()->mutable_end(), m_end );
1687
1688 aContainer.PackFrom( dimension );
1689}
1690
1691
1692bool PCB_DIM_CENTER::Deserialize( const google::protobuf::Any &aContainer )
1693{
1694 using namespace kiapi::common;
1695
1696 if( !PCB_DIMENSION_BASE::Deserialize( aContainer ) )
1697 return false;
1698
1699 kiapi::board::types::Dimension dimension;
1700 aContainer.UnpackTo( &dimension );
1701
1702 if( !dimension.has_center() )
1703 return false;
1704
1705 SetStart( UnpackVector2( dimension.center().center() ) );
1706 SetEnd( UnpackVector2( dimension.center().end() ) );
1707
1708 Update();
1709
1710 return true;
1711}
1712
1713
1715{
1716 return new PCB_DIM_CENTER( *this );
1717}
1718
1719
1721{
1722 wxASSERT( aImage->Type() == Type() );
1723
1724 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1725}
1726
1727
1729{
1730 return BITMAPS::add_center_dimension;
1731}
1732
1733
1735{
1736 int halfWidth = VECTOR2I( m_end - m_start ).x + ( m_lineThickness / 2.0 );
1737
1738 BOX2I bBox;
1739
1740 bBox.SetX( m_start.x - halfWidth );
1741 bBox.SetY( m_start.y - halfWidth );
1742 bBox.SetWidth( halfWidth * 2 );
1743 bBox.SetHeight( halfWidth * 2 );
1744
1745 bBox.Normalize();
1746
1747 return bBox;
1748}
1749
1750// fixme: we cannot use GetBoundingBox() as it returns the bbox of the 'leader' segment (used in hit testing and other non-view logic)
1752{
1753 const int maxSize = std::max(m_end.x - m_start.x, m_end.y - m_start.y) + m_lineThickness / 2.0;
1754
1755 BOX2I bBox;
1756
1757 bBox.SetX( m_start.x - maxSize );
1758 bBox.SetY( m_start.y - maxSize );
1759 bBox.SetWidth( maxSize * 2 );
1760 bBox.SetHeight( maxSize * 2 );
1761
1762 return bBox;
1763}
1764
1765
1767{
1768 // Even if PCB_DIM_CENTER has no text, we still need to update its text position
1769 // so GetTextPos() users get a valid value. Required at least for lasso hit-testing.
1771
1773}
1774
1775
1777{
1778 if( m_busy ) // Skeep reentrance that happens sometimes after calling updateText()
1779 return;
1780
1781 m_busy = true;
1782
1783 m_shapes.clear();
1784
1786 VECTOR2I arm( m_end - m_start );
1787
1788 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1789
1790 RotatePoint( arm, -ANGLE_90 );
1791
1792 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1793
1794 updateText();
1795
1796 m_busy = false;
1797}
1798
1799
1800static struct DIMENSION_DESC
1801{
1803 {
1805 .Map( DIM_PRECISION::X, _HKI( "0" ) )
1806 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
1807 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
1808 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
1809 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
1810 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
1811 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
1812 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
1813 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
1814 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
1815
1817 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
1818 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
1819 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
1820
1822 .Map( DIM_UNITS_MODE::INCH, _HKI( "Inches" ) )
1823 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
1824 .Map( DIM_UNITS_MODE::MM, _HKI( "Millimeters" ) )
1825 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
1826
1828 .Map( DIM_ARROW_DIRECTION::INWARD, _HKI( "Inward" ) )
1829 .Map( DIM_ARROW_DIRECTION::OUTWARD, _HKI( "Outward" ) );
1830
1839
1840 propMgr.Mask( TYPE_HASH( PCB_DIMENSION_BASE ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
1841
1842 const wxString groupDimension = _HKI( "Dimension Properties" );
1843
1844 auto isLeader =
1845 []( INSPECTABLE* aItem ) -> bool
1846 {
1847 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) != nullptr;
1848 };
1849
1850 auto isNotLeader =
1851 []( INSPECTABLE* aItem ) -> bool
1852 {
1853 return dynamic_cast<PCB_DIM_LEADER*>( aItem ) == nullptr;
1854 };
1855
1856 auto isMultiArrowDirection =
1857 []( INSPECTABLE* aItem ) -> bool
1858 {
1859 return dynamic_cast<PCB_DIM_ALIGNED*>( aItem ) != nullptr;
1860 };
1861
1864 groupDimension )
1865 .SetAvailableFunc( isNotLeader );
1868 groupDimension )
1869 .SetAvailableFunc( isNotLeader );
1870 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
1872 groupDimension )
1873 .SetAvailableFunc( isNotLeader );
1874
1877 groupDimension )
1878 .SetAvailableFunc( isLeader );
1879
1882 groupDimension )
1883 .SetAvailableFunc( isNotLeader );
1886 groupDimension )
1887 .SetAvailableFunc( isNotLeader );
1890 groupDimension )
1891 .SetAvailableFunc( isNotLeader );
1892 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
1894 groupDimension )
1895 .SetAvailableFunc( isNotLeader );
1896
1899 groupDimension )
1900 .SetAvailableFunc( isMultiArrowDirection );
1901
1902 const wxString groupText = _HKI( "Text Properties" );
1903
1904 const auto isTextOrientationWriteable =
1905 []( INSPECTABLE* aItem ) -> bool
1906 {
1907 return !static_cast<PCB_DIMENSION_BASE*>( aItem )->GetKeepTextAligned();
1908 };
1909
1910 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Keep Aligned with Dimension" ),
1913 groupText );
1914
1915 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, double>( _HKI( "Orientation" ),
1918 PROPERTY_DISPLAY::PT_DEGREE ),
1919 groupText )
1920 .SetWriteableFunc( isTextOrientationWriteable );
1921 }
1923
1928
1929
1931{
1933 {
1944
1945 const wxString groupDimension = _HKI( "Dimension Properties" );
1946
1947 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
1950 groupDimension );
1951 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
1954 groupDimension );
1955
1957 _HKI( "Text" ),
1958 []( INSPECTABLE* aItem ) { return false; } );
1960 _HKI( "Vertical Justification" ),
1961 []( INSPECTABLE* aItem ) { return false; } );
1963 _HKI( "Hyperlink" ),
1964 []( INSPECTABLE* aItem ) { return false; } );
1966 _HKI( "Knockout" ),
1967 []( INSPECTABLE* aItem ) { return false; } );
1968 }
1970
1971
1973{
1975 {
1988
1990 _HKI( "Text" ),
1991 []( INSPECTABLE* aItem ) { return false; } );
1993 _HKI( "Vertical Justification" ),
1994 []( INSPECTABLE* aItem ) { return false; } );
1996 _HKI( "Hyperlink" ),
1997 []( INSPECTABLE* aItem ) { return false; } );
1999 _HKI( "Knockout" ),
2000 []( INSPECTABLE* aItem ) { return false; } );
2001 }
2003
2004
2006{
2008 {
2019
2020 const wxString groupDimension = _HKI( "Dimension Properties" );
2021
2022 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
2024 PROPERTY_DISPLAY::PT_SIZE ),
2025 groupDimension );
2026
2028 _HKI( "Text" ),
2029 []( INSPECTABLE* aItem ) { return false; } );
2031 _HKI( "Vertical Justification" ),
2032 []( INSPECTABLE* aItem ) { return false; } );
2034 _HKI( "Hyperlink" ),
2035 []( INSPECTABLE* aItem ) { return false; } );
2037 _HKI( "Knockout" ),
2038 []( INSPECTABLE* aItem ) { return false; } );
2039 }
2041
2042
2044{
2046 {
2048 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
2049 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
2050 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
2051
2062
2063 const wxString groupDimension = _HKI( "Dimension Properties" );
2064
2067 groupDimension );
2068
2070 _HKI( "Text" ),
2071 []( INSPECTABLE* aItem ) { return false; } );
2073 _HKI( "Vertical Justification" ),
2074 []( INSPECTABLE* aItem ) { return false; } );
2076 _HKI( "Hyperlink" ),
2077 []( INSPECTABLE* aItem ) { return false; } );
2079 _HKI( "Knockout" ),
2080 []( INSPECTABLE* aItem ) { return false; } );
2081 }
2083
2085
2086
2088{
2090 {
2101
2102
2104 _HKI( "Text" ),
2105 []( INSPECTABLE* aItem ) { return false; } );
2107 _HKI( "Vertical Justification" ),
2108 []( INSPECTABLE* aItem ) { return false; } );
2110 _HKI( "Hyperlink" ),
2111 []( INSPECTABLE* aItem ) { return false; } );
2113 _HKI( "Knockout" ),
2114 []( INSPECTABLE* aItem ) { return false; } );
2115 }
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
Definition: approximation.h:32
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
BOX2< VECTOR2I > BOX2I
Definition: box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:232
void SetLocked(bool aLocked) override
Definition: board_item.h:323
PCB_LAYER_ID m_layer
Definition: board_item.h:453
bool IsLocked() const override
Definition: board_item.cpp:103
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:280
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:79
bool IsSideSpecific() const
Definition: board_item.cpp:190
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:180
EDA_UNITS GetUserUnits()
Definition: board.h:754
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 Sin() const
Definition: eda_angle.h:178
double AsDegrees() const
Definition: eda_angle.h:116
EDA_ANGLE Normalize180()
Definition: eda_angle.h:268
ORIGIN_TRANSFORMS & GetOriginTransforms() override
Return a reference to the default ORIGIN_TRANSFORMS object.
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
const KIID m_Uuid
Definition: eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
EDA_ITEM * m_parent
Owner.
Definition: eda_item.h:528
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
int GetTextHeight() const
Definition: eda_text.h:264
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: eda_text.cpp:187
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:270
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:97
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:578
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: eda_text.cpp:223
KIFONT::FONT * GetFont() const
Definition: eda_text.h:244
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:393
int GetTextWidth() const
Definition: eda_text.h:261
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:735
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:596
double Similarity(const EDA_TEXT &aOther) const
Definition: eda_text.cpp:1267
virtual void ClearRenderCache()
Definition: eda_text.cpp:663
bool IsMirrored() const
Definition: eda_text.h:187
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition: eda_text.cpp:465
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.
Definition: eda_text.cpp:1108
void SetTextAngleDegrees(double aOrientation)
Definition: eda_text.h:147
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:270
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:299
int GetTextThickness() const
Definition: eda_text.h:125
bool operator==(const EDA_TEXT &aRhs) const
Definition: eda_text.h:393
static ENUM_MAP< T > & Instance()
Definition: property.h:697
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:37
Definition: kiid.h:49
std::string AsStdString() const
Definition: kiid.cpp:252
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)
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.
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: pcb_text.cpp:203
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: pcb_text.cpp:139
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition: pcb_text.cpp:361
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_text.cpp:475
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:258
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition: property.h:283
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:74
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()
Definition: property_mgr.h:76
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
int GetRadius() const
Definition: shape_circle.h:118
const VECTOR2I GetCenter() const
Definition: shape_circle.h:123
void AddShape(SHAPE *aShape)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Base class for iterating over all segments in a given SHAPE_POLY_SET.
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...
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.
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
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 _HKI(x)
#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
@ NONE
Definition: eda_shape.h:69
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:170
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
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.
Definition: eda_units.cpp:289
KICOMMON_API wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:144
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:180
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.
Definition: ui_common.cpp:221
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.
Definition: ui_common.cpp:203
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:400
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.
Definition: pcb_dimension.h:62
@ OUTSIDE
Text appears outside the dimension line (default)
DIM_UNITS_FORMAT
How to display the units in a dimension's text.
Definition: pcb_dimension.h:40
DIM_UNITS_MODE
Used for storing the units selection in the file because EDA_UNITS alone doesn't cut it.
Definition: pcb_dimension.h:72
DIM_ARROW_DIRECTION
Used for dimension's arrow.
Definition: pcb_dimension.h:83
DIM_TEXT_BORDER
Frame to show around dimension text.
Definition: pcb_dimension.h:92
DIM_PRECISION
Definition: pcb_dimension.h:47
#define TYPE_HASH(x)
Definition: property.h:72
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:799
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition: property.h:62
#define REGISTER_TYPE(x)
Definition: property_mgr.h:351
@ INCH
Definition: rs274x.cpp:62
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:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
constexpr int sign(T val)
Definition: util.h:145
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695