KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ratsnest_view_item.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) 2013 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Maciej Suminski <[email protected]>
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, see <https://www.gnu.org/licenses/>.
21 */
22
26
28
29#include <kiface_base.h>
31#include <pcbnew_settings.h>
32#include <pcb_painter.h>
34#include <layer_ids.h>
35#include <pcb_base_frame.h>
36#include <view/view.h>
37
38#include <memory>
39#include <utility>
40
41
42// A zero length connection is drawn as a fixed size cross
43static constexpr int CROSS_SIZE = 200000;
44
45// How far a curved line's control point sits off the chord, as a fraction of the span
46static constexpr double CURVE_BOW = 0.1;
47
48
49// A cross on an anchor near the coordinate limit overflows an int, so keep it in doubles
50static void drawCross( KIGFX::GAL* aGal, const VECTOR2D& aPos )
51{
52 aGal->DrawLine( aPos + VECTOR2D( -CROSS_SIZE, -CROSS_SIZE ),
53 aPos + VECTOR2D( CROSS_SIZE, CROSS_SIZE ) );
54 aGal->DrawLine( aPos + VECTOR2D( -CROSS_SIZE, CROSS_SIZE ),
55 aPos + VECTOR2D( CROSS_SIZE, -CROSS_SIZE ) );
56}
57
58
59RATSNEST_VIEW_ITEM::RATSNEST_VIEW_ITEM( std::shared_ptr<CONNECTIVITY_DATA> aData ) :
61 m_data( std::move( aData ) )
62{
63}
64
65
67{
68 // Doubles throughout because the span between two board corners overflows an int
69 VECTOR2D span = aTarget - aSource;
70
71 return aSource + VECTOR2D( 0.5 * span.x - CURVE_BOW * span.y,
72 0.5 * span.y + CURVE_BOW * span.x );
73}
74
75
76bool RATSNEST_VIEW_ITEM::LineInViewport( const VECTOR2I& aSource, const VECTOR2I& aTarget,
77 const BOX2D& aViewport, bool aCurved )
78{
79 VECTOR2D source( aSource );
80 VECTOR2D target( aTarget );
81 BOX2D bounds( source );
82
83 if( aSource == aTarget )
84 {
85 bounds.Inflate( CROSS_SIZE );
86 }
87 else
88 {
89 bounds.Merge( target );
90
91 // A cubic stays inside the hull of its endpoints and its control points, which are both
92 // the same point here
93 if( aCurved )
94 bounds.Merge( CurveControlPoint( source, target ) );
95 }
96
97 return aViewport.Intersects( bounds );
98}
99
100
102{
103 // Make it always visible
104 BOX2I bbox;
105 bbox.SetMaximum();
106
107 return bbox;
108}
109
110
111void RATSNEST_VIEW_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
112{
113 std::unique_lock<KISPINLOCK> lock( m_data->GetLock(), std::try_to_lock );
114
115 if( !lock )
116 return;
117
118 PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() );
119
120 if( !cfg )
121 return;
122
123 auto rs = static_cast<KIGFX::PCB_RENDER_SETTINGS*>( aView->GetPainter()->GetSettings() );
124 KIGFX::GAL* gal = aView->GetGAL();
125 gal->SetIsStroke( true );
126 gal->SetIsFill( false );
128
129 std::set<int> highlightedNets = rs->GetHighlightNetCodes();
130 const std::set<int>& hiddenNets = rs->GetHiddenNets();
131
132 COLOR4D defaultColor = rs->GetColor( nullptr, LAYER_RATSNEST );
133 COLOR4D color = defaultColor;
134 const bool colorByNet = rs->GetNetColorMode() != NET_COLOR_MODE::OFF;
135 const bool dimStatic = m_data->GetLocalRatsnest().size() > 0 || highlightedNets.size() > 0;
136
137 std::map<int, KIGFX::COLOR4D>& netColors = rs->GetNetColorMap();
138
139 const bool onlyVisibleLayers = cfg->m_Display.m_RatsnestMode == RATSNEST_MODE::VISIBLE;
140 LSET visibleLayers;
141
142 // If we are in "other layers off" mode, the active layer is the only visible layer
143 if( rs->m_ContrastModeDisplay == HIGH_CONTRAST_MODE::HIDDEN )
144 {
145 if( rs->GetPrimaryHighContrastLayer() > UNDEFINED_LAYER )
146 visibleLayers.set( rs->GetPrimaryHighContrastLayer() );
147 }
148 else
149 {
151 [&]( PCB_LAYER_ID layer )
152 {
153 if( aView->IsLayerVisible( layer ) )
154 visibleLayers.set( layer );
155 } );
156 }
157
158 auto adjustColor =
159 [&]( COLOR4D& color_base, double brightnessDelta, double alpha )
160 {
161 if( rs->GetColor( nullptr, LAYER_PCB_BACKGROUND ).GetBrightness() < 0.5 )
162 return color_base.Brightened( brightnessDelta ).WithAlpha( std::min( alpha, 1.0 ) );
163 else
164 return color_base.Darkened( brightnessDelta ).WithAlpha( std::min( alpha, 1.0 ) );
165 };
166
168
169 // Adaptive tessellation filter for the curved ratsnest. The ratsnest is only a visual
170 // hint, so there is no need to tessellate the Bezier to the default 10 nm precision: a
171 // polyline whose deviation from the true curve stays below line_width/2 is fully hidden
172 // by the line's own thickness. We use line_width/4 for a 2x safety margin. The filter is
173 // in world units and scales with zoom (line width is already world-scaled above), so it
174 // produces far fewer segments without any visible faceting.
175 const double curveFilter = curved_ratsnest ? ( gal->GetLineWidth() / 4.0 ) : 0.0;
176
177 // Lines are stroked, so one just off screen still reaches back into the viewport
178 BOX2D viewport = aView->GetViewport();
179 viewport.Inflate( gal->GetLineWidth() );
180
181 // Draw the "dynamic" ratsnest (i.e. for objects that may be currently being moved)
182 for( const RN_DYNAMIC_LINE& l : m_data->GetLocalRatsnest() )
183 {
184 if( hiddenNets.count( l.netCode ) )
185 continue;
186
187 if( !LineInViewport( l.a, l.b, viewport, curved_ratsnest ) )
188 continue;
189
190 const NETCLASS* nc = nullptr;
191 const NET_SETTINGS* netSettings = m_data->GetNetSettings();
192
193 if( m_data->HasNetNameForNetCode( l.netCode ) )
194 {
195 const wxString& netName = m_data->GetNetNameForNetCode( l.netCode );
196
197 if( netSettings && netSettings->HasEffectiveNetClass( netName ) )
198 nc = netSettings->GetCachedEffectiveNetClass( netName ).get();
199 }
200
201 if( colorByNet && netColors.count( l.netCode ) )
202 color = netColors.at( l.netCode );
203 else if( colorByNet && nc && nc->HasPcbColor() )
204 color = nc->GetPcbColor();
205 else
206 color = defaultColor;
207
208 if( color == COLOR4D::UNSPECIFIED )
209 color = defaultColor;
210
211 gal->SetStrokeColor( adjustColor( color, 0.5, color.a + 0.3 ) );
212
213 if( l.a == l.b )
214 {
215 drawCross( gal, l.a );
216 }
217 else
218 {
219 if( curved_ratsnest )
220 {
221 const VECTOR2D center = CurveControlPoint( l.a, l.b );
222 gal->DrawCurve( l.a, center, center, l.b, curveFilter );
223 }
224 else
225 {
226 gal->DrawLine( l.a, l.b );
227 }
228 }
229 }
230
231 for( int i = 1 /* skip "No Net" at [0] */; i < m_data->GetNetCount(); ++i )
232 {
233 if( hiddenNets.count( i ) )
234 continue;
235
236 RN_NET* net = m_data->GetRatsnestForNet( i );
237
238 if( !net || m_data->GetConnectivityAlgo()->IsNetDirty( i ) )
239 continue;
240
241 const NETCLASS* nc = nullptr;
242 const NET_SETTINGS* netSettings = m_data->GetNetSettings();
243
244 if( m_data->HasNetNameForNetCode( i ) )
245 {
246 const wxString& netName = m_data->GetNetNameForNetCode( i );
247
248 if( netSettings && netSettings->HasEffectiveNetClass( netName ) )
249 nc = netSettings->GetCachedEffectiveNetClass( netName ).get();
250 }
251
252 if( colorByNet && netColors.count( i ) )
253 color = netColors.at( i );
254 else if( colorByNet && nc && nc->HasPcbColor() )
255 color = nc->GetPcbColor();
256 else
257 color = defaultColor;
258
259 if( color == COLOR4D::UNSPECIFIED )
260 color = defaultColor;
261
262 if( dimStatic )
263 color = adjustColor( color, 0.0, color.a / 2 );
264
265 // Draw the "static" ratsnest
266 if( highlightedNets.count( i ) )
267 gal->SetStrokeColor( adjustColor( color, 0.8, color.a + 0.4 ) );
268 else
269 gal->SetStrokeColor( color ); // using the default ratsnest color for not highlighted
270
271 // Every line of a net is stroked in one colour on one layer, so their order is not
272 // observable and the sort in GetEdges() would be paid on every frame
273 for( const CN_EDGE& edge : net->GetUnsortedEdges() )
274 {
275 if( !edge.IsVisible() )
276 continue;
277
278 const std::shared_ptr<const CN_ANCHOR>& sourceNode = edge.GetSourceNode();
279 const std::shared_ptr<const CN_ANCHOR>& targetNode = edge.GetTargetNode();
280
281 if( !sourceNode || sourceNode->Dirty() || !targetNode || targetNode->Dirty() )
282 continue;
283
284 const VECTOR2I source( sourceNode->Pos() );
285 const VECTOR2I target( targetNode->Pos() );
286
287 if( !LineInViewport( source, target, viewport, curved_ratsnest ) )
288 continue;
289
290 bool enable = !sourceNode->GetNoLine() && !targetNode->GetNoLine();
291 bool show;
292
293 // If the global ratsnest is currently enabled, the local ratsnest should be easy to
294 // turn off, so either element can disable it.
295 // If the global ratsnest is disabled, the local ratsnest should be easy to turn on
296 // so either element can enable it.
298 {
299 show = sourceNode->Parent()->GetLocalRatsnestVisible() &&
300 targetNode->Parent()->GetLocalRatsnestVisible();
301 }
302 else
303 {
304 show = sourceNode->Parent()->GetLocalRatsnestVisible() ||
305 targetNode->Parent()->GetLocalRatsnestVisible();
306 }
307
308 if( onlyVisibleLayers && show )
309 {
310 LSET sourceLayers = sourceNode->Parent()->GetLayerSet();
311 LSET targetLayers = targetNode->Parent()->GetLayerSet();
312
313 if( !( sourceLayers & visibleLayers ).any() ||
314 !( targetLayers & visibleLayers ).any() )
315 {
316 show = false;
317 }
318 }
319
320 if ( enable && show )
321 {
322 if ( source == target )
323 {
324 drawCross( gal, source );
325 }
326 else
327 {
328 if( curved_ratsnest )
329 {
330 const VECTOR2D center = CurveControlPoint( source, target );
331 gal->DrawCurve( source, center, center, target, curveFilter );
332 }
333 else
334 {
335 gal->DrawLine( source, target );
336 }
337 }
338 }
339 }
340 }
341}
342
343
344std::vector<int> RATSNEST_VIEW_ITEM::ViewGetLayers() const
345{
346 return { LAYER_RATSNEST };
347}
348
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
@ curved_ratsnest
@ HIDDEN
Inactive layers are hidden.
@ OFF
Net (and netclass) colors are not shown.
@ VISIBLE
Ratsnest lines are drawn to items on visible layers only.
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
BOX2< VECTOR2D > BOX2D
Definition box2.h:915
BASE_SET & set(size_t pos)
Definition base_set.h:126
constexpr void SetMaximum()
Definition box2.h:77
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:400
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:92
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition color4d.h:309
COLOR4D Darkened(double aFactor) const
Return a color that is darker by a given factor, without modifying object.
Definition color4d.h:279
double a
Alpha component.
Definition color4d.h:394
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition color4d.h:265
Abstract interface for drawing on a 2D-surface.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
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.
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0)
Draw a cubic bezier spline.
float GetLineWidth() const
Get the line width.
double GetWorldScale() const
Get the world scale.
PCB specific render settings.
Definition pcb_painter.h:84
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition view.cpp:611
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:209
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition view.h:429
PAINTER * GetPainter() const
Return the painter object used by the view for drawing VIEW_ITEM objects.
Definition view.h:227
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
void RunOnLayers(const std::function< void(PCB_LAYER_ID)> &aFunction) const
Execute a function on each layer of the LSET.
Definition lset.h:275
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:43
COLOR4D GetPcbColor(bool aIsForSave=false) const
Definition netclass.h:206
bool HasPcbColor() const
Definition netclass.h:205
NET_SETTINGS stores various net-related settings in a project context.
bool HasEffectiveNetClass(const wxString &aNetName) const
Determines if an effective netclass for the given net name has been cached.
std::shared_ptr< NETCLASS > GetCachedEffectiveNetClass(const wxString &aNetName) const
Returns an already cached effective netclass for the given net name.
DISPLAY_OPTIONS m_Display
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
static bool LineInViewport(const VECTOR2I &aSource, const VECTOR2I &aTarget, const BOX2D &aViewport, bool aCurved)
Return true when a ratsnest line between aSource and aTarget can contribute to aViewport.
static VECTOR2D CurveControlPoint(const VECTOR2D &aSource, const VECTOR2D &aTarget)
Return the doubled Bezier control point used to bow a curved ratsnest line.
RATSNEST_VIEW_ITEM(std::shared_ptr< CONNECTIVITY_DATA > aData)
std::shared_ptr< CONNECTIVITY_DATA > m_data
Object containing ratsnest data.
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
Describe ratsnest for a single net.
const std::vector< CN_EDGE > & GetUnsortedEdges() const
Return the ratsnest edges in no particular order.
A type-safe container of any type.
Definition ki_any.h:92
std::string source
@ LAYER_PCB_BACKGROUND
PCB background color.
Definition layer_ids.h:277
@ LAYER_RATSNEST
Definition layer_ids.h:249
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ UNDEFINED_LAYER
Definition layer_ids.h:57
STL namespace.
Class that computes missing connections on a PCB.
static void drawCross(KIGFX::GAL *aGal, const VECTOR2D &aPos)
static constexpr double CURVE_BOW
static constexpr int CROSS_SIZE
Class that draws missing connections on a PCB.
VECTOR2I center
@ NOT_USED
the 3d code uses this value
Definition typeinfo.h:71
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707