KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gr_basic.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 1992-2022 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 <wx/graphics.h>
26#include <math/vector2wx.h>
27
28#include <algorithm>
29
30static const bool FILLED = true;
31static const bool NOT_FILLED = false;
32
33// For draw mode = XOR GR_XOR or GR_NXOR by background color
35
36
37/* These functions are used by corresponding functions
38 * ( GRSCircle is called by GRCircle for instance) after mapping coordinates
39 * from user units to screen units(pixels coordinates)
40 */
41static void GRSRect( wxDC* aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D& aColor );
42
43
44
46static bool s_ForceBlackPen; /* if true: draws in black instead of
47 * color for printing. */
48static COLOR4D s_DC_lastbrushcolor( 0, 0, 0, 0 );
49static bool s_DC_lastbrushfill = false;
50static wxDC* s_DC_lastDC = nullptr;
51
52
53static void vector2IwxDrawPolygon( wxDC* aDC, const VECTOR2I* Points, int n )
54{
55 wxPoint* points = new wxPoint[n];
56
57 for( int i = 0; i < n; i++ )
58 points[i] = wxPoint( Points[i].x, Points[i].y );
59
60 aDC->DrawPolygon( n, points );
61 delete[] points;
62}
63
64
65static void winDrawLine( wxDC* DC, int x1, int y1, int x2, int y2, int width )
66{
67 GRLastMoveToX = x2;
68 GRLastMoveToY = y2;
69 DC->DrawLine( x1, y1, x2, y2 );
70}
71
72
73void GRResetPenAndBrush( wxDC* DC )
74{
75 GRSetBrush( DC, BLACK ); // Force no fill
77 s_DC_lastDC = nullptr;
78}
79
80
81void GRSetColorPen( wxDC* DC, const COLOR4D& Color, int width, wxPenStyle style )
82{
83 COLOR4D color = Color;
84
85 wxDash dots[2] = { 1, 3 };
86
87 // Under OSX and while printing when wxPen is set to 0, renderer follows the request drawing
88 // nothing & in the bitmap world the minimum is enough to light a pixel, in vectorial one not
89 if( width <= 1 && DC->GetBrush().GetStyle() != wxBRUSHSTYLE_SOLID )
90 width = DC->DeviceToLogicalXRel( 1 );
91
92 if( s_ForceBlackPen )
94
95 // wxWidgets will enforce a minimum pen width when printing, so we have to make the pen
96 // transparent when we don't want the object stroked.
97 if( width == 0 )
98 {
100 style = wxPENSTYLE_TRANSPARENT;
101 }
102
103 const wxPen& curr_pen = DC->GetPen();
104
105 if( !curr_pen.IsOk() || curr_pen.GetColour() != color.ToColour()
106 || curr_pen.GetWidth() != width || curr_pen.GetStyle() != style )
107 {
108 wxPen pen;
109 pen.SetColour( color.ToColour() );
110
111 if( style == wxPENSTYLE_DOT )
112 {
113 style = wxPENSTYLE_USER_DASH;
114 pen.SetDashes( 2, dots );
115 }
116
117 pen.SetWidth( width );
118 pen.SetStyle( style );
119 DC->SetPen( pen );
120 }
121 else
122 {
123 // Should be not needed, but on Linux, in printing process
124 // the curr pen settings needs to be sometimes re-initialized
125 // Clearly, this is due to a bug, related to SetBrush(),
126 // but we have to live with it, at least on wxWidgets 3.0
127 DC->SetPen( curr_pen );
128 }
129}
130
131
132void GRSetBrush( wxDC* DC, const COLOR4D& Color, bool fill )
133{
134 COLOR4D color = Color;
135
136 if( s_ForceBlackPen )
138
139 if( s_DC_lastbrushcolor != color || s_DC_lastbrushfill != fill || s_DC_lastDC != DC )
140 {
141 wxBrush brush;
142
143 brush.SetColour( color.ToColour() );
144
145 if( fill )
146 brush.SetStyle( wxBRUSHSTYLE_SOLID );
147 else
148 brush.SetStyle( wxBRUSHSTYLE_TRANSPARENT );
149
150 DC->SetBrush( brush );
151
153 s_DC_lastbrushfill = fill;
154 s_DC_lastDC = DC;
155 }
156}
157
158
159void GRForceBlackPen( bool flagforce )
160{
161 s_ForceBlackPen = flagforce;
162}
163
164
166{
167 return s_ForceBlackPen;
168}
169
170
171void GRLine( wxDC* DC, int x1, int y1, int x2, int y2, int width, const COLOR4D& Color,
172 wxPenStyle aStyle)
173{
174 GRSetColorPen( DC, Color, width, aStyle );
175 winDrawLine( DC, x1, y1, x2, y2, width );
176 GRLastMoveToX = x2;
177 GRLastMoveToY = y2;
178}
179
180
181void GRLine( wxDC* aDC, const VECTOR2I& aStart, const VECTOR2I& aEnd, int aWidth,
182 const COLOR4D& aColor, wxPenStyle aStyle )
183{
184 GRLine( aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, aColor, aStyle );
185}
186
187
188void GRMoveTo( int x, int y )
189{
190 GRLastMoveToX = x;
191 GRLastMoveToY = y;
192}
193
194
195void GRLineTo( wxDC* DC, int x, int y, int width, const COLOR4D& Color )
196{
197 GRLine( DC, GRLastMoveToX, GRLastMoveToY, x, y, width, Color );
198}
199
200
201void GRCSegm( wxDC* DC, const VECTOR2I& A, const VECTOR2I& B, int width, const COLOR4D& Color )
202{
203 GRLastMoveToX = B.x;
204 GRLastMoveToY = B.y;
205
206 if( width <= 2 ) /* single line or 2 pixels */
207 {
208 GRSetColorPen( DC, Color, width );
209 DC->DrawLine( A.x, A.y, B.x, B.y );
210 return;
211 }
212
213 GRSetBrush( DC, Color, NOT_FILLED );
214 GRSetColorPen( DC, Color, 0 );
215
216 int radius = ( width + 1 ) >> 1;
217 int dx = B.x - A.x;
218 int dy = B.y - A.y;
219 EDA_ANGLE angle( VECTOR2I( dx, dy ) );
220
221 angle = -angle;
222
223 VECTOR2I start;
224 VECTOR2I end;
225 VECTOR2I org( A.x, A.y );
226 int len = (int) hypot( dx, dy );
227
228 // We know if the DC is mirrored, to draw arcs
229 int slx = DC->DeviceToLogicalX( 1 ) - DC->DeviceToLogicalX( 0 );
230 int sly = DC->DeviceToLogicalY( 1 ) - DC->DeviceToLogicalY( 0 );
231 bool mirrored = ( slx > 0 && sly < 0 ) || ( slx < 0 && sly > 0 );
232
233 // first edge
234 start.x = 0;
235 start.y = radius;
236 end.x = len;
237 end.y = radius;
238 RotatePoint( start, angle );
239 RotatePoint( end, angle );
240
241 start += org;
242 end += org;
243
244 DC->DrawLine( ToWxPoint( start ), ToWxPoint( end ) );
245
246 // first rounded end
247 end.x = 0;
248 end.y = -radius;
249 RotatePoint( end, angle );
250 end += org;
251
252 if( !mirrored )
253 DC->DrawArc( ToWxPoint(end ), ToWxPoint(start ), ToWxPoint(org ) );
254 else
255 DC->DrawArc( ToWxPoint(start ), ToWxPoint(end ), ToWxPoint(org ) );
256
257 // second edge
258 start.x = len;
259 start.y = -radius;
260 RotatePoint( start, angle );
261 start += org;
262
263 DC->DrawLine( ToWxPoint( start ), ToWxPoint( end ) );
264
265 // second rounded end
266 end.x = len;
267 end.y = radius;
268 RotatePoint( end, angle);
269 end += org;
270
271 if( !mirrored )
272 DC->DrawArc( end.x, end.y, start.x, start.y, B.x, B.y );
273 else
274 DC->DrawArc( start.x, start.y, end.x, end.y, B.x, B.y );
275}
276
277
278void GRFilledSegment( wxDC* aDC, const VECTOR2I& aStart, const VECTOR2I& aEnd, int aWidth,
279 const COLOR4D& aColor )
280{
281 GRSetColorPen( aDC, aColor, aWidth );
282 winDrawLine( aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth );
283}
284
288static void GRSPoly( wxDC* DC, int n, const VECTOR2I* Points, bool Fill, int width,
289 const COLOR4D& Color, const COLOR4D& BgColor )
290{
291 if( Fill && ( n > 2 ) )
292 {
293 GRSetBrush( DC, BgColor, FILLED );
294 GRSetColorPen( DC, Color, width );
295
296 vector2IwxDrawPolygon( DC, Points, n );
297 }
298 else
299 {
300 GRMoveTo( Points[0].x, Points[0].y );
301
302 for( int i = 1; i < n; ++i )
303 GRLineTo( DC, Points[i].x, Points[i].y, width, Color );
304 }
305}
306
307
311static void GRSClosedPoly( wxDC* aDC, int aPointCount, const VECTOR2I* aPoints, bool aFill,
312 int aWidth, const COLOR4D& aColor, const COLOR4D& aBgColor )
313{
314 if( aFill && ( aPointCount > 2 ) )
315 {
316 GRLastMoveToX = aPoints[aPointCount - 1].x;
317 GRLastMoveToY = aPoints[aPointCount - 1].y;
318 GRSetBrush( aDC, aBgColor, FILLED );
319 GRSetColorPen( aDC, aColor, aWidth );
320 vector2IwxDrawPolygon( aDC, aPoints, aPointCount );
321 }
322 else
323 {
324 GRMoveTo( aPoints[0].x, aPoints[0].y );
325
326 for( int i = 1; i < aPointCount; ++i )
327 GRLineTo( aDC, aPoints[i].x, aPoints[i].y, aWidth, aColor );
328
329 int lastpt = aPointCount - 1;
330
331 // Close the polygon
332 if( aPoints[lastpt] != aPoints[0] )
333 GRLineTo( aDC, aPoints[0].x, aPoints[0].y, aWidth, aColor );
334 }
335}
336
337
341void GRPoly( wxDC* DC, int n, const VECTOR2I* Points, bool Fill, int width, const COLOR4D& Color,
342 const COLOR4D& BgColor )
343{
344 GRSPoly( DC, n, Points, Fill, width, Color, BgColor );
345}
346
347
351void GRClosedPoly( wxDC* DC, int n, const VECTOR2I* Points, bool Fill, const COLOR4D& Color )
352{
353 GRSClosedPoly( DC, n, Points, Fill, 0, Color, Color );
354}
355
356
357void GRCircle( wxDC* aDC, const VECTOR2I& aPos, int aRadius, int aWidth, const COLOR4D& aColor )
358{
359 GRSetBrush( aDC, aColor, NOT_FILLED );
360 GRSetColorPen( aDC, aColor, aWidth );
361
362 // Draw two arcs here to make a circle. Unfortunately, the printerDC doesn't handle
363 // transparent brushes when used with circles. It does work for for arcs, however
364 aDC->DrawArc(aPos.x + aRadius, aPos.y, aPos.x - aRadius, aPos.y, aPos.x, aPos.y );
365 aDC->DrawArc(aPos.x - aRadius, aPos.y, aPos.x + aRadius, aPos.y, aPos.x, aPos.y );
366}
367
368
369void GRFilledCircle( wxDC* aDC, const VECTOR2I& aPos, int aRadius, int aWidth,
370 const COLOR4D& aStrokeColor, const COLOR4D& aFillColor )
371{
372 GRSetBrush( aDC, aFillColor, FILLED );
373 GRSetColorPen( aDC, aStrokeColor, aWidth );
374 aDC->DrawEllipse( aPos.x - aRadius, aPos.y - aRadius, 2 * aRadius, 2 * aRadius );
375}
376
377
378void GRArc( wxDC* aDC, const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter,
379 int aWidth, const COLOR4D& aColor )
380{
381 GRSetBrush( aDC, aColor );
382 GRSetColorPen( aDC, aColor, aWidth );
383 aDC->DrawArc( aStart.x, aStart.y, aEnd.x, aEnd.y, aCenter.x, aCenter.y );
384}
385
386
387void GRFilledArc( wxDC* DC, const VECTOR2I& aStart, const VECTOR2I& aEnd, const VECTOR2I& aCenter,
388 int width, const COLOR4D& Color, const COLOR4D& BgColor )
389{
390 GRSetBrush( DC, BgColor, FILLED );
391 GRSetColorPen( DC, Color, width );
392 DC->DrawArc( aStart.x, aStart.y, aEnd.x, aEnd.y, aCenter.x, aCenter.y );
393}
394
395
396void GRRect( wxDC* DC, const VECTOR2I& aStart, const VECTOR2I& aEnd, int aWidth,
397 const COLOR4D& aColor )
398{
399 GRSRect( DC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, aColor );
400}
401
402
403void GRFilledRect( wxDC* DC, const VECTOR2I& aStart, const VECTOR2I& aEnd, int aWidth,
404 const COLOR4D& aColor, const COLOR4D& aBgColor )
405{
406 GRSFilledRect( DC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, aColor, aBgColor );
407}
408
409
410void GRSRect( wxDC* aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D& aColor )
411{
412 VECTOR2I points[5];
413 points[0] = VECTOR2I( x1, y1 );
414 points[1] = VECTOR2I( x1, y2 );
415 points[2] = VECTOR2I( x2, y2 );
416 points[3] = VECTOR2I( x2, y1 );
417 points[4] = points[0];
418 GRSClosedPoly( aDC, 5, points, NOT_FILLED, aWidth, aColor, aColor );
419}
420
421
422void GRSFilledRect( wxDC* aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D& aColor,
423 const COLOR4D& aBgColor )
424{
425 VECTOR2I points[5];
426 points[0] = VECTOR2I( x1, y1 );
427 points[1] = VECTOR2I( x1, y2 );
428 points[2] = VECTOR2I( x2, y2 );
429 points[3] = VECTOR2I( x2, y1 );
430 points[4] = points[0];
431
432 GRSetBrush( aDC, aBgColor, FILLED );
433 GRSetColorPen( aDC, aBgColor, aWidth );
434
435 vector2IwxDrawPolygon( aDC, points, 5 );
436}
int color
Definition: DXF_plotter.cpp:58
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:398
static const COLOR4D BLACK
Definition: color4d.h:402
@ BLACK
Definition: color4d.h:44
void GRForceBlackPen(bool flagforce)
Definition: gr_basic.cpp:159
void GRResetPenAndBrush(wxDC *DC)
Definition: gr_basic.cpp:73
void GRLineTo(wxDC *DC, int x, int y, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:195
static int GRLastMoveToY
Definition: gr_basic.cpp:45
static void GRSRect(wxDC *aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:410
void GRRect(wxDC *DC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:396
void GRCSegm(wxDC *DC, const VECTOR2I &A, const VECTOR2I &B, int width, const COLOR4D &Color)
Definition: gr_basic.cpp:201
static void winDrawLine(wxDC *DC, int x1, int y1, int x2, int y2, int width)
Definition: gr_basic.cpp:65
static bool s_ForceBlackPen
Definition: gr_basic.cpp:46
static void vector2IwxDrawPolygon(wxDC *aDC, const VECTOR2I *Points, int n)
Definition: gr_basic.cpp:53
static int GRLastMoveToX
Definition: gr_basic.cpp:45
static const bool NOT_FILLED
Definition: gr_basic.cpp:31
static bool s_DC_lastbrushfill
Definition: gr_basic.cpp:49
void GRCircle(wxDC *aDC, const VECTOR2I &aPos, int aRadius, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:357
void GRFilledSegment(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:278
void GRFilledArc(wxDC *DC, const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, int width, const COLOR4D &Color, const COLOR4D &BgColor)
Definition: gr_basic.cpp:387
void GRSetColorPen(wxDC *DC, const COLOR4D &Color, int width, wxPenStyle style)
Definition: gr_basic.cpp:81
void GRSetBrush(wxDC *DC, const COLOR4D &Color, bool fill)
Definition: gr_basic.cpp:132
static void GRSPoly(wxDC *DC, int n, const VECTOR2I *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:288
void GRMoveTo(int x, int y)
Definition: gr_basic.cpp:188
static void GRSClosedPoly(wxDC *aDC, int aPointCount, const VECTOR2I *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:311
void GRLine(wxDC *DC, int x1, int y1, int x2, int y2, int width, const COLOR4D &Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:171
static COLOR4D s_DC_lastbrushcolor(0, 0, 0, 0)
static const bool FILLED
Definition: gr_basic.cpp:30
GR_DRAWMODE g_XorMode
Definition: gr_basic.cpp:34
void GRSFilledRect(wxDC *aDC, int x1, int y1, int x2, int y2, int aWidth, const COLOR4D &aColor, const COLOR4D &aBgColor)
Definition: gr_basic.cpp:422
void GRClosedPoly(wxDC *DC, int n, const VECTOR2I *Points, bool Fill, const COLOR4D &Color)
Draw a closed polyline and fill it if Fill, in object space.
Definition: gr_basic.cpp:351
static wxDC * s_DC_lastDC
Definition: gr_basic.cpp:50
void GRFilledRect(wxDC *DC, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, const COLOR4D &aColor, const COLOR4D &aBgColor)
Definition: gr_basic.cpp:403
void GRArc(wxDC *aDC, const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, int aWidth, const COLOR4D &aColor)
Definition: gr_basic.cpp:378
void GRPoly(wxDC *DC, int n, const VECTOR2I *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:341
bool GetGRForceBlackPenState(void)
Definition: gr_basic.cpp:165
void GRFilledCircle(wxDC *aDC, const VECTOR2I &aPos, int aRadius, int aWidth, const COLOR4D &aStrokeColor, const COLOR4D &aFillColor)
Draw a circle onto the drawing context aDC centered at the user coordinates (x,y).
Definition: gr_basic.cpp:369
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:35
@ GR_NXOR
Definition: gr_basic.h:39
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
wxPoint ToWxPoint(const VECTOR2I &aSize)
Definition: vector2wx.h:50