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