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