KiCad PCB EDA Suite
router_preview_item.cpp
Go to the documentation of this file.
1 /*
2  * KiRouter - a push-and-(sometimes-)shove PCB router
3  *
4  * Copyright (C) 2013-2014 CERN
5  * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * Author: Tomasz Wlostowski <[email protected]>
7  *
8  * This program is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation, either version 3 of the License, or (at your
11  * option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <deque>
23 #include <gal/color4d.h>
24 
25 #include <geometry/shape_rect.h>
26 #include <geometry/shape_simple.h>
27 #include <pcb_painter.h>
28 #include <trigo.h>
29 
30 #include "router_preview_item.h"
31 
32 #include "pns_arc.h"
33 #include "pns_line.h"
34 #include "pns_segment.h"
35 #include "pns_via.h"
36 
37 using namespace KIGFX;
38 
39 
42 {
43  m_view = aView;
44 
45  m_shape = aItem ? aItem->Shape()->Clone() : nullptr;
46  m_hole = aItem && aItem->Hole() ? aItem->Hole()->Clone() : nullptr;
47 
48  m_clearance = -1;
50 
51  m_showClearance = false;
52 
53  // initialize variables, overwritten by Update( aItem ), if aItem != NULL
54  m_router = nullptr;
55  m_type = PR_SHAPE;
56  m_style = 0;
57  m_width = 0;
58  m_depth = 0;
59 
60  if( aItem )
61  Update( aItem );
62 }
63 
64 
66 {
67  delete m_shape;
68  delete m_hole;
69 }
70 
71 
73 {
74  m_originLayer = aItem->Layers().Start();
75 
76  if( const PNS::LINE* l = dyn_cast<const PNS::LINE*>( aItem ) )
77  {
78  if( !l->SegmentCount() )
79  return;
80  }
81  else if( const PNS::VIA* v = dyn_cast<const PNS::VIA*>( aItem ) )
82  {
83  if( v->IsVirtual() )
84  return;
85  }
86 
87  assert( m_originLayer >= 0 );
88 
91  m_color.a = 0.8;
92  m_depth = BaseOverlayDepth - aItem->Layers().Start();
93 
94  switch( aItem->Kind() )
95  {
96  case PNS::ITEM::LINE_T:
97  m_type = PR_SHAPE;
98  m_width = static_cast<const PNS::LINE*>( aItem )->Width();
99  break;
100 
101  case PNS::ITEM::ARC_T:
102  m_type = PR_SHAPE;
103  m_width = static_cast<const PNS::ARC*>( aItem )->Width();
104  break;
105 
107  m_type = PR_SHAPE;
108  m_width = static_cast<const PNS::SEGMENT*>( aItem )->Width();
109  break;
110 
111  case PNS::ITEM::VIA_T:
113  m_type = PR_SHAPE;
114  m_width = 0;
115  m_color = COLOR4D( 0.7, 0.7, 0.7, 0.8 );
117 
118  delete m_shape;
119  m_shape = nullptr;
120 
121  if( aItem->Shape() )
122  m_shape = aItem->Shape()->Clone();
123 
124  delete m_hole;
125  m_hole = nullptr;
126 
127  if( aItem->Hole() )
128  m_hole = aItem->Hole()->Clone();
129 
130  break;
131 
132  case PNS::ITEM::SOLID_T:
133  m_type = PR_SHAPE;
134  m_width = 0;
135  break;
136 
137  default:
138  break;
139  }
140 
141  if( aItem->Marker() & PNS::MK_VIOLATION )
142  m_color = COLOR4D( 0, 1, 0, 1 );
143 }
144 
145 
147 {
148  BOX2I bbox;
149 
150  switch( m_type )
151  {
152  case PR_SHAPE:
153  if( m_shape )
154  {
155  bbox = m_shape->BBox();
156  bbox.Inflate( m_width / 2 );
157  }
158 
159  if( m_hole )
160  bbox.Merge( m_hole->BBox() );
161 
162  return bbox;
163 
164  case PR_POINT:
165  bbox = BOX2I ( m_pos - VECTOR2I( 100000, 100000 ), VECTOR2I( 200000, 200000 ) );
166  return bbox;
167 
168  default:
169  break;
170  }
171 
172  return bbox;
173 }
174 
175 
177 {
178  gal->SetIsFill( false );
179 
180  for( int s = 0; s < aL->GetSegmentCount(); s++ )
181  gal->DrawLine( aL->GetSegment( s ).A, aL->GetSegment( s ).B );
182 
183  const SHAPE_LINE_CHAIN* lineChain = dynamic_cast<const SHAPE_LINE_CHAIN*>( aL );
184 
185  for( size_t s = 0; lineChain && s < lineChain->ArcCount(); s++ )
186  {
187  const SHAPE_ARC& arc = lineChain->CArcs()[s];
188 
189  double start_angle = DEG2RAD( arc.GetStartAngle() );
190  double angle = DEG2RAD( arc.GetCentralAngle() );
191 
192  gal->DrawArc( arc.GetCenter(), arc.GetRadius(), start_angle, start_angle + angle);
193  }
194 
195  if( aL->IsClosed() )
196  gal->DrawLine( aL->GetSegment( -1 ).B, aL->GetSegment( 0 ).A );
197 }
198 
199 
200 void ROUTER_PREVIEW_ITEM::drawShape( const SHAPE* aShape, KIGFX::GAL* gal ) const
201 {
202  bool holeDrawn = false;
203 
204  switch( aShape->Type() )
205  {
207  {
208  const SHAPE_LINE_CHAIN_BASE* l = (const SHAPE_LINE_CHAIN_BASE*) aShape;
209 
210  if( m_showClearance && m_clearance > 0 )
211  {
212  gal->SetLineWidth( m_width + 2 * m_clearance );
213  drawLineChain( l, gal );
214  }
215 
216  gal->SetLayerDepth( m_depth );
217  gal->SetLineWidth( m_width );
218  gal->SetStrokeColor( m_color );
219  gal->SetFillColor( m_color );
220  drawLineChain( l, gal );
221  break;
222  }
223 
224  case SH_LINE_CHAIN:
225  {
226  const SHAPE_LINE_CHAIN* l = (const SHAPE_LINE_CHAIN*) aShape;
227  const int w = m_width;
228 
229  if( m_showClearance && m_clearance > 0 )
230  {
231  gal->SetLineWidth( w + 2 * m_clearance );
232  drawLineChain( l, gal );
233  }
234 
235  gal->SetLayerDepth( m_depth );
236  gal->SetLineWidth( w );
237  gal->SetStrokeColor( m_color );
238  gal->SetFillColor( m_color );
239  drawLineChain( l, gal );
240  break;
241  }
242 
243  case SH_SEGMENT:
244  {
245  const SHAPE_SEGMENT* s = (const SHAPE_SEGMENT*) aShape;
246  const int w = s->GetWidth();
247 
248  gal->SetIsStroke( false );
249 
250  if( m_showClearance && m_clearance > 0 )
251  {
252  gal->SetLineWidth( w + 2 * m_clearance );
253  gal->DrawSegment( s->GetSeg().A, s->GetSeg().B, s->GetWidth() + 2 * m_clearance );
254  }
255 
256  gal->SetLayerDepth( m_depth );
257  gal->SetLineWidth( w );
258  gal->SetFillColor( m_color );
259  gal->DrawSegment( s->GetSeg().A, s->GetSeg().B, s->GetWidth() );
260  break;
261  }
262 
263  case SH_CIRCLE:
264  {
265  const SHAPE_CIRCLE* c = static_cast<const SHAPE_CIRCLE*>( aShape );
266  gal->SetStrokeColor( m_color );
267 
268  if( m_showClearance && m_clearance > 0 )
269  {
270  gal->SetIsStroke( false );
271  gal->DrawCircle( c->GetCenter(), c->GetRadius() + m_clearance );
272  }
273 
274  gal->SetLayerDepth( m_depth );
275 
276  if( m_hole && dynamic_cast<SHAPE_CIRCLE*>( m_hole ) )
277  {
278  const SHAPE_CIRCLE* h = static_cast<const SHAPE_CIRCLE*>( m_hole );
279  int halfWidth = m_width / 2;
280 
281  gal->SetIsStroke( true );
282  gal->SetIsFill( false );
283  gal->SetLineWidth( halfWidth + c->GetRadius() - h->GetRadius() );
284  gal->DrawCircle( c->GetCenter(), ( halfWidth + c->GetRadius() + h->GetRadius() ) / 2 );
285 
286  holeDrawn = true;
287  }
288  else
289  {
290  gal->SetIsStroke( m_width ? true : false );
291  gal->SetLineWidth( m_width );
292  gal->SetFillColor( m_color );
293  gal->DrawCircle( c->GetCenter(), c->GetRadius() );
294  }
295 
296  break;
297  }
298 
299  case SH_RECT:
300  {
301  const SHAPE_RECT* r = (const SHAPE_RECT*) aShape;
302  gal->SetFillColor( m_color );
303 
304  if( m_showClearance && m_clearance > 0 )
305  {
306  VECTOR2I p0( r->GetPosition() ), s( r->GetSize() );
307  gal->SetIsStroke( true );
308  gal->SetLineWidth( 2 * m_clearance );
309  gal->DrawLine( p0, VECTOR2I( p0.x + s.x, p0.y ) );
310  gal->DrawLine( p0, VECTOR2I( p0.x, p0.y + s.y ) );
311  gal->DrawLine( p0 + s , VECTOR2I( p0.x + s.x, p0.y ) );
312  gal->DrawLine( p0 + s, VECTOR2I( p0.x, p0.y + s.y ) );
313  }
314 
315  gal->SetLayerDepth( m_depth );
316  gal->SetIsStroke( m_width ? true : false );
317  gal->SetLineWidth( m_width);
318  gal->SetStrokeColor( m_color );
319  gal->DrawRectangle( r->GetPosition(), r->GetPosition() + r->GetSize() );
320 
321  break;
322  }
323 
324  case SH_SIMPLE:
325  {
326  const SHAPE_SIMPLE* c = (const SHAPE_SIMPLE*) aShape;
327  std::deque<VECTOR2D> polygon = std::deque<VECTOR2D>();
328 
329  for( int i = 0; i < c->PointCount(); i++ )
330  {
331  polygon.push_back( c->CDPoint( i ) );
332  }
333 
334  gal->SetFillColor( m_color );
335 
336  if( m_showClearance && m_clearance > 0 )
337  {
338  gal->SetIsStroke( true );
339  gal->SetLineWidth( 2 * m_clearance );
340 
341  // need the implicit last segment to be explicit for DrawPolyline
342  polygon.push_back( c->CDPoint( 0 ) );
343  gal->DrawPolyline( polygon );
344  }
345 
346  gal->SetLayerDepth( m_depth );
347  gal->SetIsStroke( m_width ? true : false );
348  gal->SetLineWidth( m_width );
349  gal->SetStrokeColor( m_color );
350  gal->DrawPolygon( polygon );
351  break;
352  }
353 
354  case SH_ARC:
355  {
356  const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( aShape );
357  const int w = arc->GetWidth();
358 
359  auto start_angle = DEG2RAD( arc->GetStartAngle() );
360  auto angle = DEG2RAD( arc->GetCentralAngle() );
361 
362  gal->SetIsFill( false );
363  gal->SetIsStroke( true );
364 
365  if( m_showClearance && m_clearance > 0 )
366  {
367  gal->SetLineWidth( w + 2 * m_clearance );
368  gal->DrawArc( arc->GetCenter(), arc->GetRadius(), start_angle, start_angle + angle );
369  }
370 
371  gal->SetLayerDepth( m_depth );
372  gal->SetStrokeColor( m_color );
373  gal->SetFillColor( m_color );
374  gal->SetLineWidth( w );
375  gal->DrawArc( arc->GetCenter(), arc->GetRadius(), start_angle, start_angle + angle );
376  break;
377  }
378 
379  case SH_COMPOUND:
380  wxFAIL_MSG( wxT( "Router preview item: nested compound shapes not supported" ) );
381  break;
382 
383  case SH_POLY_SET:
384  wxFAIL_MSG( wxT( "Router preview item: SHAPE_POLY_SET not supported" ) );
385  break;
386 
387  case SH_NULL:
388  break;
389  }
390 
391  if( m_hole && !holeDrawn )
392  {
393  gal->SetLayerDepth( m_depth );
394  gal->SetIsStroke( true );
395  gal->SetIsFill( false );
396  gal->SetStrokeColor( m_color );
397  gal->SetLineWidth( 1 );
398 
399  SHAPE_CIRCLE* circle = dynamic_cast<SHAPE_CIRCLE*>( m_hole );
400  SHAPE_SEGMENT* slot = dynamic_cast<SHAPE_SEGMENT*>( m_hole );
401 
402  if( circle )
403  gal->DrawCircle( circle->GetCenter(), circle->GetRadius() );
404  else if( slot )
405  gal->DrawSegment( slot->GetSeg().A, slot->GetSeg().B, slot->GetWidth() );
406  }
407 }
408 
409 
410 void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
411 {
412  GAL* gal = aView->GetGAL();
413  //col.Brighten(0.7);
414 
415  if( m_type == PR_SHAPE )
416  {
417  if( !m_shape )
418  return;
419 
420  // N.B. The order of draw here is important
421  // Cairo doesn't current support z-ordering, so we need
422  // to draw the clearance first to ensure it is in the background
424 
425  //TODO(snh) Add configuration option for the color/alpha here
426  gal->SetStrokeColor( COLOR4D( DARKDARKGRAY ).WithAlpha( 0.9 ) );
427  gal->SetFillColor( COLOR4D( DARKDARKGRAY ).WithAlpha( 0.7 ) );
428  gal->SetIsStroke( m_width ? true : false );
429  gal->SetIsFill( true );
430 
432  {
433  std::vector<SHAPE*> subshapes;
434  m_shape->GetIndexableSubshapes( subshapes );
435 
436  for( SHAPE* shape : subshapes )
437  drawShape( shape, gal );
438  }
439  else
440  {
441  drawShape( m_shape, gal );
442  }
443  }
444 }
445 
446 
447 void ROUTER_PREVIEW_ITEM::Line( const SHAPE_LINE_CHAIN& aLine, int aWidth, int aStyle )
448 {
449  m_width = aWidth;
450 
451  if( aStyle >= 0 )
452  m_color = assignColor( aStyle );
453 
454  m_type = PR_SHAPE;
455  m_depth = -1024; // TODO gal->GetMinDepth()
456 
457  SHAPE_LINE_CHAIN *lc = static_cast<SHAPE_LINE_CHAIN*>( aLine.Clone() );
458  lc->SetWidth( aWidth );
459  m_shape = lc;
460 }
461 
462 
463 void ROUTER_PREVIEW_ITEM::Point( const VECTOR2I& aPos, int aStyle )
464 {
465 }
466 
467 
468 void ROUTER_PREVIEW_ITEM::Box( const BOX2I& aBox, int aStyle )
469 {
470 }
471 
472 
474 {
475  auto settings = static_cast<PCB_RENDER_SETTINGS*>( m_view->GetPainter()->GetSettings() );
476 
477  return settings->GetLayerColor( aLayer );
478 }
479 
480 
481 const COLOR4D ROUTER_PREVIEW_ITEM::assignColor( int aStyle ) const
482 {
483  COLOR4D color;
484 
485  switch( aStyle )
486  {
487  case 0: color = COLOR4D( 0, 1, 0, 1 ); break;
488  case 1: color = COLOR4D( 1, 0, 0, 1 ); break;
489  case 2: color = COLOR4D( 1, 1, 0, 1 ); break;
490  case 3: color = COLOR4D( 0, 0, 1, 1 ); break;
491  case 4: color = COLOR4D( 1, 1, 1, 1 ); break;
492  case 5: color = COLOR4D( 1, 1, 0, 1 ); break;
493  case 6: color = COLOR4D( 0, 1, 1, 1 ); break;
494  case 32: color = COLOR4D( 0, 0, 1, 1 ); break;
495  default: color = COLOR4D( 0.4, 0.4, 0.4, 1 ); break;
496  }
497 
498  return color;
499 }
500 
501 const int ROUTER_PREVIEW_ITEM::ClearanceOverlayDepth = -VIEW::VIEW_MAX_LAYERS - 10;
502 const int ROUTER_PREVIEW_ITEM::BaseOverlayDepth = -VIEW::VIEW_MAX_LAYERS - 20;
503 const int ROUTER_PREVIEW_ITEM::ViaOverlayDepth = -VIEW::VIEW_MAX_LAYERS - 50;
compound shape, consisting of multiple simple shapes
Definition: shape.h:49
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
Base class for PNS router board items.
Definition: pns_item.h:55
virtual void DrawPolyline(const std::deque< VECTOR2D > &aPointList)
Draw a polyline.
void drawShape(const SHAPE *aShape, KIGFX::GAL *aGal) const
static const int ClearanceOverlayDepth
virtual const SHAPE * Hole() const
Definition: pns_item.h:205
currently selected items overlay
Definition: layer_ids.h:226
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
BOX2< VECTOR2I > BOX2I
Definition: box2.h:506
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:41
void drawLineChain(const SHAPE_LINE_CHAIN_BASE *aL, KIGFX::GAL *aGal) const
int GetRadius() const
Definition: shape_circle.h:107
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:243
static const int BaseOverlayDepth
double GetRadius() const
Definition: shape_arc.cpp:452
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle)
Draw an arc.
virtual bool IsClosed() const =0
the 3d code uses this value
Definition: typeinfo.h:79
int color
Definition: DXF_plotter.cpp:57
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:190
double GetStartAngle() const
Definition: shape_arc.cpp:404
const VECTOR2I GetCenter() const
Definition: shape_circle.h:112
size_t ArcCount() const
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition: pns_line.h:60
virtual size_t GetSegmentCount() const =0
const std::vector< SHAPE_ARC > & CArcs() const
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
virtual const BOX2I BBox(int aClearance=0) const =0
Compute a bounding box of the shape, with a margin of aClearance a collision.
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:208
const KIGFX::COLOR4D getLayerColor(int aLayer) const
const SEG & GetSeg() const
virtual void SetLineWidth(float aLineWidth)
Set the line width.
int Start() const
Definition: pns_layerset.h:82
void SetWidth(int aWidth)
Set the width of all segments in the chain.
const VECTOR2D CDPoint(int aIndex) const
Return a given point as a vector with elements of type double.
Definition: shape_simple.h:113
double a
Alpha component.
Definition: color4d.h:387
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth)
Draw a rounded segment.
Meta control for all vias opacity/visibility.
Definition: layer_ids.h:200
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual const SHAPE * Shape() const
Return the geometrical shape of the item.
Definition: pns_item.h:200
void Update(const PNS::ITEM *aItem)
void Line(const SHAPE_LINE_CHAIN &aLine, int aWidth=0, int aStyle=-1)
const KIGFX::COLOR4D assignColor(int aStyle) const
virtual SHAPE * Clone() const
Return a dynamically allocated copy of the shape.
Definition: shape.h:139
circular arc
Definition: shape.h:50
An abstract shape on 2D plane.
Definition: shape.h:116
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:363
virtual void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override
Draw the parts of the object belonging to layer aLayer.
E_SERIE r
Definition: eserie.cpp:41
circle
Definition: shape.h:46
void Point(const VECTOR2I &aPos, int aStyle=0)
virtual const SEG GetSegment(int aIndex) const =0
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:281
int GetWidth() const
Definition: shape_arc.h:156
set of polygons (with holes, etc.)
Definition: shape.h:48
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList)
Draw a polygon.
a single triangle belonging to a POLY_SET triangulation
Definition: shape.h:52
virtual void GetIndexableSubshapes(std::vector< SHAPE * > &aSubshapes)
Definition: shape.h:106
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius)
Draw a circle using world coordinates.
double DEG2RAD(double deg)
Definition: trigo.h:229
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
VECTOR2I A
Definition: seg.h:48
int PointCount() const
Return the number of points (vertices) in this polygon.
Definition: shape_simple.h:88
double GetCentralAngle() const
Definition: shape_arc.cpp:439
empty shape (no shape...),
Definition: shape.h:51
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
line chain (polyline)
Definition: shape.h:45
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:130
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
virtual bool HasIndexableSubshapes() const
Definition: shape.h:99
axis-aligned rectangle
Definition: shape.h:43
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
static const int ViaOverlayDepth
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
int GetWidth() const
simple polygon
Definition: shape.h:47
SHAPE_TYPE Type() const
Return the type of the shape.
Definition: shape.h:94
void Box(const BOX2I &aBox, int aStyle=0)
VECTOR2I GetCenter() const
Definition: shape_arc.cpp:424
const LAYER_RANGE & Layers() const
Definition: pns_item.h:154
virtual int Marker() const
Definition: pns_item.h:212
ROUTER_PREVIEW_ITEM(const PNS::ITEM *aItem=nullptr, KIGFX::VIEW *aView=nullptr)
line segment
Definition: shape.h:44
Abstract interface for drawing on a 2D-surface.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
VECTOR2I B
Definition: seg.h:49