KiCad PCB EDA Suite
Loading...
Searching...
No Matches
constraint_overlay.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <algorithm>
23#include <cmath>
24#include <limits>
25#include <ranges>
26#include <set>
27
28#include <wx/image.h>
29
30#include <board.h>
31#include <footprint.h>
32#include <pcb_dimension.h>
33#include <pcb_shape.h>
34#include <view/view.h>
35#include <view/view_overlay.h>
36#include <gal/color4d.h>
38#include <gal/painter.h>
39#include <render_settings.h>
40#include <base_units.h>
41#include <bitmap_base.h>
42#include <bitmaps.h>
43#include <math/util.h>
44#include <geometry/eda_angle.h>
47#include <tool/edit_points.h>
48
52
53using KIGFX::COLOR4D;
54
55
57 VIEW_OVERLAY_HOLDER( aView ),
58 m_board( aBoard ),
61{
62 m_view->Add( &m_badgeItem );
63}
64
65
67{
68 // Remove the badge item before the base removes the tint overlay. Each is removed exactly once.
69 m_view->Remove( &m_badgeItem );
70}
71
72
74{
75 if( !m_overlay )
76 return;
77
79 m_previewAnchor.reset();
80
81 m_overlay->Clear();
82 m_view->Update( m_overlay.get() );
83
84 // Drop the badges from both the draw item and Badges(), so a hidden overlay is not still
85 // clickable through hitTestBadge.
86 m_badges.clear();
87 m_badgeItem.SetBadges( {}, niluuid );
88 m_view->Update( &m_badgeItem );
89 m_view->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
90}
91
92
94{
95 return 14.0; // In screen pixels. The caller converts to world units with the view scale.
96}
97
98
100{
101 // Up-right of the anchor, in screen pixels, so the glyph and its hit disc sit clear of the
102 // geometry and a click on the shape at the anchor still selects the shape.
103 return VECTOR2D( 16.0, -16.0 );
104}
105
106
107double CONSTRAINT_OVERLAY::BadgeWorldPerPixel( double aWorldScale )
108{
109 // Capped so a zoomed-out glyph shrinks instead of dominating the board. Shared by the drawing
110 // and the hit-test so the clickable disc always matches the visible glyph.
111 const double maxWorldPerPx = pcbIUScale.mmToIU( 3.0 ) / 16.0;
112
113 return aWorldScale > 0.0 ? std::min( 1.0 / aWorldScale, maxWorldPerPx ) : maxWorldPerPx;
114}
115
116
117std::vector<VECTOR2D> CONSTRAINT_OVERLAY::LayoutBadges( const std::vector<CONSTRAINT_BADGE>& aBadges,
118 double aWorldPerPx )
119{
120 // Screen pixels scaled to world, so placement holds its look at any zoom.
121 const double discPx = 11.0; // chip radius
122 const double marginPx = 3.0; // gap the chip keeps from geometry and other badges
123 const VECTOR2D preferred = BadgeScreenOffset();
124 const double baseMag = preferred.EuclideanNorm();
125 const double baseAngle = atan2( preferred.y, preferred.x );
126
127 const double shapeClear = ( discPx + marginPx ) * aWorldPerPx;
128 const double badgeClear = ( 2.0 * discPx + marginPx ) * aWorldPerPx;
129
130 // Fan the direction out from the default, then push farther if every direction is blocked.
131 static const double dirSpread[] = { 0, 30, -30, 60, -60, 90, -90, 120, -120, 150, -150, 180 };
132 static const double magSteps[] = { 1.0, 1.6, 2.3 };
133
134 std::vector<VECTOR2D> positions;
135 positions.reserve( aBadges.size() );
136
137 for( const CONSTRAINT_BADGE& badge : aBadges )
138 {
139 VECTOR2D anchor( badge.pos );
140
141 // Clearance to the nearest obstacle.
142 auto clearance = [&]( const VECTOR2D& aPos ) -> double
143 {
144 double d = std::numeric_limits<double>::max();
145 VECTOR2I p( KiROUND( aPos.x ), KiROUND( aPos.y ) );
146
147 for( const SEG& seg : badge.avoid )
148 d = std::min( d, seg.Distance( p ) - shapeClear );
149
150 for( const VECTOR2D& placed : positions )
151 d = std::min( d, ( placed - aPos ).EuclideanNorm() - badgeClear );
152
153 return d;
154 };
155
156 VECTOR2D best = anchor + preferred * aWorldPerPx;
157 double bestScore = -std::numeric_limits<double>::max();
158 bool placed = false;
159
160 for( double mag : magSteps )
161 {
162 for( double spread : dirSpread )
163 {
164 double a = baseAngle + spread * M_PI / 180.0;
165 VECTOR2D cand = anchor + VECTOR2D( cos( a ), sin( a ) ) * ( baseMag * mag * aWorldPerPx );
166 double score = clearance( cand );
167
168 if( score >= 0.0 )
169 {
170 best = cand;
171 placed = true;
172 break;
173 }
174
175 if( score > bestScore )
176 {
177 bestScore = score;
178 best = cand;
179 }
180 }
181
182 if( placed )
183 break;
184 }
185
186 positions.push_back( best );
187 }
188
189 return positions;
190}
191
192
193bool CONSTRAINT_OVERLAY::SetSelected( const KIID& aConstraint )
194{
195 if( m_selected == aConstraint )
196 return false;
197
198 m_selected = aConstraint;
199 return true;
200}
201
202
203bool CONSTRAINT_OVERLAY::SetIsolated( const KIID& aConstraint )
204{
205 if( m_isolated == aConstraint )
206 return false;
207
208 m_isolated = aConstraint;
209 return true;
210}
211
212
214{
215 if( m_mode == aMode )
216 return false;
217
218 m_mode = aMode;
219 return true;
220}
221
222
224{
225 if( m_hoverShape == aShape )
226 return false;
227
228 m_hoverShape = aShape;
229 return true;
230}
231
232
233bool CONSTRAINT_OVERLAY::SetPickPreview( const KIID& aElement, bool aWholeElement,
234 const std::optional<VECTOR2I>& aAnchor )
235{
236 if( m_previewElement == aElement && m_previewWhole == aWholeElement && m_previewAnchor == aAnchor )
237 return false;
238
239 m_previewElement = aElement;
240 m_previewWhole = aWholeElement;
241 m_previewAnchor = aAnchor;
242
243 render();
244 return true;
245}
246
247
249{
250 SetPickPreview( niluuid, true, std::nullopt );
251}
252
253
255{
256 if( !m_overlay || !m_board )
257 return;
258
259 m_lastDiag = aDiag;
260 render();
261}
262
263
265{
266 // Only the selected-badge highlight changed; redraw from the cached diagnosis without the
267 // expensive board-wide re-solve. render() no-ops when the overlay is not ready.
268 render();
269}
270
271
273{
274 if( !m_overlay || !m_board )
275 return;
276
277 m_overlay->Clear();
278 m_badges.clear();
279
280 // State tints are theme colors read from active color settings so they can be rethemed
281 // Literals are shipped defaults used as fallback when no painter attached such as headless tests
282 COLOR4D underColor( 0.80, 0.42, 0.02, 0.9 ); // amber, free DOF remain
283 COLOR4D wellColor( 0.18, 0.72, 0.30, 0.9 ); // green, fully constrained
284 COLOR4D overColor( 0.92, 0.18, 0.18, 0.9 ); // red, conflicting / errored
285
286 if( KIGFX::PAINTER* painter = m_view->GetPainter() )
287 {
288 if( KIGFX::RENDER_SETTINGS* settings = painter->GetSettings() )
289 {
290 underColor = settings->GetLayerColor( LAYER_CONSTRAINT_UNDER );
291 wellColor = settings->GetLayerColor( LAYER_CONSTRAINT_WELL );
292 overColor = settings->GetLayerColor( LAYER_CONSTRAINT_OVER );
293 }
294 }
295
296 const double lineWidth = pcbIUScale.mmToIU( 0.15 );
297
298 auto colorForState =
299 [&]( CONSTRAINT_STATE aState ) -> COLOR4D
300 {
301 switch( aState )
302 {
303 case CONSTRAINT_STATE::WELL_CONSTRAINED: return wellColor;
304 case CONSTRAINT_STATE::OVER_CONSTRAINED: return overColor;
306 default: return underColor;
307 }
308 };
309
310 auto setStroke =
311 [&]( const COLOR4D& aColor )
312 {
313 m_overlay->SetIsFill( false );
314 m_overlay->SetIsStroke( true );
315 m_overlay->SetStrokeColor( aColor );
316 m_overlay->SetLineWidth( lineWidth );
317 };
318
319 auto outlineShape =
320 [&]( const PCB_SHAPE* aShape, const COLOR4D& aColor )
321 {
322 setStroke( aColor );
323
324 if( aShape->GetShape() == SHAPE_T::CIRCLE )
325 {
326 m_overlay->Circle( aShape->GetCenter(), aShape->GetRadius() );
327 }
328 else if( aShape->GetShape() == SHAPE_T::SEGMENT )
329 {
330 m_overlay->Segment( aShape->GetStart(), aShape->GetEnd(), lineWidth );
331 }
332 else if( aShape->GetShape() == SHAPE_T::ARC )
333 {
334 EDA_ANGLE startAngle( aShape->GetStart() - aShape->GetCenter() );
335 m_overlay->Arc( aShape->GetCenter(), aShape->GetRadius(), startAngle,
336 startAngle + aShape->GetArcAngle() );
337 }
338 else if( aShape->GetShape() == SHAPE_T::ELLIPSE )
339 {
340 SHAPE_ELLIPSE ellipse( aShape->GetEllipseCenter(), aShape->GetEllipseMajorRadius(),
341 aShape->GetEllipseMinorRadius(), aShape->GetEllipseRotation() );
342 m_overlay->Polyline( ellipse.ConvertToPolyline( aShape->GetMaxError() ) );
343 }
344 else if( aShape->GetShape() == SHAPE_T::ELLIPSE_ARC )
345 {
346 SHAPE_ELLIPSE ellipse( aShape->GetEllipseCenter(), aShape->GetEllipseMajorRadius(),
347 aShape->GetEllipseMinorRadius(), aShape->GetEllipseRotation(),
348 aShape->GetEllipseStartAngle(), aShape->GetEllipseEndAngle() );
349 m_overlay->Polyline( ellipse.ConvertToPolyline( aShape->GetMaxError() ) );
350 }
351 else if( aShape->GetShape() == SHAPE_T::BEZIER )
352 {
353 // Stroke flattened curve fall back to chord if untessellated
354 const std::vector<VECTOR2I>& pts = aShape->GetBezierPoints();
355
356 if( pts.size() >= 2 )
357 m_overlay->Polyline( SHAPE_LINE_CHAIN( pts ) );
358 else
359 m_overlay->Segment( aShape->GetStart(), aShape->GetEnd(), lineWidth );
360 }
361 };
362
364
365 // Decide what is shown. A panel-row isolation wins; otherwise ALWAYS shows everything and HOVER
366 // shows only the hovered shape's constraints (or nothing when nothing is hovered).
367 bool showAll = false;
368 KIID focusConstraint = niluuid; // isolation: show only this constraint
369 KIID focusShape = niluuid; // hover: show only constraints referencing this shape
370
371 auto referencesShape = []( const PCB_CONSTRAINT* aConstraint, const KIID& aShape )
372 {
373 return std::ranges::any_of( aConstraint->GetMembers(),
374 [&]( const CONSTRAINT_MEMBER& m ) { return m.m_item == aShape; } );
375 };
376
377 if( m_isolated != niluuid )
378 {
379 if( dynamic_cast<PCB_CONSTRAINT*>( m_board->ResolveItem( m_isolated, true ) ) )
380 focusConstraint = m_isolated;
381 else
382 m_isolated = niluuid; // the isolated constraint is gone; fall through to the mode
383 }
384
385 if( m_isolated == niluuid )
386 {
388 showAll = true;
389 else if( m_hoverShape != niluuid )
390 focusShape = m_hoverShape;
391 // else HOVER with nothing hovered leaves showAll false so only always on badges show none focused
392 }
393
394 auto constraintShown =
395 [&]( PCB_CONSTRAINT* aConstraint ) -> bool
396 {
397 if( focusConstraint != niluuid )
398 return aConstraint->m_Uuid == focusConstraint;
399
400 if( showAll )
401 return true;
402
403 if( focusShape == niluuid )
404 return false;
405
406 return referencesShape( aConstraint, focusShape );
407 };
408
409 // Constrained shapes are marked by cached under shadow layer not an on top tint
410 // Overlay only draws badges and while authoring the pick preview
411 std::set<KIID> erroredIds( diag.errored.begin(), diag.errored.end() );
412 std::set<KIID> conflictingIds( diag.conflicting.begin(), diag.conflicting.end() );
413
414 auto badgePosition =
415 [&]( const CONSTRAINT_MEMBER& aFirst ) -> std::optional<VECTOR2I>
416 {
417 if( std::optional<VECTOR2I> pos = ConstraintAnchorPosition( m_board, aFirst ) )
418 return pos;
419
420 // A WHOLE member (segment/line/circle) has no single anchor; label its centre.
421 if( PCB_SHAPE* shape =
422 dynamic_cast<PCB_SHAPE*>( m_board->ResolveItem( aFirst.m_item, true ) ) )
423 {
424 return shape->GetBoundingBox().Centre();
425 }
426
427 return std::nullopt;
428 };
429
430 // A constrained shape as world segments, for the badge placement search.
431 auto appendShapeSegs = [&]( const PCB_SHAPE* aShape, std::vector<SEG>& aOut )
432 {
433 switch( aShape->GetShape() )
434 {
435 case SHAPE_T::SEGMENT: aOut.emplace_back( aShape->GetStart(), aShape->GetEnd() ); break;
436
437 case SHAPE_T::CIRCLE:
438 case SHAPE_T::ARC:
439 {
440 VECTOR2I center = aShape->GetCenter();
441 double radius = aShape->GetRadius();
442 EDA_ANGLE start = aShape->GetShape() == SHAPE_T::ARC ? EDA_ANGLE( aShape->GetStart() - center ) : ANGLE_0;
443 EDA_ANGLE sweep = aShape->GetShape() == SHAPE_T::ARC ? aShape->GetArcAngle() : ANGLE_360;
444 int steps = std::max( 2, KiROUND( std::abs( sweep.AsDegrees() ) / 30.0 ) );
445 VECTOR2I prev;
446
447 for( int i = 0; i <= steps; ++i )
448 {
449 EDA_ANGLE a = start + sweep * ( double( i ) / steps );
450 VECTOR2I p( center.x + KiROUND( radius * a.Cos() ), center.y + KiROUND( radius * a.Sin() ) );
451
452 if( i > 0 )
453 aOut.emplace_back( prev, p );
454
455 prev = p;
456 }
457
458 break;
459 }
460
461 case SHAPE_T::BEZIER:
462 {
463 const std::vector<VECTOR2I>& pts = aShape->GetBezierPoints();
464
465 for( size_t i = 1; i < pts.size(); ++i )
466 aOut.emplace_back( pts[i - 1], pts[i] );
467
468 break;
469 }
470
471 default: break;
472 }
473 };
474
475 // Selected badge draws enlarged and ringed
476 // Badge colour reflects constraint solve state no on top tint
477 auto walkConstraints =
478 [&]( const CONSTRAINTS& aConstraints )
479 {
480 for( PCB_CONSTRAINT* constraint : aConstraints )
481 {
482 const std::vector<CONSTRAINT_MEMBER>& members = constraint->GetMembers();
483
484 if( members.empty() || !constraintShown( constraint ) )
485 continue;
486
487 bool errored = erroredIds.contains( constraint->m_Uuid );
488 bool conflicting = conflictingIds.contains( constraint->m_Uuid );
489
490 const CONSTRAINT_MEMBER& first = members.front();
491 std::optional<VECTOR2I> pos = badgePosition( first );
492
493 if( !pos )
494 continue;
495
496 COLOR4D color;
497
498 if( errored || conflicting )
499 {
500 color = overColor;
501 }
502 else if( auto it = diag.shapeStates.find( first.m_item );
503 it != diag.shapeStates.end() )
504 {
505 color = colorForState( it->second );
506 }
507 else
508 {
509 color = underColor; // undiagnosed (e.g. an unsupported cluster); not "well"
510 }
511
512 std::vector<SEG> avoid;
513
514 for( const CONSTRAINT_MEMBER& member : members )
515 {
516 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( m_board->ResolveItem( member.m_item, true ) ) )
517 {
518 appendShapeSegs( shape, avoid );
519 }
520 }
521
522 m_badges.push_back(
523 { *pos, constraint->m_Uuid, constraint->GetConstraintType(), color, std::move( avoid ) } );
524 }
525 };
526
527 walkConstraints( m_board->Constraints() );
528
529 for( FOOTPRINT* footprint : m_board->Footprints() )
530 walkConstraints( footprint->Constraints() );
531
532 // Pick preview outline draws last on top of diagnostics tint in a hue distinct from state colours
533 // Anchor point drawn by badge item at constant screen size like an edit handle not scaled with zoom
535 {
536 const COLOR4D previewColor( 0.10, 0.85, 0.95, 0.9 ); // cyan, distinct from the state tints
537
538 BOARD_ITEM* previewItem = m_board->ResolveItem( m_previewElement, true );
539
540 if( PCB_SHAPE* shape = dynamic_cast<PCB_SHAPE*>( previewItem ) )
541 {
542 outlineShape( shape, previewColor );
543 }
544 else if( PCB_DIMENSION_BASE* dimension = dynamic_cast<PCB_DIMENSION_BASE*>( previewItem ) )
545 {
546 // Dimension has no outline to stroke so mark bindable feature points like diagnostics render
547 // keeps whole element visible while picking
548 setStroke( previewColor );
549
550 for( const CONSTRAINT_ANCHOR_POINT& anchor : ConstraintItemAnchors( dimension ) )
551 m_overlay->Circle( anchor.pos, 2 * lineWidth );
552 }
553 }
554
555 // Drop a selection whose constraint no longer has a badge (deleted, or its members vanished).
556 if( m_selected != niluuid
557 && std::none_of( m_badges.begin(), m_badges.end(),
558 [&]( const CONSTRAINT_BADGE& aBadge )
559 { return aBadge.constraint == m_selected; } ) )
560 {
562 }
563
564 m_badgeItem.SetBadges( m_badges, m_selected );
565
566 // Only a point pick shows the anchor marker badge item draws it at constant screen size
567 m_badgeItem.SetPreviewAnchor( m_previewWhole ? std::optional<VECTOR2I>{} : m_previewAnchor );
568
569 m_view->Update( &m_badgeItem );
570 m_view->Update( m_overlay.get() );
571 m_view->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
572}
573
574
579
580
582
583
585{
586 if( auto it = m_icons.find( aType ); it != m_icons.end() )
587 return it->second.get();
588
589 std::unique_ptr<BITMAP_BASE> base;
590
591 if( BITMAPS id = ConstraintTypeBitmap( aType ); id != BITMAPS::INVALID_BITMAP )
592 {
593 if( wxBitmap bmp = KiBitmap( id ); bmp.IsOk() )
594 {
595 base = std::make_unique<BITMAP_BASE>();
596 base->SetImage( bmp.ConvertToImage() );
597 }
598 }
599
600 return ( m_icons[aType] = std::move( base ) ).get();
601}
602
603
605{
606 uint8_t r = uint8_t( aColor.r * 255.0 );
607 uint8_t g = uint8_t( aColor.g * 255.0 );
608 uint8_t b = uint8_t( aColor.b * 255.0 );
609 uint8_t a = uint8_t( aColor.a * 255.0 );
610
611 uint32_t key = ( uint32_t( r ) << 24 ) | ( uint32_t( g ) << 16 ) | ( uint32_t( b ) << 8 ) | a;
612
613 if( auto it = m_discs.find( key ); it != m_discs.end() )
614 return it->second.get();
615
616 const int S = 96;
617 wxImage img( S, S );
618 img.InitAlpha();
619
620 const double center = S / 2.0;
621 const double radius = center - 1.0;
622
623 for( int y = 0; y < S; ++y )
624 {
625 for( int x = 0; x < S; ++x )
626 {
627 double d = std::hypot( x + 0.5 - center, y + 0.5 - center );
628 double coverage = std::clamp( radius - d + 0.5, 0.0, 1.0 );
629
630 img.SetRGB( x, y, r, g, b );
631 img.SetAlpha( x, y, uint8_t( a * coverage ) );
632 }
633 }
634
635 auto base = std::make_unique<BITMAP_BASE>();
636 base->SetImage( img );
637
638 return ( m_discs[key] = std::move( base ) ).get();
639}
640
641
642void CONSTRAINT_BADGE_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
643{
644 KIGFX::GAL* gal = aView->GetGAL();
645 const double scale = gal->GetWorldScale();
646
647 if( scale <= 0.0 )
648 return;
649
650 const double iconPx = 18.0;
651 const double bigIconPx = 26.0;
652 const double linePx = 1.5;
653
654 // Keep the badge a constant on-screen size at any zoom. A world-size floor would make it grow
655 // without bound as you keep zooming in, so there is none.
656 const double worldPerPx = CONSTRAINT_OVERLAY::BadgeWorldPerPixel( scale );
657 const double worldUnitLength = gal->GetWorldUnitLength();
658
659 // The same layout drives hit-testing (CONSTRAINT_EDIT_TOOL::hitTestBadge), so draw and click
660 // positions can never diverge. Recompute only when the zoom or badge set changed.
661 if( m_layoutScale != worldPerPx )
662 {
664 m_layoutScale = worldPerPx;
665 }
666
667 // Draw a bitmap centred on aPos, scaled so its width spans aWidth world units.
668 auto blit = [&]( BITMAP_BASE* aBmp, const VECTOR2I& aPos, double aWidth )
669 {
670 double natural = aBmp->GetSizePixels().x / ( aBmp->GetPPI() * worldUnitLength );
671
672 if( natural <= 0.0 )
673 return;
674
675 gal->Save();
676 gal->Translate( aPos );
677 gal->Scale( VECTOR2D( aWidth / natural, aWidth / natural ) );
678 gal->DrawBitmap( *aBmp, 1.0 );
679 gal->Restore();
680 };
681
682 for( size_t i = 0; i < m_badges.size(); ++i )
683 {
684 const CONSTRAINT_BADGE& badge = m_badges[i];
685 BITMAP_BASE* bitmap = icon( badge.type );
686
687 if( !bitmap )
688 continue;
689
690 bool selected = m_selected != niluuid && badge.constraint == m_selected;
691 double iconSize = ( selected ? bigIconPx : iconPx ) * worldPerPx;
692 double chipR = 0.62 * iconSize;
693 VECTOR2I pos( KiROUND( m_layout[i].x ), KiROUND( m_layout[i].y ) );
694
695 // Chip and icon are both bitmaps, so the icon always lands on top of the chip.
696 blit( disc( badge.color ), pos, 2.0 * chipR );
697
698 if( selected )
699 {
700 gal->SetIsFill( false );
701 gal->SetIsStroke( true );
702 gal->SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 0.9 ) );
703 gal->SetLineWidth( static_cast<float>( linePx * worldPerPx ) );
704 gal->DrawCircle( pos, chipR + 2.0 * linePx * worldPerPx );
705 }
706
707 blit( bitmap, pos, iconSize );
708 }
709
710 // Anchor draws here not in cached overlay so it holds constant on screen size like edit handle
711 // sized larger so candidate point stands out
712 if( m_previewAnchor )
713 {
714 const double pxToWorld = 1.0 / scale;
715 const double radius = 1.25 * EDIT_POINT::POINT_SIZE * pxToWorld;
716
717 gal->SetIsFill( true );
718 gal->SetIsStroke( true );
719 gal->SetFillColor( COLOR4D( 0.95, 0.15, 0.85, 0.95 ) ); // magenta, contrasts the outline
720 gal->SetStrokeColor( COLOR4D( 1.0, 1.0, 1.0, 0.9 ) );
721 gal->SetLineWidth( static_cast<float>( linePx * pxToWorld ) );
723 }
724}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition bitmap.cpp:100
BITMAPS
A list of all bitmap identifiers.
@ INVALID_BITMAP
CONSTRAINT_STATE
The constraint state of a shape, for the diagnostics overlay tint.
@ OVER_CONSTRAINED
In a cluster the solver reports as conflicting.
@ UNDER_CONSTRAINED
In a cluster with remaining free degrees of freedom.
@ WELL_CONSTRAINED
In a fully-determined cluster (zero free DOF).
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
This class handle bitmap images in KiCad.
Definition bitmap_base.h:45
VECTOR2I GetSizePixels() const
int GetPPI() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
int GetMaxError() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
std::optional< VECTOR2I > m_previewAnchor
std::vector< CONSTRAINT_BADGE > m_badges
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
std::map< uint32_t, std::unique_ptr< BITMAP_BASE > > m_discs
BITMAP_BASE * disc(const KIGFX::COLOR4D &aColor) const
A filled disc of the given colour, built and cached on first use.
~CONSTRAINT_BADGE_ITEM() override
std::map< PCB_CONSTRAINT_TYPE, std::unique_ptr< BITMAP_BASE > > m_icons
std::vector< VECTOR2D > m_layout
BITMAP_BASE * icon(PCB_CONSTRAINT_TYPE aType) const
The badge icon for a constraint type, loaded and cached on first use (nullptr for UNDEFINED).
static double BadgeHitRadius()
Click hit radius in screen pixels.
bool SetPickPreview(const KIID &aElement, bool aWholeElement, const std::optional< VECTOR2I > &aAnchor)
Preview next constraint pick target while authoring a point based constraint aElement is shape or dim...
bool SetVisibilityMode(OVERLAY_MODE aMode)
Set the visibility mode (HOVER vs ALWAYS). Returns true if it changed.
void RefreshSelection()
Redraw from the last diagnosis without re-solving (for a selection-only change).
bool SetIsolated(const KIID &aConstraint)
Show only this constraint, or niluuid to show all. Returns true if it changed.
CONSTRAINT_OVERLAY(BOARD *aBoard, KIGFX::VIEW *aView)
CONSTRAINT_BADGE_ITEM m_badgeItem
void ClearPickPreview()
Drop any pick preview.
BOARD_CONSTRAINT_DIAGNOSTICS m_lastDiag
std::vector< CONSTRAINT_BADGE > m_badges
std::optional< VECTOR2I > m_previewAnchor
static double BadgeWorldPerPixel(double aWorldScale)
World units per screen pixel for badge sizing, capped at far zoom-out.
void render()
Redraw the tint and badges from m_lastDiag (no re-solve).
void Clear()
Hide the overlay.
static VECTOR2D BadgeScreenOffset()
Screen-pixel offset from a badge's anchor to where its glyph draws and hit-tests, keeping the glyph c...
bool SetSelected(const KIID &aConstraint)
Mark a constraint as selected so its badge draws enlarged and ringed; pass niluuid to clear.
bool SetHoverShape(const KIID &aShape)
In HOVER mode, show only this shape's constraints; niluuid draws nothing.
static std::vector< VECTOR2D > LayoutBadges(const std::vector< CONSTRAINT_BADGE > &aBadges, double aWorldPerPx)
The on-screen draw position (world units) of each badge at the given scale: the anchor offset by Badg...
void Update(const BOARD_CONSTRAINT_DIAGNOSTICS &aDiag)
Redraw the tint and badges from aDiag (the caller owns the one board-wide solve).
double Sin() const
Definition eda_angle.h:178
double AsDegrees() const
Definition eda_angle.h:116
double Cos() const
Definition eda_angle.h:197
const KIID m_Uuid
Definition eda_item.h:531
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:37
EDA_ANGLE GetArcAngle() const
int GetEllipseMinorRadius() const
Definition eda_shape.h:310
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:292
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:338
int GetEllipseMajorRadius() const
Definition eda_shape.h:301
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:319
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:185
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:329
const std::vector< VECTOR2I > & GetBezierPoints() const
Definition eda_shape.h:404
static const int POINT_SIZE
Single point size in pixels.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double r
Red component.
Definition color4d.h:389
double g
Green component.
Definition color4d.h:390
double a
Alpha component.
Definition color4d.h:392
double b
Blue component.
Definition color4d.h:391
Abstract interface for drawing on a 2D-surface.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual void Translate(const VECTOR2D &aTranslation)
Translate the context.
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius)
Draw a circle using world coordinates.
virtual void Restore()
Restore the context.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
double GetWorldUnitLength() const
virtual void Scale(const VECTOR2D &aScale)
Scale the context.
virtual void DrawBitmap(const BITMAP_BASE &aBitmap, double alphaBlend=1.0)
Draw a bitmap image.
virtual void Save()
Save the context.
double GetWorldScale() const
Get the world scale.
Contains all the knowledge about how to draw graphical object onto any particular output device.
Definition painter.h:55
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:207
Definition kiid.h:44
A geometric constraint between board items (issue #2329).
const std::vector< CONSTRAINT_MEMBER > & GetMembers() const
Abstract dimension API.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:78
Definition seg.h:38
int Distance(const SEG &aSeg) const
Compute minimum Euclidean distance to segment aSeg.
Definition seg.cpp:698
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
std::shared_ptr< KIGFX::VIEW_OVERLAY > m_overlay
VIEW_OVERLAY_HOLDER(KIGFX::VIEW *aView)
std::vector< CONSTRAINT_ANCHOR_POINT > ConstraintItemAnchors(const BOARD_ITEM *aItem)
The constraint anchors an item exposes.
std::optional< VECTOR2I > ConstraintAnchorPosition(BOARD *aBoard, const CONSTRAINT_MEMBER &aMember)
Current location of a constraint member's anchor (its shape's START/END/CENTER, or a dimension's feat...
OVERLAY_MODE
Draws the geometric-constraint diagnostics tint onto a GAL overlay (issue #2329): every constrained s...
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:417
@ ELLIPSE
Definition eda_shape.h:52
@ SEGMENT
Definition eda_shape.h:46
@ ELLIPSE_ARC
Definition eda_shape.h:53
@ S
Solder (HASL/SMOBC)
KIID niluuid(0)
@ LAYER_CONSTRAINT_UNDER
Under-constrained (free DOF remain).
Definition layer_ids.h:334
@ LAYER_CONSTRAINT_OVER
Over-constrained / conflicting.
Definition layer_ids.h:336
@ LAYER_CONSTRAINT_WELL
Fully constrained.
Definition layer_ids.h:335
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:35
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
BITMAPS ConstraintTypeBitmap(PCB_CONSTRAINT_TYPE aType)
Badge icon for a constraint type; INVALID_BITMAP for UNDEFINED.
PCB_CONSTRAINT_TYPE
The geometric relationship a PCB_CONSTRAINT enforces between its members.
std::deque< PCB_CONSTRAINT * > CONSTRAINTS
const int scale
Board-wide diagnostics for the constraint overlay and info bar.
std::map< KIID, CONSTRAINT_STATE > shapeStates
std::vector< KIID > errored
Invalid constraints (member missing, deleted, or of a kind incompatible with the type).
A selectable feature of a shape (a segment endpoint, arc centre, ...) and its location.
An on-canvas constraint badge.
KIGFX::COLOR4D color
PCB_CONSTRAINT_TYPE type
One participant in a constraint: a referenced board item plus the feature of that item that participa...
KIID m_item
Referenced board item, usually a PCB_SHAPE.
VECTOR2I center
int radius
int clearance
#define M_PI
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:72
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682