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