KiCad PCB EDA Suite
gr_basic.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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
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 <gr_basic.h>
23 #include <trigo.h>
24 #include <eda_item.h>
25 #include <math_for_graphics.h>
26 #include <wx/graphics.h>
28 #include <math/util.h> // for KiROUND
29 
30 #include <algorithm>
31 
32 static const bool FILLED = true;
33 static const bool NOT_FILLED = false;
34 
35 /* Important Note:
36  * These drawing functions clip draw item before send these items to wxDC draw
37  * functions. For guy who asks why i did it, see a sample of problems encountered
38  * when pixels
39  * coordinates overflow 16 bits values:
40  * http://trac.wxwidgets.org/ticket/10446
41  * Problems can be found under Windows **and** Linux (mainly when drawing arcs)
42  * (mainly at low zoom values (2, 1 or 0.5), in Pcbnew)
43  * some of these problems could be now fixed in recent distributions.
44  *
45  * Currently (feb 2009) there are overflow problems when drawing solid (filled)
46  * polygons under linux without clipping
47  *
48  * So before removing clipping functions, be aware these bug (they are not in
49  * KiCad or wxWidgets) are fixed by testing how are drawn complex lines arcs
50  * and solid polygons under Windows and Linux and remember users can have old
51  * versions with bugs
52  */
53 
54 
55 /* Definitions for enabling and disabling debugging features in gr_basic.cpp.
56  * Please remember to set these back to 0 before making LAUNCHPAD commits.
57  */
58 #define DEBUG_DUMP_CLIP_ERROR_COORDS 0 // Set to 1 to dump clip algorithm errors.
59 #define DEBUG_DUMP_CLIP_COORDS 0 // Set to 1 to dump clipped coordinates.
60 
61 
62 // For draw mode = XOR GR_XOR or GR_NXOR by background color
64 
65 
66 static void ClipAndDrawPoly( EDA_RECT* ClipBox, wxDC* DC, const wxPoint* Points, int n );
67 
68 /* These functions are used by corresponding functions
69  * ( GRSCircle is called by GRCircle for instance) after mapping coordinates
70  * from user units to screen units(pixels coordinates)
71  */
72 static void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1,
73  int x2, int y2, int aWidth, const COLOR4D& aColor );
74 
75 
76 
78 static bool s_ForceBlackPen; /* if true: draws in black instead of
79  * color for printing. */
80 static int xcliplo = 0,
81  ycliplo = 0,
82  xcliphi = 2000,
83  ycliphi = 2000;
84 
85 static COLOR4D s_DC_lastbrushcolor( 0, 0, 0, 0 );
86 static bool s_DC_lastbrushfill = false;
87 static wxDC* s_DC_lastDC = nullptr;
88 
89 static void WinClipAndDrawLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
90  int width )
91 {
92  GRLastMoveToX = x2;
93  GRLastMoveToY = y2;
94 
95  if( ClipBox )
96  {
97  EDA_RECT clipbox(*ClipBox);
98  clipbox.Inflate(width/2);
99  if( ClipLine( &clipbox, x1, y1, x2, y2 ) )
100  return;
101  }
102 
103  DC->DrawLine( x1, y1, x2, y2 );
104 }
105 
106 
107 void GRResetPenAndBrush( wxDC* DC )
108 {
109  GRSetBrush( DC, BLACK ); // Force no fill
110  s_DC_lastbrushcolor = COLOR4D::UNSPECIFIED;
111  s_DC_lastDC = nullptr;
112 }
113 
114 
115 void GRSetColorPen( wxDC* DC, const COLOR4D& Color, int width, wxPenStyle style )
116 {
117  COLOR4D color = Color;
118 
119  wxDash dots[2] = { 1, 3 };
120 
121  // Under OSX and while printing when wxPen is set to 0, renderer follows the request drawing
122  // nothing & in the bitmap world the minimum is enough to light a pixel, in vectorial one not
123  if( width <= 1 )
124  width = DC->DeviceToLogicalXRel( 1 );
125 
126  if( s_ForceBlackPen )
128 
129  const wxPen& curr_pen = DC->GetPen();
130 
131  if( !curr_pen.IsOk() || curr_pen.GetColour() != color.ToColour()
132  || curr_pen.GetWidth() != width || curr_pen.GetStyle() != style )
133  {
134  wxPen pen;
135  pen.SetColour( color.ToColour() );
136 
137  if( style == wxPENSTYLE_DOT )
138  {
139  style = wxPENSTYLE_USER_DASH;
140  pen.SetDashes( 2, dots );
141  }
142 
143  pen.SetWidth( width );
144  pen.SetStyle( style );
145  DC->SetPen( pen );
146  }
147  else
148  {
149  // Should be not needed, but on Linux, in printing process
150  // the curr pen settings needs to be sometimes re-initialized
151  // Clearly, this is due to a bug, related to SetBrush(),
152  // but we have to live with it, at least on wxWidgets 3.0
153  DC->SetPen( curr_pen );
154  }
155 }
156 
157 
158 void GRSetBrush( wxDC* DC, const COLOR4D& Color, bool fill )
159 {
160  COLOR4D color = Color;
161 
162  if( s_ForceBlackPen )
164 
165  if( s_DC_lastbrushcolor != color || s_DC_lastbrushfill != fill || s_DC_lastDC != DC )
166  {
167  wxBrush brush;
168 
169  brush.SetColour( color.ToColour() );
170 
171  if( fill )
172  brush.SetStyle( wxBRUSHSTYLE_SOLID );
173  else
174  brush.SetStyle( wxBRUSHSTYLE_TRANSPARENT );
175 
176  DC->SetBrush( brush );
177 
179  s_DC_lastbrushfill = fill;
180  s_DC_lastDC = DC;
181  }
182 }
183 
184 
185 void GRForceBlackPen( bool flagforce )
186 {
187  s_ForceBlackPen = flagforce;
188 }
189 
190 
192 {
193  return s_ForceBlackPen;
194 }
195 
196 
197 void GRLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
198  const COLOR4D& Color, wxPenStyle aStyle)
199 {
200  GRSetColorPen( DC, Color, width, aStyle );
201  WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, width );
202  GRLastMoveToX = x2;
203  GRLastMoveToY = y2;
204 }
205 
206 
207 void GRLine( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
208  const COLOR4D& aColor, wxPenStyle aStyle )
209 {
210  GRLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, aColor, aStyle );
211 }
212 
213 
214 void GRMoveTo( int x, int y )
215 {
216  GRLastMoveToX = x;
217  GRLastMoveToY = y;
218 }
219 
220 
221 void GRLineTo( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int width, const COLOR4D& Color )
222 {
223  GRLine( ClipBox, DC, GRLastMoveToX, GRLastMoveToY, x, y, width, Color );
224 }
225 
226 
227 void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
228  int aPenSize, const COLOR4D& Color )
229 {
230  GRLastMoveToX = x2;
231  GRLastMoveToY = y2;
232 
233  if( ClipBox )
234  {
235  EDA_RECT clipbox( *ClipBox );
236  clipbox.Inflate( width / 2 );
237 
238  if( ClipLine( &clipbox, x1, y1, x2, y2 ) )
239  return;
240  }
241 
242  if( width <= 2 ) /* single line or 2 pixels */
243  {
244  GRSetColorPen( DC, Color, width );
245  DC->DrawLine( x1, y1, x2, y2 );
246  return;
247  }
248 
249  GRSetBrush( DC, Color, NOT_FILLED );
250  GRSetColorPen( DC, Color, aPenSize );
251 
252  int radius = ( width + 1 ) >> 1;
253  int dx = x2 - x1;
254  int dy = y2 - y1;
255  double angle = -ArcTangente( dy, dx );
256  wxPoint start;
257  wxPoint end;
258  wxPoint org( x1, y1 );
259  int len = (int) hypot( dx, dy );
260 
261  // We know if the DC is mirrored, to draw arcs
262  int slx = DC->DeviceToLogicalX( 1 ) - DC->DeviceToLogicalX( 0 );
263  int sly = DC->DeviceToLogicalY( 1 ) - DC->DeviceToLogicalY( 0 );
264  bool mirrored = ( slx > 0 && sly < 0 ) || ( slx < 0 && sly > 0 );
265 
266  // first edge
267  start.x = 0;
268  start.y = radius;
269  end.x = len;
270  end.y = radius;
271  RotatePoint( &start, angle );
272  RotatePoint( &end, angle );
273 
274  start += org;
275  end += org;
276 
277  DC->DrawLine( start, end );
278 
279  // first rounded end
280  end.x = 0;
281  end.y = -radius;
282  RotatePoint( &end, angle );
283  end += org;
284 
285  if( !mirrored )
286  DC->DrawArc( end, start, org );
287  else
288  DC->DrawArc( start, end, org );
289 
290  // second edge
291  start.x = len;
292  start.y = -radius;
293  RotatePoint( &start, angle );
294  start += org;
295 
296  DC->DrawLine( start, end );
297 
298  // second rounded end
299  end.x = len;
300  end.y = radius;
301  RotatePoint( &end, angle);
302  end += org;
303 
304  if( !mirrored )
305  DC->DrawArc( end.x, end.y, start.x, start.y, x2, y2 );
306  else
307  DC->DrawArc( start.x, start.y, end.x, end.y, x2, y2 );
308 }
309 
310 
311 void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
312  const COLOR4D& Color )
313 {
314  GRCSegm( ClipBox, DC, x1, y1, x2, y2, width, 0, Color );
315 }
316 
317 
318 void GRCSegm( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
319  const COLOR4D& aColor )
320 {
321  GRCSegm( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, 0, aColor );
322 }
323 
324 
325 void GRFillCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
326  const COLOR4D& Color )
327 {
328  GRSetColorPen( DC, Color, width );
329  WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, width );
330 }
331 
332 
333 void GRFilledSegment( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd,
334  int aWidth, const COLOR4D& aColor )
335 {
336  GRSetColorPen( aDC, aColor, aWidth );
337  WinClipAndDrawLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth );
338 }
339 
340 static bool IsGRSPolyDrawable( EDA_RECT* ClipBox, int n, const wxPoint* Points )
341 {
342  if( !ClipBox )
343  return true;
344 
345  if( n <= 0 )
346  return false;
347 
348  int Xmin, Xmax, Ymin, Ymax;
349 
350  Xmin = Xmax = Points[0].x;
351  Ymin = Ymax = Points[0].y;
352 
353  for( int ii = 1; ii < n; ii++ ) // calculate rectangle
354  {
355  Xmin = std::min( Xmin, Points[ii].x );
356  Xmax = std::max( Xmax, Points[ii].x );
357  Ymin = std::min( Ymin, Points[ii].y );
358  Ymax = std::max( Ymax, Points[ii].y );
359  }
360 
361  xcliplo = ClipBox->GetX();
362  ycliplo = ClipBox->GetY();
363  xcliphi = ClipBox->GetRight();
364  ycliphi = ClipBox->GetBottom();
365 
366  if( Xmax < xcliplo )
367  return false;
368  if( Xmin > xcliphi )
369  return false;
370  if( Ymax < ycliplo )
371  return false;
372  if( Ymin > ycliphi )
373  return false;
374 
375  return true;
376 }
377 
378 
382 static void GRSPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill,
383  int width, const COLOR4D& Color, const COLOR4D& BgColor )
384 {
385  if( !IsGRSPolyDrawable( ClipBox, n, Points ) )
386  return;
387 
388  if( Fill && ( n > 2 ) )
389  {
390  GRSetBrush( DC, BgColor, FILLED );
391  GRSetColorPen( DC, Color, width );
392 
393  /* clip before send the filled polygon to wxDC, because under linux
394  * (GTK?) polygons having large coordinates are incorrectly drawn
395  * (integer overflow in coordinates, I am guessing)
396  */
397  ClipAndDrawPoly( ClipBox, DC, Points, n );
398  }
399  else
400  {
401 
402  GRMoveTo( Points[0].x, Points[0].y );
403 
404  for( int i = 1; i < n; ++i )
405  {
406  GRLineTo( ClipBox, DC, Points[i].x, Points[i].y, width, Color );
407  }
408  }
409 }
410 
411 
415 static void GRSClosedPoly( EDA_RECT* aClipBox, wxDC* aDC, int aPointCount, const wxPoint* aPoints,
416  bool aFill, int aWidth, const COLOR4D& aColor, const COLOR4D& aBgColor )
417 {
418  if( !IsGRSPolyDrawable( aClipBox, aPointCount, aPoints ) )
419  return;
420 
421  if( aFill && ( aPointCount > 2 ) )
422  {
423  GRLastMoveToX = aPoints[aPointCount - 1].x;
424  GRLastMoveToY = aPoints[aPointCount - 1].y;
425  GRSetBrush( aDC, aBgColor, FILLED );
426  GRSetColorPen( aDC, aColor, aWidth );
427  ClipAndDrawPoly( aClipBox, aDC, aPoints, aPointCount );
428  }
429  else
430  {
431 
432  GRMoveTo( aPoints[0].x, aPoints[0].y );
433 
434  for( int i = 1; i < aPointCount; ++i )
435  {
436  GRLineTo( aClipBox, aDC, aPoints[i].x, aPoints[i].y, aWidth, aColor );
437  }
438 
439  int lastpt = aPointCount - 1;
440 
441  // Close the polygon
442  if( aPoints[lastpt] != aPoints[0] )
443  {
444  GRLineTo( aClipBox, aDC, aPoints[0].x, aPoints[0].y, aWidth, aColor );
445  }
446  }
447 }
448 
449 
453 void GRPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill, int width,
454  const COLOR4D& Color, const COLOR4D& BgColor )
455 {
456  GRSPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
457 }
458 
459 
463 void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill,
464  const COLOR4D& Color, const COLOR4D& BgColor )
465 {
466  GRClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor );
467 }
468 
469 
470 void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill, int width,
471  const COLOR4D& Color, const COLOR4D& BgColor )
472 {
473  GRSClosedPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
474 }
475 
476 
477 static bool clipCircle( EDA_RECT* aClipBox, int xc, int yc, int r, int aWidth )
478 {
479  // Clip circles that are outside the ClipBox.
480  if( aClipBox )
481  {
482  int x0, y0, xm, ym;
483  x0 = aClipBox->GetX();
484  y0 = aClipBox->GetY();
485  xm = aClipBox->GetRight();
486  ym = aClipBox->GetBottom();
487 
488  r += aWidth;
489 
490  if( xc < ( x0 - r ) )
491  return true;
492 
493  if( yc < ( y0 - r ) )
494  return true;
495 
496  if( xc > ( r + xm ) )
497  return true;
498 
499  if( yc > ( r + ym ) )
500  return true;
501  }
502 
503  return false;
504 }
505 
506 
507 void GRCircle( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, int r, int width, const COLOR4D& Color )
508 {
509  if( clipCircle( ClipBox, xc, yc, r, width ) || r <= 0 )
510  return;
511 
512  GRSetBrush( DC, Color, NOT_FILLED );
513  GRSetColorPen( DC, Color, width );
514 
515  // Draw two arcs here to make a circle. Unfortunately, the printerDC doesn't handle
516  // transparent brushes when used with circles. It does work for for arcs, however
517  DC->DrawArc(xc + r, yc, xc - r, yc, xc, yc);
518  DC->DrawArc(xc - r, yc, xc + r, yc, xc, yc);
519 }
520 
521 
522 void GRCircle( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aPos, int aRadius, int aWidth,
523  const COLOR4D& aColor )
524 {
525  GRCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, aWidth, aColor );
526 }
527 
528 
529 void GRFilledCircle( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int r, int width,
530  const COLOR4D& Color, const COLOR4D& BgColor )
531 {
532  if( clipCircle( ClipBox, x, y, r, width ) || r <= 0 )
533  return;
534 
535  GRSetBrush( DC, BgColor, FILLED );
536  GRSetColorPen( DC, Color, width );
537  DC->DrawEllipse( x - r, y - r, r + r, r + r );
538 }
539 
540 
541 void GRFilledCircle( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aPos, int aRadius,
542  const COLOR4D& aColor )
543 {
544  GRFilledCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, 0, aColor, aColor );
545 }
546 
547 
548 void GRArc1( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int xc, int yc,
549  int width, const COLOR4D& Color )
550 {
551  /* Clip arcs off screen. */
552  if( ClipBox )
553  {
554  int x0, y0, xm, ym, r;
555  x0 = ClipBox->GetX();
556  y0 = ClipBox->GetY();
557  xm = ClipBox->GetRight();
558  ym = ClipBox->GetBottom();
559  r = KiROUND( Distance( x1, y1, xc, yc ) );
560 
561  if( xc < ( x0 - r ) )
562  return;
563 
564  if( yc < ( y0 - r ) )
565  return;
566 
567  if( xc > ( r + xm ) )
568  return;
569 
570  if( yc > ( r + ym ) )
571  return;
572  }
573 
574  GRSetBrush( DC, Color );
575  GRSetColorPen( DC, Color, width );
576  DC->DrawArc( x1, y1, x2, y2, xc, yc );
577 }
578 
579 
580 void GRArc1( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd,
581  const wxPoint& aCenter, int aWidth, const COLOR4D& aColor )
582 {
583  GRArc1( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aCenter.x, aCenter.y,
584  aWidth, aColor );
585 }
586 
587 
588 void GRFilledArc1( EDA_RECT* ClipBox, wxDC* DC, const wxPoint& aStart, const wxPoint& aEnd,
589  const wxPoint& aCenter, int width, const COLOR4D& Color, const COLOR4D& BgColor )
590 {
591  /* Clip arcs off screen. */
592  if( ClipBox )
593  {
594  int x0, y0, xm, ym, r;
595  x0 = ClipBox->GetX();
596  y0 = ClipBox->GetY();
597  xm = ClipBox->GetRight();
598  ym = ClipBox->GetBottom();
599  r = KiROUND( Distance( aStart.x, aStart.y, aCenter.x, aCenter.y ) );
600 
601  if( aCenter.x < ( x0 - r ) )
602  return;
603 
604  if( aCenter.y < ( y0 - r ) )
605  return;
606 
607  if( aCenter.x > ( r + xm ) )
608  return;
609 
610  if( aCenter.y > ( r + ym ) )
611  return;
612  }
613 
614  GRSetBrush( DC, BgColor, FILLED );
615  GRSetColorPen( DC, Color, width );
616  DC->DrawArc( aStart.x, aStart.y, aEnd.x, aEnd.y, aCenter.x, aCenter.y );
617 }
618 
619 
620 void GRArc( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, double StAngle, double EndAngle, int r,
621  const COLOR4D& Color )
622 {
623  int x1, y1, x2, y2;
624 
625  /* Clip arcs off screen */
626  if( ClipBox )
627  {
628  int radius = r + 1;
629  int x0, y0, xm, ym, x, y;
630  x0 = ClipBox->GetX();
631  y0 = ClipBox->GetY();
632  xm = ClipBox->GetRight();
633  ym = ClipBox->GetBottom();
634  x = xc;
635  y = yc;
636 
637  if( x < ( x0 - radius ) )
638  return;
639 
640  if( y < ( y0 - radius ) )
641  return;
642 
643  if( x > ( xm + radius ) )
644  return;
645 
646  if( y > ( ym + radius ) )
647  return;
648  }
649 
650  x1 = r;
651  y1 = 0;
652  RotatePoint( &x1, &y1, EndAngle );
653 
654  x2 = r;
655  y2 = 0;
656  RotatePoint( &x2, &y2, StAngle );
657 
658  GRSetBrush( DC, Color, NOT_FILLED );
659  GRSetColorPen( DC, Color );
660  DC->DrawArc( xc + x1, yc - y1, xc + x2, yc - y2, xc, yc );
661 }
662 
663 
664 void GRArc( EDA_RECT* ClipBox, wxDC* DC, int x, int y, double StAngle, double EndAngle, int r,
665  int width, const COLOR4D& Color )
666 {
667  int x1, y1, x2, y2;
668 
669  /* Clip arcs off screen. */
670  if( ClipBox )
671  {
672  int x0, y0, xm, ym;
673  x0 = ClipBox->GetX();
674  y0 = ClipBox->GetY();
675  xm = ClipBox->GetRight();
676  ym = ClipBox->GetBottom();
677 
678  if( x < ( x0 - r - width ) )
679  return;
680 
681  if( y < ( y0 - r - width ) )
682  return;
683 
684  if( x > ( r + xm + width ) )
685  return;
686 
687  if( y > ( r + ym + width ) )
688  return;
689  }
690 
691  x1 = r;
692  y1 = 0;
693  RotatePoint( &x1, &y1, EndAngle );
694 
695  x2 = r;
696  y2 = 0;
697  RotatePoint( &x2, &y2, StAngle );
698 
699  GRSetBrush( DC, Color );
700  GRSetColorPen( DC, Color, width );
701  DC->DrawArc( x + x1, y - y1, x + x2, y - y2, x, y );
702 }
703 
704 
705 void GRRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
706  const COLOR4D& Color )
707 {
708  GRSRect( ClipBox, DC, x1, y1, x2, y2, width, Color );
709 }
710 
711 
712 void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
713  const COLOR4D& Color, const COLOR4D& BgColor )
714 {
715  GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, 0, Color, BgColor );
716 }
717 
718 
719 void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
720  const COLOR4D& Color, const COLOR4D& BgColor )
721 {
722  GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, width, Color, BgColor );
723 }
724 
725 
726 void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2, int aWidth,
727  const COLOR4D& aColor )
728 {
729  wxPoint points[5];
730  points[0] = wxPoint( x1, y1 );
731  points[1] = wxPoint( x1, y2 );
732  points[2] = wxPoint( x2, y2 );
733  points[3] = wxPoint( x2, y1 );
734  points[4] = points[0];
735  GRSClosedPoly( aClipBox, aDC, 5, points, NOT_FILLED, aWidth, aColor, aColor );
736 }
737 
738 
739 void GRSFilledRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2, int aWidth,
740  const COLOR4D& aColor, const COLOR4D& aBgColor )
741 {
742  wxPoint points[5];
743  points[0] = wxPoint( x1, y1 );
744  points[1] = wxPoint( x1, y2 );
745  points[2] = wxPoint( x2, y2 );
746  points[3] = wxPoint( x2, y1 );
747  points[4] = points[0];
748 
749  GRSetBrush( aDC, aBgColor, FILLED );
750  GRSetColorPen( aDC, aBgColor, aWidth );
751 
752  if( aClipBox && ( aWidth > 0 ) )
753  {
754  EDA_RECT clipbox( *aClipBox );
755  clipbox.Inflate( aWidth );
756  ClipAndDrawPoly( &clipbox, aDC, points, 5 ); // polygon approach is more accurate
757  }
758  else
759  {
760  ClipAndDrawPoly(aClipBox, aDC, points, 5 );
761  }
762 }
763 
773 #include <SutherlandHodgmanClipPoly.h>
774 
775 void ClipAndDrawPoly( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint* Points, int n )
776 {
777  if( aClipBox == nullptr )
778  {
779  aDC->DrawPolygon( n, Points );
780  return;
781  }
782 
783  // A clip box exists: clip and draw the polygon.
784  static std::vector<wxPoint> clippedPolygon;
785  static pointVector inputPolygon, outputPolygon;
786 
787  inputPolygon.clear();
788  outputPolygon.clear();
789  clippedPolygon.clear();
790 
791  for( int ii = 0; ii < n; ii++ )
792  inputPolygon.push_back( PointF( (REAL) Points[ii].x, (REAL) Points[ii].y ) );
793 
794  RectF window( (REAL) aClipBox->GetX(), (REAL) aClipBox->GetY(),
795  (REAL) aClipBox->GetWidth(), (REAL) aClipBox->GetHeight() );
796 
797  SutherlandHodgman sh( window );
798  sh.Clip( inputPolygon, outputPolygon );
799 
800  for( cpointIterator cit = outputPolygon.begin(); cit != outputPolygon.end(); ++cit )
801  {
802  clippedPolygon.emplace_back( KiROUND( cit->X ), KiROUND( cit->Y ) );
803  }
804 
805  if( clippedPolygon.size() )
806  aDC->DrawPolygon( clippedPolygon.size(), &clippedPolygon[0] );
807 }
808 
809 
GR_DRAWMODE g_XorMode
Definition: gr_basic.cpp:63
void GRResetPenAndBrush(wxDC *DC)
Definition: gr_basic.cpp:107
static int ycliplo
Definition: gr_basic.cpp:81
static const bool FILLED
Definition: gr_basic.cpp:32
void GRSetColorPen(wxDC *DC, const COLOR4D &Color, int width, wxPenStyle style)
Definition: gr_basic.cpp:115
static int ycliphi
Definition: gr_basic.cpp:83
void GRFilledRect(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, const COLOR4D &Color, const COLOR4D &BgColor)
Definition: gr_basic.cpp:712
int GetX() const
Definition: eda_rect.h:107
static bool clipCircle(EDA_RECT *aClipBox, int xc, int yc, int r, int aWidth)
Definition: gr_basic.cpp:477
int color
Definition: DXF_plotter.cpp:57
static void GRSPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Draw a new polyline and fill it if Fill, in screen space.
Definition: gr_basic.cpp:382
int GetWidth() const
Definition: eda_rect.h:118
static void GRSClosedPoly(EDA_RECT *aClipBox, wxDC *aDC, int aPointCount, const wxPoint *aPoints, bool aFill, int aWidth, const COLOR4D &aColor, const COLOR4D &aBgColor)
Draw a new closed polyline and fill it if Fill, in screen space.
Definition: gr_basic.cpp:415
void GRRect(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:705
Definition: color4d.h:44
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
static int xcliphi
Definition: gr_basic.cpp:82
static int GRLastMoveToX
Definition: gr_basic.cpp:77
bool ClipLine(const EDA_RECT *aClipBox, int &x1, int &y1, int &x2, int &y2)
Test if any part of a line falls within the bounds of a rectangle.
int GetBottom() const
Definition: eda_rect.h:123
void GRSetBrush(wxDC *DC, const COLOR4D &Color, bool fill)
Definition: gr_basic.cpp:158
static int xcliplo
Definition: gr_basic.cpp:80
static const bool NOT_FILLED
Definition: gr_basic.cpp:33
void GRArc(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, double StAngle, double EndAngle, int r, const COLOR4D &Color)
Definition: gr_basic.cpp:620
static int GRLastMoveToY
Definition: gr_basic.cpp:77
void GRForceBlackPen(bool flagforce)
Definition: gr_basic.cpp:185
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:39
static void WinClipAndDrawLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width)
Definition: gr_basic.cpp:89
static wxDC * s_DC_lastDC
Definition: gr_basic.cpp:87
int GetRight() const
Definition: eda_rect.h:120
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, const COLOR4D &Color)
Draw a circle onto the drawing context aDC centered at the user coordinates (x,y).
Definition: gr_basic.cpp:507
void GRFillCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:325
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, const COLOR4D &Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:197
a few functions useful in geometry calculations.
static bool IsGRSPolyDrawable(EDA_RECT *ClipBox, int n, const wxPoint *Points)
Definition: gr_basic.cpp:340
void GRFilledSegment(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aStart, const wxPoint &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:333
E_SERIE r
Definition: eserie.cpp:41
void GRClosedPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, const COLOR4D &Color, const COLOR4D &BgColor)
Draw a closed polyline and fill it if Fill, in object space.
Definition: gr_basic.cpp:463
static void GRSRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:726
int GetHeight() const
Definition: eda_rect.h:119
static COLOR4D s_DC_lastbrushcolor(0, 0, 0, 0)
void GRLineTo(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:221
void GRMoveTo(int x, int y)
Definition: gr_basic.cpp:214
static void ClipAndDrawPoly(EDA_RECT *ClipBox, wxDC *DC, const wxPoint *Points, int n)
Used to clip a polygon and draw it as Filled Polygon.
Definition: gr_basic.cpp:775
void GRArc1(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int xc, int yc, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:548
void GRFilledArc1(EDA_RECT *ClipBox, wxDC *DC, const wxPoint &aStart, const wxPoint &aEnd, const wxPoint &aCenter, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Definition: gr_basic.cpp:588
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
Handle the component boundary box.
Definition: eda_rect.h:42
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:73
int GetY() const
Definition: eda_rect.h:108
void GRPoly(EDA_RECT *ClipBox, wxDC *DC, int n, const wxPoint *Points, bool Fill, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Draw a new polyline and fill it if Fill, in drawing space.
Definition: gr_basic.cpp:453
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
bool GetGRForceBlackPenState(void)
Definition: gr_basic.cpp:191
static bool s_DC_lastbrushfill
Definition: gr_basic.cpp:86
void GRSFilledRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D &aColor, const COLOR4D &aBgColor)
Definition: gr_basic.cpp:739
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:364
static bool s_ForceBlackPen
Definition: gr_basic.cpp:78
void GRFilledCircle(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int r, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Definition: gr_basic.cpp:529
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
void GRCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, int aPenSize, const COLOR4D &Color)
Definition: gr_basic.cpp:227