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 <stambaughw@gmail.com>
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 <base_screen.h>
26 #include <bezier_curves.h>
27 #include <math_for_graphics.h>
28 #include <wx/graphics.h>
30 #include <math/util.h> // for KiROUND
31 
32 #include <algorithm>
33 
34 static const bool FILLED = true;
35 static const bool NOT_FILLED = false;
36 
37 /* Important Note:
38  * These drawing functions clip draw item before send these items to wxDC draw
39  * functions. For guy who asks why i did it, see a sample of problems encountered
40  * when pixels
41  * coordinates overflow 16 bits values:
42  * http://trac.wxwidgets.org/ticket/10446
43  * Problems can be found under Windows **and** Linux (mainly when drawing arcs)
44  * (mainly at low zoom values (2, 1 or 0.5), in Pcbnew)
45  * some of these problems could be now fixed in recent distributions.
46  *
47  * Currently (feb 2009) there are overflow problems when drawing solid (filled)
48  * polygons under linux without clipping
49  *
50  * So before removing clipping functions, be aware these bug (they are not in
51  * KiCad or wxWidgets) are fixed by testing how are drawn complex lines arcs
52  * and solid polygons under Windows and Linux and remember users can have old
53  * versions with bugs
54  */
55 
56 
57 /* Definitions for enabling and disabling debugging features in gr_basic.cpp.
58  * Please remember to set these back to 0 before making LAUNCHPAD commits.
59  */
60 #define DEBUG_DUMP_CLIP_ERROR_COORDS 0 // Set to 1 to dump clip algorithm errors.
61 #define DEBUG_DUMP_CLIP_COORDS 0 // Set to 1 to dump clipped coordinates.
62 
63 
64 // For draw mode = XOR GR_XOR or GR_NXOR by background color
66 
67 
68 static void ClipAndDrawPoly( EDA_RECT* ClipBox, wxDC* DC, const wxPoint* Points, int n );
69 
70 /* These functions are used by corresponding functions
71  * ( GRSCircle is called by GRCircle for instance) after mapping coordinates
72  * from user units to screen units(pixels coordinates)
73  */
74 static void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1,
75  int x2, int y2, int aWidth, const COLOR4D& aColor,
76  wxPenStyle aStyle = wxPENSTYLE_SOLID );
77 
78 
79 
81 static bool s_ForceBlackPen; /* if true: draws in black instead of
82  * color for printing. */
83 static int xcliplo = 0,
84  ycliplo = 0,
85  xcliphi = 2000,
86  ycliphi = 2000;
87 
88 static COLOR4D s_DC_lastcolor( 0, 0, 0, 0 );
89 static COLOR4D s_DC_lastbrushcolor( 0, 0, 0, 0 );
90 static bool s_DC_lastbrushfill = false;
91 static wxDC* s_DC_lastDC = nullptr;
92 
93 static void WinClipAndDrawLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
94  int width )
95 {
96  GRLastMoveToX = x2;
97  GRLastMoveToY = y2;
98 
99  if( ClipBox )
100  {
101  EDA_RECT clipbox(*ClipBox);
102  clipbox.Inflate(width/2);
103  if( ClipLine( &clipbox, x1, y1, x2, y2 ) )
104  return;
105  }
106 
107  DC->DrawLine( x1, y1, x2, y2 );
108 }
109 
110 
111 void GRResetPenAndBrush( wxDC* DC )
112 {
113  GRSetBrush( DC, BLACK ); // Force no fill
114  s_DC_lastbrushcolor = COLOR4D::UNSPECIFIED;
115  s_DC_lastcolor = COLOR4D::UNSPECIFIED;
116  s_DC_lastDC = nullptr;
117 }
118 
119 
120 void GRSetColorPen( wxDC* DC, const COLOR4D& Color, int width, wxPenStyle style )
121 {
122  COLOR4D color = Color;
123 
124  wxDash dots[2] = { 1, 3 };
125 
126  // Under OSX and while printing when wxPen is set to 0, renderer follows the request drawing
127  // nothing & in the bitmap world the minimum is enough to light a pixel, in vectorial one not
128  if( width <= 1 )
129  width = DC->DeviceToLogicalXRel( 1 );
130 
131  if( s_ForceBlackPen )
133 
134  const wxPen& curr_pen = DC->GetPen();
135 
136  if( !curr_pen.IsOk() || curr_pen.GetColour() != color.ToColour()
137  || curr_pen.GetWidth() != width || curr_pen.GetStyle() != style )
138  {
139  wxPen pen;
140  pen.SetColour( color.ToColour() );
141 
142  if( style == wxPENSTYLE_DOT )
143  {
144  style = wxPENSTYLE_USER_DASH;
145  pen.SetDashes( 2, dots );
146  }
147 
148  pen.SetWidth( width );
149  pen.SetStyle( style );
150  DC->SetPen( pen );
151  }
152  else
153  {
154  // Should be not needed, but on Linux, in printing process
155  // the curr pen settings needs to be sometimes re-initialized
156  // Clearly, this is due to a bug, related to SetBrush(),
157  // but we have to live with it, at least on wxWidgets 3.0
158  DC->SetPen( curr_pen );
159  }
160 }
161 
162 
163 void GRSetBrush( wxDC* DC, const COLOR4D& Color, bool fill )
164 {
165  COLOR4D color = Color;
166 
167  if( s_ForceBlackPen )
169 
170  if( s_DC_lastbrushcolor != color || s_DC_lastbrushfill != fill || s_DC_lastDC != DC )
171  {
172  wxBrush brush;
173 
174  brush.SetColour( color.ToColour() );
175 
176  if( fill )
177  brush.SetStyle( wxBRUSHSTYLE_SOLID );
178  else
179  brush.SetStyle( wxBRUSHSTYLE_TRANSPARENT );
180 
181  DC->SetBrush( brush );
182 
184  s_DC_lastbrushfill = fill;
185  s_DC_lastDC = DC;
186  }
187 }
188 
189 
190 void GRForceBlackPen( bool flagforce )
191 {
192  s_ForceBlackPen = flagforce;
193 }
194 
195 
197 {
198  return s_ForceBlackPen;
199 }
200 
201 
202 void GRPutPixel( EDA_RECT* ClipBox, wxDC* DC, int x, int y, const COLOR4D& Color )
203 {
204  if( ClipBox && !ClipBox->Contains( x, y ) )
205  return;
206 
207  GRSetColorPen( DC, Color );
208  DC->DrawPoint( x, y );
209 }
210 
211 
212 void GRLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
213  const COLOR4D& Color, wxPenStyle aStyle)
214 {
215  GRSetColorPen( DC, Color, width, aStyle );
216  WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, width );
217  GRLastMoveToX = x2;
218  GRLastMoveToY = y2;
219 }
220 
221 
222 void GRLine( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
223  const COLOR4D& aColor, wxPenStyle aStyle )
224 {
225  GRLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, aColor, aStyle );
226 }
227 
228 
229 void GRMoveTo( int x, int y )
230 {
231  GRLastMoveToX = x;
232  GRLastMoveToY = y;
233 }
234 
235 
236 void GRLineTo( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int width, const COLOR4D& Color )
237 {
238  GRLine( ClipBox, DC, GRLastMoveToX, GRLastMoveToY, x, y, width, Color );
239 }
240 
241 
242 void GRLineArray( EDA_RECT* aClipBox, wxDC* aDC, std::vector<wxPoint>& aLines,
243  int aWidth, const COLOR4D& aColor )
244 {
245  if( aLines.empty() )
246  return;
247 
248  GRSetColorPen( aDC, aColor, aWidth );
249 
250  if( aClipBox )
251  aClipBox->Inflate( aWidth / 2 );
252 
253  for( unsigned i = 0; i < aLines.size(); i += 2 )
254  {
255  int x1 = aLines[i].x;
256  int y1 = aLines[i].y;
257  int x2 = aLines[i + 1].x;
258  int y2 = aLines[i + 1].y;
259 
260  if( ( aClipBox == nullptr ) || !ClipLine( aClipBox, x1, y1, x2, y2 ) )
261  aDC->DrawLine( x1, y1, x2, y2 );
262  }
263 
264  GRMoveTo( aLines[aLines.size() - 1].x, aLines[aLines.size() - 1].y );
265 
266  if( aClipBox )
267  aClipBox->Inflate( -aWidth / 2 );
268 }
269 
270 
271 void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
272  int aPenSize, const COLOR4D& Color )
273 {
274  GRLastMoveToX = x2;
275  GRLastMoveToY = y2;
276 
277  if( ClipBox )
278  {
279  EDA_RECT clipbox( *ClipBox );
280  clipbox.Inflate( width / 2 );
281 
282  if( ClipLine( &clipbox, x1, y1, x2, y2 ) )
283  return;
284  }
285 
286  if( width <= 2 ) /* single line or 2 pixels */
287  {
288  GRSetColorPen( DC, Color, width );
289  DC->DrawLine( x1, y1, x2, y2 );
290  return;
291  }
292 
293  GRSetBrush( DC, Color, NOT_FILLED );
294  GRSetColorPen( DC, Color, aPenSize );
295 
296  int radius = ( width + 1 ) >> 1;
297  int dx = x2 - x1;
298  int dy = y2 - y1;
299  double angle = -ArcTangente( dy, dx );
300  wxPoint start;
301  wxPoint end;
302  wxPoint org( x1, y1 );
303  int len = (int) hypot( dx, dy );
304 
305  // We know if the DC is mirrored, to draw arcs
306  int slx = DC->DeviceToLogicalX( 1 ) - DC->DeviceToLogicalX( 0 );
307  int sly = DC->DeviceToLogicalY( 1 ) - DC->DeviceToLogicalY( 0 );
308  bool mirrored = ( slx > 0 && sly < 0 ) || ( slx < 0 && sly > 0 );
309 
310  // first edge
311  start.x = 0;
312  start.y = radius;
313  end.x = len;
314  end.y = radius;
315  RotatePoint( &start, angle );
316  RotatePoint( &end, angle );
317 
318  start += org;
319  end += org;
320 
321  DC->DrawLine( start, end );
322 
323  // first rounded end
324  end.x = 0;
325  end.y = -radius;
326  RotatePoint( &end, angle );
327  end += org;
328 
329  if( !mirrored )
330  DC->DrawArc( end, start, org );
331  else
332  DC->DrawArc( start, end, org );
333 
334  // second edge
335  start.x = len;
336  start.y = -radius;
337  RotatePoint( &start, angle );
338  start += org;
339 
340  DC->DrawLine( start, end );
341 
342  // second rounded end
343  end.x = len;
344  end.y = radius;
345  RotatePoint( &end, angle);
346  end += org;
347 
348  if( !mirrored )
349  DC->DrawArc( end.x, end.y, start.x, start.y, x2, y2 );
350  else
351  DC->DrawArc( start.x, start.y, end.x, end.y, x2, y2 );
352 }
353 
354 
355 void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
356  const COLOR4D& Color )
357 {
358  GRCSegm( ClipBox, DC, x1, y1, x2, y2, width, 0, Color );
359 }
360 
361 
362 void GRCSegm( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd, int aWidth,
363  const COLOR4D& aColor )
364 {
365  GRCSegm( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, 0, aColor );
366 }
367 
368 
369 void GRFillCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
370  int width, const COLOR4D& Color )
371 {
372  GRSetColorPen( DC, Color, width );
373  WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, width );
374 }
375 
376 
377 void GRFilledSegment( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd,
378  int aWidth, const COLOR4D& aColor )
379 {
380  GRSetColorPen( aDC, aColor, aWidth );
381  WinClipAndDrawLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth );
382 }
383 
384 static bool IsGRSPolyDrawable( EDA_RECT* ClipBox, int n, const wxPoint* Points )
385 {
386  if( !ClipBox )
387  return true;
388 
389  if( n <= 0 )
390  return false;
391 
392  int Xmin, Xmax, Ymin, Ymax;
393 
394  Xmin = Xmax = Points[0].x;
395  Ymin = Ymax = Points[0].y;
396 
397  for( int ii = 1; ii < n; ii++ ) // calculate rectangle
398  {
399  Xmin = std::min( Xmin, Points[ii].x );
400  Xmax = std::max( Xmax, Points[ii].x );
401  Ymin = std::min( Ymin, Points[ii].y );
402  Ymax = std::max( Ymax, Points[ii].y );
403  }
404 
405  xcliplo = ClipBox->GetX();
406  ycliplo = ClipBox->GetY();
407  xcliphi = ClipBox->GetRight();
408  ycliphi = ClipBox->GetBottom();
409 
410  if( Xmax < xcliplo )
411  return false;
412  if( Xmin > xcliphi )
413  return false;
414  if( Ymax < ycliplo )
415  return false;
416  if( Ymin > ycliphi )
417  return false;
418 
419  return true;
420 }
421 
422 
426 static void GRSPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill,
427  int width, const COLOR4D& Color, const COLOR4D& BgColor )
428 {
429  if( !IsGRSPolyDrawable( ClipBox, n, Points ) )
430  return;
431 
432  if( Fill && ( n > 2 ) )
433  {
434  GRSetBrush( DC, BgColor, FILLED );
435  GRSetColorPen( DC, Color, width );
436 
437  /* clip before send the filled polygon to wxDC, because under linux
438  * (GTK?) polygons having large coordinates are incorrectly drawn
439  * (integer overflow in coordinates, I am guessing)
440  */
441  ClipAndDrawPoly( ClipBox, DC, Points, n );
442  }
443  else
444  {
445 
446  GRMoveTo( Points[0].x, Points[0].y );
447 
448  for( int i = 1; i < n; ++i )
449  {
450  GRLineTo( ClipBox, DC, Points[i].x, Points[i].y, width, Color );
451  }
452  }
453 }
454 
455 
459 static void GRSClosedPoly( EDA_RECT* aClipBox, wxDC* aDC, int aPointCount, const wxPoint* aPoints,
460  bool aFill, int aWidth, const COLOR4D& aColor, const COLOR4D& aBgColor )
461 {
462  if( !IsGRSPolyDrawable( aClipBox, aPointCount, aPoints ) )
463  return;
464 
465  if( aFill && ( aPointCount > 2 ) )
466  {
467  GRLastMoveToX = aPoints[aPointCount - 1].x;
468  GRLastMoveToY = aPoints[aPointCount - 1].y;
469  GRSetBrush( aDC, aBgColor, FILLED );
470  GRSetColorPen( aDC, aColor, aWidth );
471  ClipAndDrawPoly( aClipBox, aDC, aPoints, aPointCount );
472  }
473  else
474  {
475 
476  GRMoveTo( aPoints[0].x, aPoints[0].y );
477 
478  for( int i = 1; i < aPointCount; ++i )
479  {
480  GRLineTo( aClipBox, aDC, aPoints[i].x, aPoints[i].y, aWidth, aColor );
481  }
482 
483  int lastpt = aPointCount - 1;
484 
485  // Close the polygon
486  if( aPoints[lastpt] != aPoints[0] )
487  {
488  GRLineTo( aClipBox, aDC, aPoints[0].x, aPoints[0].y, aWidth, aColor );
489  }
490  }
491 }
492 
493 
497 void GRPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill, int width,
498  const COLOR4D& Color, const COLOR4D& BgColor )
499 {
500  GRSPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
501 }
502 
503 
507 void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill,
508  const COLOR4D& Color, const COLOR4D& BgColor )
509 {
510  GRClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor );
511 }
512 
513 
514 void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, const wxPoint* Points, bool Fill, int width,
515  const COLOR4D& Color, const COLOR4D& BgColor )
516 {
517  GRSClosedPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
518 }
519 
520 
521 static bool clipCircle( EDA_RECT* aClipBox, int xc, int yc, int r, int aWidth )
522 {
523  // Clip circles that are outside the ClipBox.
524  if( aClipBox )
525  {
526  int x0, y0, xm, ym;
527  x0 = aClipBox->GetX();
528  y0 = aClipBox->GetY();
529  xm = aClipBox->GetRight();
530  ym = aClipBox->GetBottom();
531 
532  r += aWidth;
533 
534  if( xc < ( x0 - r ) )
535  return true;
536 
537  if( yc < ( y0 - r ) )
538  return true;
539 
540  if( xc > ( r + xm ) )
541  return true;
542 
543  if( yc > ( r + ym ) )
544  return true;
545  }
546 
547  return false;
548 }
549 
550 
551 void GRCircle( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, int r, int width, const COLOR4D& Color )
552 {
553  if( clipCircle( ClipBox, xc, yc, r, width ) || r <= 0 )
554  return;
555 
556  GRSetBrush( DC, Color, NOT_FILLED );
557  GRSetColorPen( DC, Color, width );
558  DC->DrawEllipse( xc - r, yc - r, r + r, r + r );
559 }
560 
561 
562 void GRCircle( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int r, const COLOR4D& Color )
563 {
564  GRCircle( ClipBox, DC, x, y, r, 0, Color );
565 }
566 
567 
568 void GRCircle( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aPos, int aRadius, int aWidth,
569  const COLOR4D& aColor )
570 {
571  GRCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, aWidth, aColor );
572 }
573 
574 
575 void GRFilledCircle( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int r, int width,
576  const COLOR4D& Color, const COLOR4D& BgColor )
577 {
578  if( clipCircle( ClipBox, x, y, r, width ) || r <= 0 )
579  return;
580 
581  GRSetBrush( DC, BgColor, FILLED );
582  GRSetColorPen( DC, Color, width );
583  DC->DrawEllipse( x - r, y - r, r + r, r + r );
584 }
585 
586 
587 void GRFilledCircle( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aPos, int aRadius,
588  const COLOR4D& aColor )
589 {
590  GRFilledCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, 0, aColor, aColor );
591 }
592 
593 
594 void GRArc1( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int xc, int yc,
595  const COLOR4D& Color )
596 {
597  GRArc1( ClipBox, DC, x1, y1, x2, y2, xc, yc, 0, Color );
598 }
599 
600 
601 void GRArc1( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int xc, int yc,
602  int width, const COLOR4D& Color )
603 {
604  /* Clip arcs off screen. */
605  if( ClipBox )
606  {
607  int x0, y0, xm, ym, r;
608  x0 = ClipBox->GetX();
609  y0 = ClipBox->GetY();
610  xm = ClipBox->GetRight();
611  ym = ClipBox->GetBottom();
612  r = KiROUND( Distance( x1, y1, xc, yc ) );
613 
614  if( xc < ( x0 - r ) )
615  return;
616 
617  if( yc < ( y0 - r ) )
618  return;
619 
620  if( xc > ( r + xm ) )
621  return;
622 
623  if( yc > ( r + ym ) )
624  return;
625  }
626 
627  GRSetBrush( DC, Color );
628  GRSetColorPen( DC, Color, width );
629  DC->DrawArc( x1, y1, x2, y2, xc, yc );
630 }
631 
632 
633 void GRArc1( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint& aStart, const wxPoint& aEnd,
634  const wxPoint& aCenter, int aWidth, const COLOR4D& aColor )
635 {
636  GRArc1( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aCenter.x, aCenter.y,
637  aWidth, aColor );
638 }
639 
640 
641 void GRFilledArc( EDA_RECT* ClipBox, wxDC* DC, int x, int y, double StAngle, double EndAngle,
642  int r, int width, const COLOR4D& Color, const COLOR4D& BgColor )
643 {
644  int x1, y1, x2, y2;
645 
646  /* Clip arcs off screen */
647  if( ClipBox )
648  {
649  int x0, y0, xm, ym;
650  x0 = ClipBox->GetX();
651  y0 = ClipBox->GetY();
652  xm = ClipBox->GetRight();
653  ym = ClipBox->GetBottom();
654 
655  if( x < ( x0 - r - 1 ) )
656  return;
657 
658  if( y < ( y0 - r - 1 ) )
659  return;
660 
661  if( x > ( r + xm + 1 ) )
662  return;
663 
664  if( y > ( r + ym + 1 ) )
665  return;
666  }
667 
668  x1 = r;
669  y1 = 0;
670  RotatePoint( &x1, &y1, EndAngle );
671 
672  x2 = r;
673  y2 = 0;
674  RotatePoint( &x2, &y2, StAngle );
675 
676  GRSetBrush( DC, BgColor, FILLED );
677  GRSetColorPen( DC, Color, width );
678  DC->DrawArc( x + x1, y - y1, x + x2, y - y2, x, y );
679 }
680 
681 
682 void GRFilledArc( EDA_RECT* ClipBox, wxDC* DC, int x, int y, double StAngle, double EndAngle,
683  int r, const COLOR4D& Color, const COLOR4D& BgColor )
684 {
685  GRFilledArc( ClipBox, DC, x, y, StAngle, EndAngle, r, 0, Color, BgColor );
686 }
687 
688 
689 void GRArc( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, double StAngle, double EndAngle, int r,
690  const COLOR4D& Color )
691 {
692  int x1, y1, x2, y2;
693 
694  /* Clip arcs off screen */
695  if( ClipBox )
696  {
697  int radius = r + 1;
698  int x0, y0, xm, ym, x, y;
699  x0 = ClipBox->GetX();
700  y0 = ClipBox->GetY();
701  xm = ClipBox->GetRight();
702  ym = ClipBox->GetBottom();
703  x = xc;
704  y = yc;
705 
706  if( x < ( x0 - radius ) )
707  return;
708 
709  if( y < ( y0 - radius ) )
710  return;
711 
712  if( x > ( xm + radius ) )
713  return;
714 
715  if( y > ( ym + radius ) )
716  return;
717  }
718 
719  x1 = r;
720  y1 = 0;
721  RotatePoint( &x1, &y1, EndAngle );
722 
723  x2 = r;
724  y2 = 0;
725  RotatePoint( &x2, &y2, StAngle );
726 
727  GRSetBrush( DC, Color, NOT_FILLED );
728  GRSetColorPen( DC, Color );
729  DC->DrawArc( xc + x1, yc - y1, xc + x2, yc - y2, xc, yc );
730 }
731 
732 
733 void GRArc( EDA_RECT* ClipBox, wxDC* DC, int x, int y, double StAngle, double EndAngle,
734  int r, int width, const COLOR4D& Color )
735 {
736  int x1, y1, x2, y2;
737 
738  /* Clip arcs off screen. */
739  if( ClipBox )
740  {
741  int x0, y0, xm, ym;
742  x0 = ClipBox->GetX();
743  y0 = ClipBox->GetY();
744  xm = ClipBox->GetRight();
745  ym = ClipBox->GetBottom();
746 
747  if( x < ( x0 - r - width ) )
748  return;
749 
750  if( y < ( y0 - r - width ) )
751  return;
752 
753  if( x > ( r + xm + width ) )
754  return;
755 
756  if( y > ( r + ym + width ) )
757  return;
758  }
759 
760  x1 = r;
761  y1 = 0;
762  RotatePoint( &x1, &y1, EndAngle );
763 
764  x2 = r;
765  y2 = 0;
766  RotatePoint( &x2, &y2, StAngle );
767 
768  GRSetBrush( DC, Color );
769  GRSetColorPen( DC, Color, width );
770  DC->DrawArc( x + x1, y - y1, x + x2, y - y2, x, y );
771 }
772 
773 
774 void GRRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2, const COLOR4D& aColor )
775 {
776  GRSRect( aClipBox, aDC, x1, y1, x2, y2, 0, aColor );
777 }
778 
779 
780 void GRRectPs( EDA_RECT* aClipBox, wxDC* aDC, const EDA_RECT& aRect, const COLOR4D& aColor,
781  wxPenStyle aStyle )
782 {
783  int x1 = aRect.GetX();
784  int y1 = aRect.GetY();
785  int x2 = aRect.GetRight();
786  int y2 = aRect.GetBottom();
787 
788  GRSRect( aClipBox, aDC, x1, y1, x2, y2, 0, aColor, aStyle );
789 }
790 
791 
792 void GRRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width,
793  const COLOR4D& Color )
794 {
795  GRSRect( ClipBox, DC, x1, y1, x2, y2, width, Color );
796 }
797 
798 
799 void GRRect( EDA_RECT* aClipBox, wxDC* aDC, const EDA_RECT& aRect, int aWidth,
800  const COLOR4D& aColor )
801 {
802  int x1 = aRect.GetX();
803  int y1 = aRect.GetY();
804  int x2 = aRect.GetRight();
805  int y2 = aRect.GetBottom();
806 
807  GRSRect( aClipBox, aDC, x1, y1, x2, y2, aWidth, aColor );
808 }
809 
810 
811 void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
812  const COLOR4D& Color, const COLOR4D& BgColor )
813 {
814  GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, 0, Color, BgColor );
815 }
816 
817 
818 void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
819  int width, const COLOR4D& Color, const COLOR4D& BgColor )
820 {
821  GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, width, Color, BgColor );
822 }
823 
824 
825 void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2,
826  int aWidth, const COLOR4D& aColor, wxPenStyle aStyle )
827 {
828  wxPoint points[5];
829  points[0] = wxPoint( x1, y1 );
830  points[1] = wxPoint( x1, y2 );
831  points[2] = wxPoint( x2, y2 );
832  points[3] = wxPoint( x2, y1 );
833  points[4] = points[0];
834  GRSClosedPoly( aClipBox, aDC, 5, points, NOT_FILLED, aWidth, aColor, aColor );
835 }
836 
837 
838 void GRSFilledRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2,
839  int aWidth, const COLOR4D& aColor, const COLOR4D& aBgColor )
840 {
841  wxPoint points[5];
842  points[0] = wxPoint( x1, y1 );
843  points[1] = wxPoint( x1, y2 );
844  points[2] = wxPoint( x2, y2 );
845  points[3] = wxPoint( x2, y1 );
846  points[4] = points[0];
847 
848  GRSetBrush( aDC, aBgColor, FILLED );
849  GRSetColorPen( aDC, aBgColor, aWidth );
850 
851  if( aClipBox && ( aWidth > 0 ) )
852  {
853  EDA_RECT clipbox( *aClipBox );
854  clipbox.Inflate( aWidth );
855  ClipAndDrawPoly( &clipbox, aDC, points, 5 ); // polygon approach is more accurate
856  }
857  else
858  {
859  ClipAndDrawPoly(aClipBox, aDC, points, 5 );
860  }
861 }
862 
872 #include <SutherlandHodgmanClipPoly.h>
873 
874 void ClipAndDrawPoly( EDA_RECT* aClipBox, wxDC* aDC, const wxPoint* Points, int n )
875 {
876  if( aClipBox == nullptr )
877  {
878  aDC->DrawPolygon( n, Points );
879  return;
880  }
881 
882  // A clip box exists: clip and draw the polygon.
883  static std::vector<wxPoint> clippedPolygon;
884  static pointVector inputPolygon, outputPolygon;
885 
886  inputPolygon.clear();
887  outputPolygon.clear();
888  clippedPolygon.clear();
889 
890  for( int ii = 0; ii < n; ii++ )
891  inputPolygon.push_back( PointF( (REAL) Points[ii].x, (REAL) Points[ii].y ) );
892 
893  RectF window( (REAL) aClipBox->GetX(), (REAL) aClipBox->GetY(),
894  (REAL) aClipBox->GetWidth(), (REAL) aClipBox->GetHeight() );
895 
896  SutherlandHodgman sh( window );
897  sh.Clip( inputPolygon, outputPolygon );
898 
899  for( cpointIterator cit = outputPolygon.begin(); cit != outputPolygon.end(); ++cit )
900  {
901  clippedPolygon.emplace_back( KiROUND( cit->X ), KiROUND( cit->Y ) );
902  }
903 
904  if( clippedPolygon.size() )
905  aDC->DrawPolygon( clippedPolygon.size(), &clippedPolygon[0] );
906 }
907 
908 
909 void GRBezier( EDA_RECT* aClipBox, wxDC* aDC, std::vector<wxPoint>& aPoint,
910  int aWidth, const COLOR4D& aColor )
911 {
912  std::vector<wxPoint> output;
913 
914  BEZIER_POLY converter( aPoint );
915  converter.GetPoly( output, aWidth );
916 
917  GRPoly( aClipBox, aDC, output.size(), &output[0], false, aWidth, aColor, aColor );
918 }
919 
920 
921 void GRDrawAnchor( EDA_RECT *aClipBox, wxDC *aDC, int x, int y, int aSize, const COLOR4D& aColor )
922 {
923  int anchor_size = aDC->DeviceToLogicalXRel( aSize );
924 
925  GRLine( aClipBox, aDC, x - anchor_size, y, x + anchor_size, y, 0, aColor );
926  GRLine( aClipBox, aDC, x, y - anchor_size, x, y + anchor_size, 0, aColor );
927 }
928 
929 
930 void GRDrawWrappedText( wxDC& aDC, wxString const& aText )
931 {
932  wxStringTokenizer tokenizer( aText, " " );
933  wxSize const dc_size = aDC.GetSize();
934  wxSize const margin = aDC.GetTextExtent( " " );
935  std::vector<wxString> lines;
936  wxString line_accumulator;
937  int total_height = 0;
938 
939  while( tokenizer.HasMoreTokens() )
940  {
941  wxString word = tokenizer.GetNextToken();
942  wxSize linesize = aDC.GetTextExtent( line_accumulator + " " + word );
943 
944  if( linesize.x >= dc_size.x - margin.x && !line_accumulator.IsEmpty() )
945  {
946  lines.push_back( line_accumulator );
947  line_accumulator = word;
948  }
949  else
950  {
951  line_accumulator += " ";
952  line_accumulator += word;
953  }
954  }
955 
956  if( !line_accumulator.IsEmpty() )
957  {
958  lines.push_back( line_accumulator );
959  }
960 
961  for( auto const& line: lines )
962  {
963  wxSize linesize = aDC.GetTextExtent( line );
964  total_height += linesize.y;
965  }
966 
967  int top = ( dc_size.y - total_height ) / 2;
968  int pos = top;
969 
970  for( auto const& line: lines )
971  {
972  wxSize linesize = aDC.GetTextExtent( line );
973  aDC.DrawText( line, ( dc_size.x - linesize.x ) / 2, pos );
974  pos += linesize.y;
975  }
976 }
GR_DRAWMODE g_XorMode
Definition: gr_basic.cpp:65
void GRResetPenAndBrush(wxDC *DC)
Definition: gr_basic.cpp:111
static int ycliplo
Definition: gr_basic.cpp:84
static const bool FILLED
Definition: gr_basic.cpp:34
void GRSetColorPen(wxDC *DC, const COLOR4D &Color, int width, wxPenStyle style)
Definition: gr_basic.cpp:120
void GRDrawWrappedText(wxDC &aDC, wxString const &aText)
Draw text centered on a wxDC with wrapping.
Definition: gr_basic.cpp:930
static int ycliphi
Definition: gr_basic.cpp:86
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:811
int GetX() const
Definition: eda_rect.h:98
static bool clipCircle(EDA_RECT *aClipBox, int xc, int yc, int r, int aWidth)
Definition: gr_basic.cpp:521
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Convert a Bezier curve to a polygon.
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:426
int GetWidth() const
Definition: eda_rect.h:109
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:459
void GRLineArray(EDA_RECT *aClipBox, wxDC *aDC, std::vector< wxPoint > &aLines, int aWidth, const COLOR4D &aColor)
Draw an array of lines (not a polygon).
Definition: gr_basic.cpp:242
Definition: color4d.h:44
void GRRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, const COLOR4D &aColor)
Definition: gr_basic.cpp:774
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
static int xcliphi
Definition: gr_basic.cpp:85
static int GRLastMoveToX
Definition: gr_basic.cpp:80
bool Contains(const wxPoint &aPoint) const
Definition: eda_rect.cpp:57
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:114
void GRDrawAnchor(EDA_RECT *aClipBox, wxDC *aDC, int x, int y, int aSize, const COLOR4D &aColor)
Definition: gr_basic.cpp:921
void GRSetBrush(wxDC *DC, const COLOR4D &Color, bool fill)
Definition: gr_basic.cpp:163
static int xcliplo
Definition: gr_basic.cpp:83
static const bool NOT_FILLED
Definition: gr_basic.cpp:35
void GRArc(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, double StAngle, double EndAngle, int r, const COLOR4D &Color)
Definition: gr_basic.cpp:689
static int GRLastMoveToY
Definition: gr_basic.cpp:80
void GRForceBlackPen(bool flagforce)
Definition: gr_basic.cpp:190
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:93
static wxDC * s_DC_lastDC
Definition: gr_basic.cpp:91
int GetRight() const
Definition: eda_rect.h:111
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:551
void GRFillCSegm(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:369
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:212
a few functions useful in geometry calculations.
void GRBezier(EDA_RECT *aClipBox, wxDC *aDC, std::vector< wxPoint > &aPoint, int aWidth, const COLOR4D &aColor)
Draw cubic (4 points: start control1, control2, end) bezier curve.
Definition: gr_basic.cpp:909
static bool IsGRSPolyDrawable(EDA_RECT *ClipBox, int n, const wxPoint *Points)
Definition: gr_basic.cpp:384
void GRFilledSegment(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aStart, const wxPoint &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:377
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:507
int GetHeight() const
Definition: eda_rect.h:110
static COLOR4D s_DC_lastbrushcolor(0, 0, 0, 0)
static COLOR4D s_DC_lastcolor(0, 0, 0, 0)
void GRLineTo(EDA_RECT *ClipBox, wxDC *DC, int x, int y, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:236
void GRArc1(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int xc, int yc, const COLOR4D &Color)
Definition: gr_basic.cpp:594
void GRMoveTo(int x, int y)
Definition: gr_basic.cpp:229
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:874
static void GRSRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D &aColor, wxPenStyle aStyle=wxPENSTYLE_SOLID)
Definition: gr_basic.cpp:825
Bezier curves to polygon converter.
Definition: bezier_curves.h:36
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:99
void GRPutPixel(EDA_RECT *ClipBox, wxDC *DC, int x, int y, const COLOR4D &Color)
Definition: gr_basic.cpp:202
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:497
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
bool GetGRForceBlackPenState(void)
Definition: gr_basic.cpp:196
BASE_SCREEN class implementation.
void GRRectPs(EDA_RECT *aClipBox, wxDC *aDC, const EDA_RECT &aRect, const COLOR4D &aColor, wxPenStyle aStyle)
Definition: gr_basic.cpp:780
void GRFilledArc(EDA_RECT *ClipBox, wxDC *DC, int x, int y, double StAngle, double EndAngle, int r, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Definition: gr_basic.cpp:641
static bool s_DC_lastbrushfill
Definition: gr_basic.cpp:90
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:838
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:81
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:575
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:271