KiCad PCB EDA Suite
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) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <bitmaps.h>
28#include <pcb_edit_frame.h>
29#include <base_units.h>
31#include <pcb_dimension.h>
32#include <pcb_text.h>
38#include <trigo.h>
39
40
41static const EDA_ANGLE s_arrowAngle( 27.5, DEGREES_T );
42
43
45 PCB_TEXT( aParent, aType ),
46 m_overrideTextEnabled( false ),
47 m_units( EDA_UNITS::INCHES ),
48 m_autoUnits( false ),
49 m_unitsFormat( DIM_UNITS_FORMAT::BARE_SUFFIX ),
50 m_precision( DIM_PRECISION::X_XXXX ),
51 m_suppressZeroes( false ),
52 m_lineThickness( pcbIUScale.mmToIU( 0.2 ) ),
53 m_arrowLength( pcbIUScale.MilsToIU( 50 ) ),
54 m_extensionOffset( 0 ),
55 m_textPosition( DIM_TEXT_POSITION::OUTSIDE ),
56 m_keepTextAligned( true ),
57 m_measuredValue( 0 ),
58 m_inClearRenderCache( false )
59{
61}
62
63
65{
67
68 switch( m_unitsFormat )
69 {
70 case DIM_UNITS_FORMAT::NO_SUFFIX: // no units
71 break;
72
73 case DIM_UNITS_FORMAT::BARE_SUFFIX: // normal
75 break;
76
77 case DIM_UNITS_FORMAT::PAREN_SUFFIX: // parenthetical
78 text += wxT( " (" ) + EDA_UNIT_UTILS::GetText( m_units ).Trim( false ) + wxT( ")" );
79 break;
80 }
81
82 text.Prepend( m_prefix );
83 text.Append( m_suffix );
84
85 SetText( text );
86}
87
88
90{
92
93 // We use EDA_TEXT::ClearRenderCache() as a signal that the properties of the EDA_TEXT
94 // have changed and we may need to update the dimension text
95
97 {
99 updateText();
100 m_inClearRenderCache = false;
101 }
102}
103
104
105template<typename ShapeType>
106void PCB_DIMENSION_BASE::addShape( const ShapeType& aShape )
107{
108 m_shapes.push_back( std::make_shared<ShapeType>( aShape ) );
109}
110
111
113{
114 struct lconv* lc = localeconv();
115 wxChar sep = lc->decimal_point[0];
116
117 int val = GetMeasuredValue();
118 int precision = static_cast<int>( m_precision );
119 wxString text;
120
121 if( precision >= 6 )
122 {
123 switch( m_units )
124 {
125 case EDA_UNITS::INCHES: precision = precision - 4; break;
126 case EDA_UNITS::MILS: precision = std::max( 0, precision - 7 ); break;
127 case EDA_UNITS::MILLIMETRES: precision = precision - 5; break;
128 default: precision = precision - 4; break;
129 }
130 }
131
132 wxString format = wxT( "%." ) + wxString::Format( wxT( "%i" ), precision ) + wxT( "f" );
133
134 text.Printf( format, EDA_UNIT_UTILS::UI::ToUserUnit( pcbIUScale, m_units, val ) );
135
136 if( m_suppressZeroes )
137 {
138 while( text.Last() == '0' )
139 {
140 text.RemoveLast();
141
142 if( text.Last() == '.' || text.Last() == sep )
143 {
144 text.RemoveLast();
145 break;
146 }
147 }
148 }
149
150 return text;
151}
152
153
154void PCB_DIMENSION_BASE::SetPrefix( const wxString& aPrefix )
155{
156 m_prefix = aPrefix;
157}
158
159
160void PCB_DIMENSION_BASE::SetSuffix( const wxString& aSuffix )
161{
162 m_suffix = aSuffix;
163}
164
165
167{
168 m_units = aUnits;
169}
170
171
173{
174 if( m_autoUnits )
175 {
177 }
178 else
179 {
180 switch( m_units )
181 {
182 default:
186 }
187 }
188}
189
190
192{
193 switch( aMode )
194 {
196 m_autoUnits = false;
198 break;
199
201 m_autoUnits = false;
203 break;
204
206 m_autoUnits = false;
208 break;
209
211 m_autoUnits = true;
213 break;
214 }
215}
216
217
219{
220 PCB_TEXT::Offset( offset );
221
222 m_start += offset;
223 m_end += offset;
224
225 Update();
226}
227
228
229void PCB_DIMENSION_BASE::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
230{
231 EDA_ANGLE newAngle = GetTextAngle() + aAngle;
232
233 newAngle.Normalize();
234
235 SetTextAngle( newAngle );
236
237 VECTOR2I pt = GetTextPos();
238 RotatePoint( pt, aRotCentre, aAngle );
239 SetTextPos( pt );
240
241 RotatePoint( m_start, aRotCentre, aAngle );
242 RotatePoint( m_end, aRotCentre, aAngle );
243
244 Update();
245}
246
247
248void PCB_DIMENSION_BASE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
249{
250 Mirror( aCentre );
251
252 SetLayer( FlipLayer( GetLayer(), GetBoard()->GetCopperLayerCount() ) );
253}
254
255
256void PCB_DIMENSION_BASE::Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight )
257{
258 int axis = aMirrorLeftRight ? axis_pos.x : axis_pos.y;
259 VECTOR2I newPos = GetTextPos();
260
261#define INVERT( pos ) ( ( pos ) = axis - ( ( pos ) - axis ) )
262 if( aMirrorLeftRight )
263 INVERT( newPos.x );
264 else
265 INVERT( newPos.y );
266
267 SetTextPos( newPos );
268
269 // invert angle
271
272 if( aMirrorLeftRight )
273 {
274 INVERT( m_start.x );
275 INVERT( m_end.x );
276 }
277 else
278 {
279 INVERT( m_start.y );
280 INVERT( m_end.y );
281 }
282
283 if( ( GetLayerSet() & LSET::SideSpecificMask() ).any() )
285
286 Update();
287}
288
289
291 std::vector<MSG_PANEL_ITEM>& aList )
292{
293 // for now, display only the text within the DIMENSION using class PCB_TEXT.
294 wxString msg;
295
296 wxCHECK_RET( m_parent != nullptr, wxT( "PCB_TEXT::GetMsgPanelInfo() m_Parent is NULL." ) );
297
298 aList.emplace_back( _( "Dimension" ), GetShownText() );
299
300 aList.emplace_back( _( "Prefix" ), GetPrefix() );
301
303 {
304 aList.emplace_back( _( "Override Text" ), GetOverrideText() );
305 }
306 else
307 {
308 aList.emplace_back( _( "Value" ), GetValueText() );
309
310 switch( GetPrecision() )
311 {
312 case DIM_PRECISION::V_VV: msg = wxT( "0.00 in / 0 mils / 0.0 mm" ); break;
313 case DIM_PRECISION::V_VVV: msg = wxT( "0.000 in / 0 mils / 0.00 mm" ); break;
314 case DIM_PRECISION::V_VVVV: msg = wxT( "0.0000 in / 0.0 mils / 0.000 mm" ); break;
315 case DIM_PRECISION::V_VVVVV: msg = wxT( "0.00000 in / 0.00 mils / 0.0000 mm" ); break;
316 default: msg = wxT( "%" ) + wxString::Format( wxT( "1.%df" ), GetPrecision() );
317 }
318
319 aList.emplace_back( _( "Precision" ), wxString::Format( msg, 0.0 ) );
320 }
321
322 aList.emplace_back( _( "Suffix" ), GetSuffix() );
323
324 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
325 // in frame's units.
327 unitsProvider.SetUserUnits( GetUnits() );
328
329 aList.emplace_back( _( "Units" ), EDA_UNIT_UTILS::GetLabel( GetUnits() ) );
330
331 aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
332 aList.emplace_back( _( "Text Thickness" ), unitsProvider.MessageTextFromValue( GetTextThickness() ) );
333 aList.emplace_back( _( "Text Width" ), unitsProvider.MessageTextFromValue( GetTextWidth() ) );
334 aList.emplace_back( _( "Text Height" ), unitsProvider.MessageTextFromValue( GetTextHeight() ) );
335
336 ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
337
339 {
340 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
341 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
342 aFrame->MessageTextFromValue( startCoord.x ),
343 aFrame->MessageTextFromValue( startCoord.y ) );
344
345 aList.emplace_back( start, wxEmptyString );
346 }
347 else
348 {
349 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
350 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
351 aFrame->MessageTextFromValue( startCoord.x ),
352 aFrame->MessageTextFromValue( startCoord.y ) );
353 VECTOR2I endCoord = originTransforms.ToDisplayAbs( GetEnd() );
354 wxString end = wxString::Format( wxT( "@(%s, %s)" ),
355 aFrame->MessageTextFromValue( endCoord.x ),
356 aFrame->MessageTextFromValue( endCoord.y ) );
357
358 aList.emplace_back( start, end );
359 }
360
361 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME && IsLocked() )
362 aList.emplace_back( _( "Status" ), _( "Locked" ) );
363
364 aList.emplace_back( _( "Layer" ), GetLayerName() );
365}
366
367
368std::shared_ptr<SHAPE> PCB_DIMENSION_BASE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
369{
370 std::shared_ptr<SHAPE_COMPOUND> effectiveShape = std::make_shared<SHAPE_COMPOUND>();
371
372 effectiveShape->AddShape( GetEffectiveTextShape()->Clone() );
373
374 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
375 effectiveShape->AddShape( shape->Clone() );
376
377 return effectiveShape;
378}
379
380
381bool PCB_DIMENSION_BASE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
382{
383 if( TextHitTest( aPosition ) )
384 return true;
385
386 int dist_max = aAccuracy + ( m_lineThickness / 2 );
387
388 // Locate SEGMENTS
389
390 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
391 {
392 if( shape->Collide( aPosition, dist_max ) )
393 return true;
394 }
395
396 return false;
397}
398
399
400bool PCB_DIMENSION_BASE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
401{
402 BOX2I arect = aRect;
403 arect.Inflate( aAccuracy );
404
405 BOX2I rect = GetBoundingBox();
406
407 if( aAccuracy )
408 rect.Inflate( aAccuracy );
409
410 if( aContained )
411 return arect.Contains( rect );
412
413 return arect.Intersects( rect );
414}
415
416
418{
419 BOX2I bBox;
420 int xmin, xmax, ymin, ymax;
421
422 bBox = GetTextBox();
423 xmin = bBox.GetX();
424 xmax = bBox.GetRight();
425 ymin = bBox.GetY();
426 ymax = bBox.GetBottom();
427
428 for( const std::shared_ptr<SHAPE>& shape : GetShapes() )
429 {
430 BOX2I shapeBox = shape->BBox();
431 shapeBox.Inflate( m_lineThickness / 2 );
432
433 xmin = std::min( xmin, shapeBox.GetOrigin().x );
434 xmax = std::max( xmax, shapeBox.GetEnd().x );
435 ymin = std::min( ymin, shapeBox.GetOrigin().y );
436 ymax = std::max( ymax, shapeBox.GetEnd().y );
437 }
438
439 bBox.SetX( xmin );
440 bBox.SetY( ymin );
441 bBox.SetWidth( xmax - xmin + 1 );
442 bBox.SetHeight( ymax - ymin + 1 );
443
444 bBox.Normalize();
445
446 return bBox;
447}
448
449
451{
452 return wxString::Format( _( "Dimension '%s' on %s" ), GetText(), GetLayerName() );
453}
454
455
456
458{
460 VECTOR2I( GetBoundingBox().GetSize() ) );
461 dimBBox.Merge( PCB_TEXT::ViewBBox() );
462
463 return dimBBox;
464}
465
466
468 bool aStart )
469{
470 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
471 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
472
473 if( aPoly.Contains( start ) )
474 return std::nullopt;
475
476 for( SHAPE_POLY_SET::CONST_SEGMENT_ITERATOR seg = aPoly.CIterateSegments(); seg; ++seg )
477 {
478 if( OPT_VECTOR2I intersection = ( *seg ).Intersect( aSeg ) )
479 {
480 if( ( *intersection - start ).SquaredEuclideanNorm() <
481 ( endpoint - start ).SquaredEuclideanNorm() )
482 endpoint = *intersection;
483 }
484 }
485
486 if( start == endpoint )
487 return std::nullopt;
488
489 return OPT_VECTOR2I( endpoint );
490}
491
492
494{
495 VECTOR2I start( aStart ? aSeg.A : aSeg.B );
496 VECTOR2I endpoint( aStart ? aSeg.B : aSeg.A );
497
498 if( aCircle.Contains( start ) )
499 return std::nullopt;
500
501 std::vector<VECTOR2I> intersections = aCircle.Intersect( aSeg );
502
503 for( VECTOR2I& intersection : aCircle.Intersect( aSeg ) )
504 {
505 if( ( intersection - start ).SquaredEuclideanNorm() <
506 ( endpoint - start ).SquaredEuclideanNorm() )
507 endpoint = intersection;
508 }
509
510 if( start == endpoint )
511 return std::nullopt;
512
513 return OPT_VECTOR2I( endpoint );
514}
515
516
518 int aClearance, int aError, ERROR_LOC aErrorLoc,
519 bool aIgnoreLineWidth ) const
520{
521 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for dimensions." ) );
522
523 for( const std::shared_ptr<SHAPE>& shape : m_shapes )
524 {
525 const SHAPE_CIRCLE* circle = dynamic_cast<const SHAPE_CIRCLE*>( shape.get() );
526 const SHAPE_SEGMENT* seg = dynamic_cast<const SHAPE_SEGMENT*>( shape.get() );
527
528 if( circle )
529 {
530 TransformCircleToPolygon( aBuffer, circle->GetCenter(),
531 circle->GetRadius() + m_lineThickness / 2 + aClearance,
532 aError, aErrorLoc );
533 }
534 else if( seg )
535 {
536 TransformOvalToPolygon( aBuffer, seg->GetSeg().A, seg->GetSeg().B,
537 m_lineThickness + 2 * aClearance, aError, aErrorLoc );
538 }
539 else
540 {
541 wxFAIL_MSG( wxT( "PCB_DIMENSION_BASE::TransformShapeToPolygon unknown shape type." ) );
542 }
543 }
544}
545
546
548 PCB_DIMENSION_BASE( aParent, aType ),
549 m_height( 0 )
550{
551 // To preserve look of old dimensions, initialize extension height based on default arrow length
552 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
553}
554
555
557{
558 return new PCB_DIM_ALIGNED( *this );
559}
560
561
563{
564 wxASSERT( aImage->Type() == Type() );
565
566 m_shapes.clear();
567 static_cast<PCB_DIM_ALIGNED*>( aImage )->m_shapes.clear();
568
569 std::swap( *static_cast<PCB_DIM_ALIGNED*>( this ), *static_cast<PCB_DIM_ALIGNED*>( aImage ) );
570
571 Update();
572}
573
574
575void PCB_DIM_ALIGNED::Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight )
576{
577 PCB_DIMENSION_BASE::Mirror( axis_pos, aMirrorLeftRight );
578
580}
581
582
584{
586}
587
588
589void PCB_DIM_ALIGNED::UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd )
590{
591 VECTOR2D height( aCrossbarStart - GetStart() );
592 VECTOR2D crossBar( aCrossbarEnd - aCrossbarStart );
593
594 if( height.Cross( crossBar ) > 0 )
595 m_height = -height.EuclideanNorm();
596 else
597 m_height = height.EuclideanNorm();
598
599 Update();
600}
601
602
604{
605 m_shapes.clear();
606
607 VECTOR2I dimension( m_end - m_start );
608
609 m_measuredValue = KiROUND( dimension.EuclideanNorm() );
610
611 VECTOR2I extension;
612
613 if( m_height > 0 )
614 extension = VECTOR2I( -dimension.y, dimension.x );
615 else
616 extension = VECTOR2I( dimension.y, -dimension.x );
617
618 // Add extension lines
619 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
620
621 VECTOR2I extStart( m_start );
622 extStart += extension.Resize( m_extensionOffset );
623
624 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
625
626 extStart = VECTOR2I( m_end );
627 extStart += extension.Resize( m_extensionOffset );
628
629 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
630
631 // Add crossbar
632 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
633 m_crossBarStart = m_start + crossBarDistance;
634 m_crossBarEnd = m_end + crossBarDistance;
635
636 // Update text after calculating crossbar position but before adding crossbar lines
637 updateText();
638
639 // Now that we have the text updated, we can determine how to draw the crossbar.
640 // First we need to create an appropriate bounding polygon to collide with
642
643 SHAPE_POLY_SET polyBox;
644 polyBox.NewOutline();
645 polyBox.Append( textBox.GetOrigin() );
646 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
647 polyBox.Append( textBox.GetEnd() );
648 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
649 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
650
651 // The ideal crossbar, if the text doesn't collide
652 SEG crossbar( m_crossBarStart, m_crossBarEnd );
653
654 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
655 bool containsA = polyBox.Contains( crossbar.A );
656 bool containsB = polyBox.Contains( crossbar.B );
657
658 OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
659 OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
660
661 if( endpointA )
662 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
663
664 if( endpointB )
665 m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
666
667 if( !containsA && !containsB && !endpointA && !endpointB )
668 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
669
670 // Add arrows
671 VECTOR2I arrowEndPos( m_arrowLength, 0 );
672 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
673 RotatePoint( arrowEndPos, -EDA_ANGLE( dimension ) + s_arrowAngle );
674 RotatePoint( arrowEndNeg, -EDA_ANGLE( dimension ) - s_arrowAngle );
675
676 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndPos ) );
677 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndNeg ) );
678 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndPos ) );
679 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) );
680}
681
682
684{
685 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
686
688 {
689 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
690 EDA_ANGLE rotation;
691
692 if( crossbarCenter.x == 0 )
693 rotation = ANGLE_90 * sign( -crossbarCenter.y );
694 else if( crossbarCenter.x < 0 )
695 rotation = -ANGLE_90;
696 else
697 rotation = ANGLE_90;
698
699 VECTOR2I textOffset = crossbarCenter;
700 RotatePoint( textOffset, rotation );
701 textOffset = crossbarCenter + textOffset.Resize( textOffsetDistance );
702
703 SetTextPos( m_crossBarStart + textOffset );
704 }
706 {
707 SetTextPos( m_crossBarStart + crossbarCenter );
708 }
709
711 {
712 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( crossbarCenter );
713 textAngle.Normalize();
714
715 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
716 textAngle -= ANGLE_180;
717
718 SetTextAngle( textAngle );
719 }
720
722}
723
724
725void PCB_DIM_ALIGNED::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
726{
728
729 // Use our own UNITS_PROVIDER to report dimension info in dimension's units rather than
730 // in frame's units.
732 unitsProvider.SetUserUnits( GetUnits() );
733
734 aList.emplace_back( _( "Height" ), unitsProvider.MessageTextFromValue( m_height ) );
735}
736
737
740{
741 // To preserve look of old dimensions, initialize extension height based on default arrow length
742 m_extensionHeight = static_cast<int>( m_arrowLength * s_arrowAngle.Sin() );
744}
745
746
748{
749 return new PCB_DIM_ORTHOGONAL( *this );
750}
751
752
754{
755 wxASSERT( aImage->Type() == Type() );
756
757 m_shapes.clear();
758 static_cast<PCB_DIM_ORTHOGONAL*>( aImage )->m_shapes.clear();
759
760 std::swap( *static_cast<PCB_DIM_ORTHOGONAL*>( this ),
761 *static_cast<PCB_DIM_ORTHOGONAL*>( aImage ) );
762
763 Update();
764}
765
766
768{
770}
771
772
774{
775 m_shapes.clear();
776
778 m_end.y - m_start.y );
780
781 VECTOR2I extension;
782
784 extension = VECTOR2I( 0, m_height );
785 else
786 extension = VECTOR2I( m_height, 0 );
787
788 // Add first extension line
789 int extensionHeight = std::abs( m_height ) - m_extensionOffset + m_extensionHeight;
790
791 VECTOR2I extStart( m_start );
792 extStart += extension.Resize( m_extensionOffset );
793
794 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
795
796 // Add crossbar
797 VECTOR2I crossBarDistance = sign( m_height ) * extension.Resize( m_height );
798 m_crossBarStart = m_start + crossBarDistance;
799
802 else
804
805 // Add second extension line (m_end to crossbar end)
807 extension = VECTOR2I( 0, m_end.y - m_crossBarEnd.y );
808 else
809 extension = VECTOR2I( m_end.x - m_crossBarEnd.x, 0 );
810
811 extensionHeight = extension.EuclideanNorm() - m_extensionOffset + m_extensionHeight;
812
813 extStart = VECTOR2I( m_crossBarEnd );
814 extStart -= extension.Resize( m_extensionHeight );
815
816 addShape( SHAPE_SEGMENT( extStart, extStart + extension.Resize( extensionHeight ) ) );
817
818 // Update text after calculating crossbar position but before adding crossbar lines
819 updateText();
820
821 // Now that we have the text updated, we can determine how to draw the crossbar.
822 // First we need to create an appropriate bounding polygon to collide with
824
825 SHAPE_POLY_SET polyBox;
826 polyBox.NewOutline();
827 polyBox.Append( textBox.GetOrigin() );
828 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
829 polyBox.Append( textBox.GetEnd() );
830 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
831 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
832
833 // The ideal crossbar, if the text doesn't collide
834 SEG crossbar( m_crossBarStart, m_crossBarEnd );
835
836 // Now we can draw 0, 1, or 2 crossbar lines depending on how the polygon collides
837 bool containsA = polyBox.Contains( crossbar.A );
838 bool containsB = polyBox.Contains( crossbar.B );
839
840 OPT_VECTOR2I endpointA = segPolyIntersection( polyBox, crossbar );
841 OPT_VECTOR2I endpointB = segPolyIntersection( polyBox, crossbar, false );
842
843 if( endpointA )
844 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar.A, *endpointA ) );
845
846 if( endpointB )
847 m_shapes.emplace_back( new SHAPE_SEGMENT( *endpointB, crossbar.B ) );
848
849 if( !containsA && !containsB && !endpointA && !endpointB )
850 m_shapes.emplace_back( new SHAPE_SEGMENT( crossbar ) );
851
852 // Add arrows
853 EDA_ANGLE crossBarAngle( m_crossBarEnd - m_crossBarStart );
854 VECTOR2I arrowEndPos( m_arrowLength, 0 );
855 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
856 RotatePoint( arrowEndPos, -crossBarAngle + s_arrowAngle );
857 RotatePoint( arrowEndNeg, -crossBarAngle - s_arrowAngle );
858
859 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndPos ) );
860 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarStart, m_crossBarStart + arrowEndNeg ) );
861 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndPos ) );
862 m_shapes.emplace_back( new SHAPE_SEGMENT( m_crossBarEnd, m_crossBarEnd - arrowEndNeg ) );
863}
864
865
867{
868 VECTOR2I crossbarCenter( ( m_crossBarEnd - m_crossBarStart ) / 2 );
869
871 {
872 int textOffsetDistance = GetEffectiveTextPenWidth() + GetTextHeight();
873
874 VECTOR2I textOffset;
875
877 textOffset.y = -textOffsetDistance;
878 else
879 textOffset.x = -textOffsetDistance;
880
881 textOffset += crossbarCenter;
882
883 SetTextPos( m_crossBarStart + textOffset );
884 }
886 {
887 SetTextPos( m_crossBarStart + crossbarCenter );
888 }
889
891 {
892 if( abs( crossbarCenter.x ) > abs( crossbarCenter.y ) )
894 else
896 }
897
899}
900
901
902void PCB_DIM_ORTHOGONAL::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
903{
904 EDA_ANGLE angle( aAngle );
905
906 // restrict angle to -179.9 to 180.0 degrees
907 angle.Normalize180();
908
909 // adjust orientation and height to new angle
910 // we can only handle the cases of -90, 0, 90, 180 degrees exactly;
911 // in the other cases we will use the nearest 90 degree angle to
912 // choose at least an approximate axis for the target orientation
913 // In case of exactly 45 or 135 degrees, we will round towards zero for consistency
914 if( angle > ANGLE_45 && angle <= ANGLE_135 )
915 {
916 // about 90 degree
918 {
920 }
921 else
922 {
925 }
926 }
927 else if( angle < -ANGLE_45 && angle >= -ANGLE_135 )
928 {
929 // about -90 degree
931 {
934 }
935 else
936 {
938 }
939 }
940 else if( angle > ANGLE_135 || angle < -ANGLE_135 )
941 {
942 // about 180 degree
944 }
945
946 // this will update m_crossBarStart and m_crossbarEnd
947 PCB_DIMENSION_BASE::Rotate( aRotCentre, angle );
948}
949
950
953 m_textBorder( DIM_TEXT_BORDER::NONE )
954{
957 m_keepTextAligned = false;
958
959 SetOverrideText( _( "Leader" ) );
960}
961
962
964{
965 return new PCB_DIM_LEADER( *this );
966}
967
968
970{
971 wxASSERT( aImage->Type() == Type() );
972
973 m_shapes.clear();
974 static_cast<PCB_DIM_LEADER*>( aImage )->m_shapes.clear();
975
976 std::swap( *static_cast<PCB_DIM_LEADER*>( this ), *static_cast<PCB_DIM_LEADER*>( aImage ) );
977
978 Update();
979}
980
981
983{
984 return BITMAPS::add_leader;
985}
986
987
989{
990 // Our geometry is dependent on the size of the text, so just update the whole shebang
992}
993
994
996{
997 m_shapes.clear();
998
1000
1001 // Now that we have the text updated, we can determine how to draw the second line
1002 // First we need to create an appropriate bounding polygon to collide with
1003 BOX2I textBox = GetTextBox().Inflate( GetTextWidth() / 2, GetEffectiveTextPenWidth() * 2 );
1004
1005 SHAPE_POLY_SET polyBox;
1006 polyBox.NewOutline();
1007 polyBox.Append( textBox.GetOrigin() );
1008 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1009 polyBox.Append( textBox.GetEnd() );
1010 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1011 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1012
1013 VECTOR2I firstLine( m_end - m_start );
1014 VECTOR2I start( m_start );
1015 start += firstLine.Resize( m_extensionOffset );
1016
1017 SEG arrowSeg( m_start, m_end );
1018 SEG textSeg( m_end, GetTextPos() );
1019 OPT_VECTOR2I arrowSegEnd;
1020 OPT_VECTOR2I textSegEnd;
1021
1023 {
1024 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1025 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1026 CIRCLE circle( textBox.GetCenter(), radius );
1027
1028 arrowSegEnd = segCircleIntersection( circle, arrowSeg );
1029 textSegEnd = segCircleIntersection( circle, textSeg );
1030 }
1031 else
1032 {
1033 arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1034 textSegEnd = segPolyIntersection( polyBox, textSeg );
1035 }
1036
1037 if( !arrowSegEnd )
1038 arrowSegEnd = m_end;
1039
1040 m_shapes.emplace_back( new SHAPE_SEGMENT( start, *arrowSegEnd ) );
1041
1042 // Add arrows
1043 VECTOR2I arrowEndPos( m_arrowLength, 0 );
1044 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
1045 RotatePoint( arrowEndPos, -EDA_ANGLE( firstLine ) + s_arrowAngle );
1046 RotatePoint( arrowEndNeg, -EDA_ANGLE( firstLine ) - s_arrowAngle );
1047
1048 m_shapes.emplace_back( new SHAPE_SEGMENT( start, start + arrowEndPos ) );
1049 m_shapes.emplace_back( new SHAPE_SEGMENT( start, start + arrowEndNeg ) );
1050
1051
1052 if( !GetText().IsEmpty() )
1053 {
1054 switch( m_textBorder )
1055 {
1057 {
1058 for( SHAPE_POLY_SET::SEGMENT_ITERATOR seg = polyBox.IterateSegments(); seg; seg++ )
1059 m_shapes.emplace_back( new SHAPE_SEGMENT( *seg ) );
1060
1061 break;
1062 }
1063
1065 {
1066 double penWidth = GetEffectiveTextPenWidth() / 2.0;
1067 double radius = ( textBox.GetWidth() / 2.0 ) - penWidth;
1068 m_shapes.emplace_back( new SHAPE_CIRCLE( textBox.GetCenter(), radius ) );
1069
1070 break;
1071 }
1072
1073 default:
1074 break;
1075 }
1076 }
1077
1078 if( textSegEnd && *arrowSegEnd == m_end )
1079 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, *textSegEnd ) );
1080}
1081
1082
1083void PCB_DIM_LEADER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1084{
1085 aList.emplace_back( _( "Leader" ), GetShownText() );
1086
1087 ORIGIN_TRANSFORMS originTransforms = aFrame->GetOriginTransforms();
1088
1089 VECTOR2I startCoord = originTransforms.ToDisplayAbs( GetStart() );
1090 wxString start = wxString::Format( wxT( "@(%s, %s)" ),
1091 aFrame->MessageTextFromValue( startCoord.x ),
1092 aFrame->MessageTextFromValue( startCoord.y ) );
1093
1094 aList.emplace_back( start, wxEmptyString );
1095
1096 aList.emplace_back( _( "Layer" ), GetLayerName() );
1097}
1098
1099
1102{
1104 m_overrideTextEnabled = false;
1105 m_keepTextAligned = true;
1106 m_isDiameter = false;
1107 m_prefix = "R ";
1109}
1110
1111
1113{
1114 return new PCB_DIM_RADIAL( *this );
1115}
1116
1117
1119{
1120 wxASSERT( aImage->Type() == Type() );
1121
1122 m_shapes.clear();
1123 static_cast<PCB_DIM_RADIAL*>( aImage )->m_shapes.clear();
1124
1125 std::swap( *static_cast<PCB_DIM_RADIAL*>( this ), *static_cast<PCB_DIM_RADIAL*>( aImage ) );
1126
1127 Update();
1128}
1129
1130
1132{
1134}
1135
1136
1138{
1139 VECTOR2I radial( m_end - m_start );
1140
1141 return m_end + radial.Resize( m_leaderLength );
1142}
1143
1144
1146{
1147 if( m_keepTextAligned )
1148 {
1149 VECTOR2I textLine( GetTextPos() - GetKnee() );
1150 EDA_ANGLE textAngle = FULL_CIRCLE - EDA_ANGLE( textLine );
1151
1152 textAngle.Normalize();
1153
1154 if( textAngle > ANGLE_90 && textAngle <= ANGLE_270 )
1155 textAngle -= ANGLE_180;
1156
1157 // Round to nearest degree
1158 textAngle = EDA_ANGLE( KiROUND( textAngle.AsDegrees() ), DEGREES_T );
1159
1160 SetTextAngle( textAngle );
1161 }
1162
1164}
1165
1166
1168{
1169 m_shapes.clear();
1170
1171 VECTOR2I center( m_start );
1172 VECTOR2I centerArm( 0, m_arrowLength );
1173
1174 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1175
1176 RotatePoint( centerArm, -ANGLE_90 );
1177
1178 m_shapes.emplace_back( new SHAPE_SEGMENT( center - centerArm, center + centerArm ) );
1179
1180 VECTOR2I radius( m_end - m_start );
1181
1182 if( m_isDiameter )
1183 m_measuredValue = KiROUND( radius.EuclideanNorm() * 2 );
1184 else
1186
1187 updateText();
1188
1189 // Now that we have the text updated, we can determine how to draw the second line
1190 // First we need to create an appropriate bounding polygon to collide with
1192
1193 SHAPE_POLY_SET polyBox;
1194 polyBox.NewOutline();
1195 polyBox.Append( textBox.GetOrigin() );
1196 polyBox.Append( textBox.GetOrigin().x, textBox.GetEnd().y );
1197 polyBox.Append( textBox.GetEnd() );
1198 polyBox.Append( textBox.GetEnd().x, textBox.GetOrigin().y );
1199 polyBox.Rotate( GetTextAngle(), textBox.GetCenter() );
1200
1201 VECTOR2I radial( m_end - m_start );
1202 radial = radial.Resize( m_leaderLength );
1203
1204 SEG arrowSeg( m_end, m_end + radial );
1205 SEG textSeg( arrowSeg.B, GetTextPos() );
1206
1207 OPT_VECTOR2I arrowSegEnd = segPolyIntersection( polyBox, arrowSeg );
1208 OPT_VECTOR2I textSegEnd = segPolyIntersection( polyBox, textSeg );
1209
1210 if( arrowSegEnd )
1211 arrowSeg.B = *arrowSegEnd;
1212
1213 if( textSegEnd )
1214 textSeg.B = *textSegEnd;
1215
1216 m_shapes.emplace_back( new SHAPE_SEGMENT( arrowSeg ) );
1217
1218 // Add arrows
1219 VECTOR2I arrowEndPos( m_arrowLength, 0 );
1220 VECTOR2I arrowEndNeg( m_arrowLength, 0 );
1221 RotatePoint( arrowEndPos, -EDA_ANGLE( radial ) + s_arrowAngle );
1222 RotatePoint( arrowEndNeg, -EDA_ANGLE( radial ) - s_arrowAngle );
1223
1224 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndPos ) );
1225 m_shapes.emplace_back( new SHAPE_SEGMENT( m_end, m_end + arrowEndNeg ) );
1226
1227 m_shapes.emplace_back( new SHAPE_SEGMENT( textSeg ) );
1228}
1229
1230
1233{
1235 m_overrideTextEnabled = true;
1236}
1237
1238
1240{
1241 return new PCB_DIM_CENTER( *this );
1242}
1243
1244
1246{
1247 wxASSERT( aImage->Type() == Type() );
1248
1249 std::swap( *static_cast<PCB_DIM_CENTER*>( this ), *static_cast<PCB_DIM_CENTER*>( aImage ) );
1250}
1251
1252
1254{
1256}
1257
1258
1260{
1261 int halfWidth = VECTOR2I( m_end - m_start ).x + ( m_lineThickness / 2.0 );
1262
1263 BOX2I bBox;
1264
1265 bBox.SetX( m_start.x - halfWidth );
1266 bBox.SetY( m_start.y - halfWidth );
1267 bBox.SetWidth( halfWidth * 2 );
1268 bBox.SetHeight( halfWidth * 2 );
1269
1270 bBox.Normalize();
1271
1272 return bBox;
1273}
1274
1275
1277{
1279 VECTOR2I( GetBoundingBox().GetSize() ) );
1280}
1281
1282
1284{
1285 m_shapes.clear();
1286
1287 VECTOR2I center( m_start );
1288 VECTOR2I arm( m_end - m_start );
1289
1290 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1291
1292 RotatePoint( arm, -ANGLE_90 );
1293
1294 m_shapes.emplace_back( new SHAPE_SEGMENT( center - arm, center + arm ) );
1295}
1296
1297
1298static struct DIMENSION_DESC
1299{
1301 {
1303 .Map( DIM_PRECISION::X, _HKI( "0" ) )
1304 .Map( DIM_PRECISION::X_X, _HKI( "0.0" ) )
1305 .Map( DIM_PRECISION::X_XX, _HKI( "0.00" ) )
1306 .Map( DIM_PRECISION::X_XXX, _HKI( "0.000" ) )
1307 .Map( DIM_PRECISION::X_XXXX, _HKI( "0.0000" ) )
1308 .Map( DIM_PRECISION::X_XXXXX, _HKI( "0.00000" ) )
1309 .Map( DIM_PRECISION::V_VV, _HKI( "0.00 in / 0 mils / 0.0 mm" ) )
1310 .Map( DIM_PRECISION::V_VVV, _HKI( "0.000 / 0 / 0.00" ) )
1311 .Map( DIM_PRECISION::V_VVVV, _HKI( "0.0000 / 0.0 / 0.000" ) )
1312 .Map( DIM_PRECISION::V_VVVVV, _HKI( "0.00000 / 0.00 / 0.0000" ) );
1313
1315 .Map( DIM_UNITS_FORMAT::NO_SUFFIX, _HKI( "1234.0" ) )
1316 .Map( DIM_UNITS_FORMAT::BARE_SUFFIX, _HKI( "1234.0 mm" ) )
1317 .Map( DIM_UNITS_FORMAT::PAREN_SUFFIX, _HKI( "1234.0 (mm)" ) );
1318
1320 .Map( DIM_UNITS_MODE::INCHES, _HKI( "Inches" ) )
1321 .Map( DIM_UNITS_MODE::MILS, _HKI( "Mils" ) )
1322 .Map( DIM_UNITS_MODE::MILLIMETRES, _HKI( "Millimeters" ) )
1323 .Map( DIM_UNITS_MODE::AUTOMATIC, _HKI( "Automatic" ) );
1324
1333
1334 const wxString groupDimension = _HKI( "Dimension Properties" );
1335
1338 groupDimension );
1341 groupDimension );
1342 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, wxString>( _HKI( "Override Text" ),
1344 groupDimension );
1345
1348 groupDimension );
1351 groupDimension );
1354 groupDimension );
1355 propMgr.AddProperty( new PROPERTY<PCB_DIMENSION_BASE, bool>( _HKI( "Suppress Trailing Zeroes" ),
1357 groupDimension );
1358 }
1360
1364
1365
1367{
1369 {
1380
1381 const wxString groupDimension = _HKI( "Dimension Properties" );
1382
1383 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Crossbar Height" ),
1386 groupDimension );
1387 propMgr.AddProperty( new PROPERTY<PCB_DIM_ALIGNED, int>( _HKI( "Extension Line Overshoot" ),
1390 groupDimension );
1391
1393 _HKI( "Visible" ),
1394 []( INSPECTABLE* aItem ) { return false; } );
1396 _HKI( "Knockout" ),
1397 []( INSPECTABLE* aItem ) { return false; } );
1399 _HKI( "Hyperlink" ),
1400 []( INSPECTABLE* aItem ) { return false; } );
1401 }
1403
1404
1406{
1408 {
1421
1423 _HKI( "Visible" ),
1424 []( INSPECTABLE* aItem ) { return false; } );
1426 _HKI( "Knockout" ),
1427 []( INSPECTABLE* aItem ) { return false; } );
1429 _HKI( "Hyperlink" ),
1430 []( INSPECTABLE* aItem ) { return false; } );
1431 }
1433
1434
1436{
1438 {
1449
1450 const wxString groupDimension = _HKI( "Dimension Properties" );
1451
1452 propMgr.AddProperty( new PROPERTY<PCB_DIM_RADIAL, int>( _HKI( "Leader Length" ),
1455 groupDimension );
1456
1458 _HKI( "Visible" ),
1459 []( INSPECTABLE* aItem ) { return false; } );
1461 _HKI( "Knockout" ),
1462 []( INSPECTABLE* aItem ) { return false; } );
1464 _HKI( "Hyperlink" ),
1465 []( INSPECTABLE* aItem ) { return false; } );
1466 }
1468
1469
1471{
1473 {
1475 .Map( DIM_TEXT_BORDER::NONE, _HKI( "None" ) )
1476 .Map( DIM_TEXT_BORDER::RECTANGLE, _HKI( "Rectangle" ) )
1477 .Map( DIM_TEXT_BORDER::CIRCLE, _HKI( "Circle" ) );
1478
1489
1490 const wxString groupDimension = _HKI( "Dimension Properties" );
1491
1494 groupDimension );
1495
1497 _HKI( "Visible" ),
1498 []( INSPECTABLE* aItem ) { return false; } );
1500 _HKI( "Knockout" ),
1501 []( INSPECTABLE* aItem ) { return false; } );
1503 _HKI( "Hyperlink" ),
1504 []( INSPECTABLE* aItem ) { return false; } );
1505 }
1507
1509
1510
1512{
1514 {
1525
1526
1528 _HKI( "Visible" ),
1529 []( INSPECTABLE* aItem ) { return false; } );
1531 _HKI( "Knockout" ),
1532 []( INSPECTABLE* aItem ) { return false; } );
1534 _HKI( "Hyperlink" ),
1535 []( INSPECTABLE* aItem ) { return false; } );
1536 }
1538
1539
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
@ add_radial_dimension
@ add_aligned_dimension
@ add_center_dimension
@ add_orthogonal_dimension
BOX2< VECTOR2I > BOX2I
Definition: box2.h:847
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:192
PCB_LAYER_ID m_layer
Definition: board_item.h:341
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:226
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:43
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:197
virtual bool IsLocked() const
Definition: board_item.cpp:71
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:94
EDA_UNITS GetUserUnits()
Definition: board.h:644
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:119
const Vec & GetOrigin() const
Definition: box2.h:183
void SetX(coord_type val)
Definition: box2.h:235
const Vec GetCenter() const
Definition: box2.h:195
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
void SetY(coord_type val)
Definition: box2.h:240
coord_type GetY() const
Definition: box2.h:181
coord_type GetWidth() const
Definition: box2.h:187
void SetWidth(coord_type val)
Definition: box2.h:245
const Vec GetEnd() const
Definition: box2.h:185
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
coord_type GetX() const
Definition: box2.h:180
coord_type GetRight() const
Definition: box2.h:189
void SetHeight(coord_type val)
Definition: box2.h:250
coord_type GetBottom() const
Definition: box2.h:190
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:588
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:209
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:249
double Sin() const
Definition: eda_angle.h:206
double AsDegrees() const
Definition: eda_angle.h:149
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:85
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
virtual const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
Definition: eda_item.cpp:254
EDA_ITEM * m_parent
Linked list: Link (parent struct)
Definition: eda_item.h:496
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:72
int GetTextHeight() const
Definition: eda_text.h:202
BOX2I GetTextBox(int aLine=-1, bool aInvertY=false) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition: eda_text.cpp:505
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:208
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:120
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:373
KIFONT::FONT * GetFont() const
Definition: eda_text.h:188
void SetMirrored(bool isMirrored)
Definition: eda_text.cpp:226
int GetTextWidth() const
Definition: eda_text.h:199
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:391
virtual void ClearRenderCache()
Definition: eda_text.cpp:440
bool IsMirrored() const
Definition: eda_text.h:139
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition: eda_text.cpp:299
std::shared_ptr< SHAPE_COMPOUND > GetEffectiveTextShape(bool aTriangulate=true, bool aUseTextRotation=true) const
build a list of segments (SHAPE_SEGMENT) to describe a text shape.
Definition: eda_text.cpp:855
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:165
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:195
int GetTextThickness() const
Definition: eda_text.h:112
static ENUM_MAP< T > & Instance()
Definition: property.h:623
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:36
static LSET SideSpecificMask()
Definition: lset.cpp:908
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 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
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 Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
void ClearRenderCache() override
int m_lineThickness
Thickness used for all graphics in the dimension.
void Move(const VECTOR2I &offset) override
Move this object.
bool m_suppressZeroes
Suppress trailing zeroes.
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.
static OPT_VECTOR2I segCircleIntersection(CIRCLE &aCircle, SEG &aSeg, bool aStart=true)
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)
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.
bool m_keepTextAligned
Calculate text orientation to match dimension.
DIM_PRECISION GetPrecision() const
wxString GetPrefix() const
void SetSuffix(const wxString &aSuffix)
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
DIM_UNITS_MODE GetUnitsMode() const
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
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
wxString m_valueString
Displayed value when m_overrideValue = true.
void ChangePrecision(DIM_PRECISION aPrecision)
bool m_overrideTextEnabled
Manually specify the displayed measurement value.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
DIM_UNITS_FORMAT m_unitsFormat
How to render the units suffix.
int GetMeasuredValue() const
bool GetSuppressZeroes() const
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.
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.
void SetOverrideText(const wxString &aValue)
wxString GetValueText() const
void ChangePrefix(const wxString &aPrefix)
wxString m_prefix
String prepended to the value.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
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.
virtual void Mirror(const VECTOR2I &axis_pos, bool aMirrorLeftRight=false)
Mirror the dimension relative to a given horizontal axis.
bool GetOverrideTextEnabled() const
void SetUnitsMode(DIM_UNITS_MODE aMode)
int m_arrowLength
Length of arrow shapes.
virtual const VECTOR2I & GetEnd() const
VECTOR2I m_end
Internal cache of drawn shapes.
void ChangeUnitsMode(DIM_UNITS_MODE aMode)
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.
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).
VECTOR2I m_crossBarStart
Crossbar start control point.
void UpdateHeight(const VECTOR2I &aCrossbarStart, const VECTOR2I &aCrossbarEnd)
Update the stored height basing on points coordinates.
virtual void swapData(BOARD_ITEM *aImage) override
PCB_DIM_ALIGNED(BOARD_ITEM *aParent, KICAD_T aType)
int m_extensionHeight
Length of extension lines past the crossbar.
VECTOR2I m_crossBarEnd
Crossbar end control point.
void Mirror(const VECTOR2I &axis_pos, bool aMirrorLeftRight=false) override
Mirror the dimension relative to a given horizontal axis.
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.
PCB_DIM_CENTER(BOARD_ITEM *aParent, bool aInFP=false)
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.
virtual void swapData(BOARD_ITEM *aImage) override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
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
PCB_DIM_LEADER(BOARD_ITEM *aParent, bool aInFP=false)
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).
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
void ChangeTextBorder(DIM_TEXT_BORDER aBorder)
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
PCB_DIM_ORTHOGONAL(BOARD_ITEM *aParent, bool aInFP=false)
void swapData(BOARD_ITEM *aImage) override
void updateText() override
Update the text field value from the current geometry (called by updateGeometry normally).
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.
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 Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
A radial dimension indicates either the radius or diameter of an arc or circle.
int GetLeaderLength() const
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 updateGeometry() override
Update the cached geometry of the dimension after changing any of its properties.
void ChangeLeaderLength(int aLength)
PCB_DIM_RADIAL(BOARD_ITEM *aParent, bool aInFP=false)
VECTOR2I GetKnee() const
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const override
Return the string actually shown after processing of the base text.
Definition: pcb_text.cpp:55
bool TextHitTest(const VECTOR2I &aPoint, int aAccuracy=0) const override
Test if aPoint is within the bounds of this object.
Definition: pcb_text.cpp:154
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: pcb_text.cpp:251
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.
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:108
const VECTOR2I GetCenter() const
Definition: shape_circle.h:113
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)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
int NewOutline()
Creates a new hole in a given outline.
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 aPolygonIdx-th polygon edges.
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)
A lower-precision version of StringFromValue().
void SetUserUnits(EDA_UNITS aUnits)
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:265
extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition: vector2d.h:459
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:350
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_180
Definition: eda_angle.h:433
static constexpr EDA_ANGLE & ANGLE_HORIZONTAL
Definition: eda_angle.h:425
@ DEGREES_T
Definition: eda_angle.h:31
static constexpr EDA_ANGLE & ANGLE_VERTICAL
Definition: eda_angle.h:426
static constexpr EDA_ANGLE & ANGLE_45
Definition: eda_angle.h:430
static constexpr EDA_ANGLE & FULL_CIRCLE
Definition: eda_angle.h:427
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:431
static constexpr EDA_ANGLE & ANGLE_270
Definition: eda_angle.h:434
static constexpr EDA_ANGLE & ANGLE_135
Definition: eda_angle.h:432
#define PCB_EDIT_FRAME_NAME
EDA_UNITS
Definition: eda_units.h:43
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ NONE
Definition: kibis.h:53
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:59
@ Dwgs_User
Definition: layer_ids.h:109
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:544
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:190
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:101
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:128
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:418
static struct LEADER_DIMENSION_DESC LEADER_DIMENSION_DESC
static struct ORTHOGONAL_DIMENSION_DESC ORTHOGONAL_DIMENSION_DESC
static const EDA_ANGLE s_arrowAngle(27.5, DEGREES_T)
static struct CENTER_DIMENSION_DESC CENTER_DIMENSION_DESC
static struct DIMENSION_DESC _DIMENSION_DESC
static struct RADIAL_DIMENSION_DESC RADIAL_DIMENSION_DESC
#define INVERT(pos)
static struct ALIGNED_DIMENSION_DESC ALIGNED_DIMENSION_DESC
DIM_TEXT_POSITION
Where to place the text on a dimension.
Definition: pcb_dimension.h:62
@ OUTSIDE
Text appears outside the dimension line (default)
@ INLINE
Text appears in line with the dimension line.
DIM_UNITS_FORMAT
How to display the units in a dimension's text.
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_TEXT_BORDER
Frame to show around dimension text.
Definition: pcb_dimension.h:83
DIM_PRECISION
Definition: pcb_dimension.h:47
#define TYPE_HASH(x)
Definition: property.h:63
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:725
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition: property.h:56
#define REGISTER_TYPE(x)
Definition: property_mgr.h:328
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
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:110
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:107
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:108
@ PCB_FP_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:97
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:109
int sign(T val)
Definition: util.h:124
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590