KiCad PCB EDA Suite
class_plotter.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) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
40 #include <fctsys.h>
41 
42 #include <trigo.h>
43 #include <wxstruct.h>
44 #include <base_struct.h>
45 #include <common.h>
46 #include <plot_common.h>
47 #include <macros.h>
48 #include <class_base_screen.h>
49 #include <drawtxt.h>
50 
52 {
53  plotScale = 1;
54  defaultPenWidth = 0;
55  currentPenWidth = -1; // To-be-set marker
56  penState = 'Z'; // End-of-path idle
57  m_plotMirror = false; // Plot mirror option flag
58  m_mirrorIsHorizontal = true;
59  m_yaxisReversed = false;
60  outputFile = 0;
61  colorMode = false; // Starts as a BW plot
62  negativeMode = false;
63  // Temporary init to avoid not initialized vars, will be set later
64  m_IUsPerDecimil = 1; // will be set later to the actual value
65  iuPerDeviceUnit = 1; // will be set later to the actual value
66  m_dashMarkLength_mm = 0.5; // Dashed line parameter in mm: segment
67  m_dashGapLength_mm = 0.25; // Dashed line parameter in mm: gap
68 }
69 
71 {
72  // Emergency cleanup, but closing the file is
73  // usually made in EndPlot().
74  if( outputFile )
75  fclose( outputFile );
76 }
77 
78 
79 bool PLOTTER::OpenFile( const wxString& aFullFilename )
80 {
81  filename = aFullFilename;
82 
83  wxASSERT( !outputFile );
84 
85  // Open the file in text mode (not suitable for all plotters
86  // but only for most of them
87  outputFile = wxFopen( filename, wxT( "wt" ) );
88 
89  if( outputFile == NULL )
90  return false ;
91 
92  return true;
93 }
94 
95 
97 {
98  wxPoint pos = aCoordinate - plotOffset;
99 
100  double x = pos.x * plotScale;
101  double y = ( paperSize.y - pos.y * plotScale );
102 
103  if( m_plotMirror )
104  {
106  x = ( paperSize.x - pos.x * plotScale );
107  else
108  y = pos.y * plotScale;
109  }
110 
111  if( m_yaxisReversed )
112  y = paperSize.y - y;
113 
114  x *= iuPerDeviceUnit;
115  y *= iuPerDeviceUnit;
116 
117  return DPOINT( x, y );
118 }
119 
120 
121 DPOINT PLOTTER::userToDeviceSize( const wxSize& size )
122 {
123  return DPOINT( size.x * plotScale * iuPerDeviceUnit,
124  size.y * plotScale * iuPerDeviceUnit );
125 }
126 
127 
128 double PLOTTER::userToDeviceSize( double size ) const
129 {
130  return size * plotScale * iuPerDeviceUnit;
131 }
132 
133 
135 {
137  return ( mark < 0.0 ) ? 0.0 : mark;
138 }
139 
140 
142 {
144 }
145 
146 void PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
147  FILL_T fill, int width )
148 {
149  wxPoint start, end;
150  const int delta = 50; // increment (in 0.1 degrees) to draw circles
151 
152  if( StAngle > EndAngle )
153  std::swap( StAngle, EndAngle );
154 
155  SetCurrentLineWidth( width );
156  /* Please NOTE the different sign due to Y-axis flip */
157  start.x = centre.x + KiROUND( cosdecideg( radius, -StAngle ) );
158  start.y = centre.y + KiROUND( sindecideg( radius, -StAngle ) );
159  MoveTo( start );
160  for( int ii = StAngle + delta; ii < EndAngle; ii += delta )
161  {
162  end.x = centre.x + KiROUND( cosdecideg( radius, -ii ) );
163  end.y = centre.y + KiROUND( sindecideg( radius, -ii ) );
164  LineTo( end );
165  }
166 
167  end.x = centre.x + KiROUND( cosdecideg( radius, -EndAngle ) );
168  end.y = centre.y + KiROUND( sindecideg( radius, -EndAngle ) );
169  FinishTo( end );
170 }
171 
172 
173 void PLOTTER::PlotImage(const wxImage & aImage, const wxPoint& aPos, double aScaleFactor )
174 {
175  wxSize size( aImage.GetWidth() * aScaleFactor,
176  aImage.GetHeight() * aScaleFactor );
177 
178  wxPoint start = aPos;
179  start.x -= size.x / 2;
180  start.y -= size.y / 2;
181 
182  wxPoint end = start;
183  end.x += size.x;
184  end.y += size.y;
185 
186  Rect( start, end, NO_FILL );
187 }
188 
189 
190 void PLOTTER::markerSquare( const wxPoint& position, int radius )
191 {
192  double r = KiROUND( radius / 1.4142 );
193  std::vector< wxPoint > corner_list;
194  wxPoint corner;
195  corner.x = position.x + r;
196  corner.y = position.y + r;
197  corner_list.push_back( corner );
198  corner.x = position.x + r;
199  corner.y = position.y - r;
200  corner_list.push_back( corner );
201  corner.x = position.x - r;
202  corner.y = position.y - r;
203  corner_list.push_back( corner );
204  corner.x = position.x - r;
205  corner.y = position.y + r;
206  corner_list.push_back( corner );
207  corner.x = position.x + r;
208  corner.y = position.y + r;
209  corner_list.push_back( corner );
210 
211  PlotPoly( corner_list, NO_FILL, GetCurrentLineWidth() );
212 }
213 
214 
215 void PLOTTER::markerCircle( const wxPoint& position, int radius )
216 {
217  Circle( position, radius * 2, NO_FILL, GetCurrentLineWidth() );
218 }
219 
220 
221 void PLOTTER::markerLozenge( const wxPoint& position, int radius )
222 {
223  std::vector< wxPoint > corner_list;
224  wxPoint corner;
225  corner.x = position.x;
226  corner.y = position.y + radius;
227  corner_list.push_back( corner );
228  corner.x = position.x + radius;
229  corner.y = position.y,
230  corner_list.push_back( corner );
231  corner.x = position.x;
232  corner.y = position.y - radius;
233  corner_list.push_back( corner );
234  corner.x = position.x - radius;
235  corner.y = position.y;
236  corner_list.push_back( corner );
237  corner.x = position.x;
238  corner.y = position.y + radius;
239  corner_list.push_back( corner );
240 
241  PlotPoly( corner_list, NO_FILL, GetCurrentLineWidth() );
242 }
243 
244 
245 void PLOTTER::markerHBar( const wxPoint& pos, int radius )
246 {
247  MoveTo( wxPoint( pos.x - radius, pos.y ) );
248  FinishTo( wxPoint( pos.x + radius, pos.y ) );
249 }
250 
251 
252 void PLOTTER::markerSlash( const wxPoint& pos, int radius )
253 {
254  MoveTo( wxPoint( pos.x - radius, pos.y - radius ) );
255  FinishTo( wxPoint( pos.x + radius, pos.y + radius ) );
256 }
257 
258 
259 void PLOTTER::markerBackSlash( const wxPoint& pos, int radius )
260 {
261  MoveTo( wxPoint( pos.x + radius, pos.y - radius ) );
262  FinishTo( wxPoint( pos.x - radius, pos.y + radius ) );
263 }
264 
265 
266 void PLOTTER::markerVBar( const wxPoint& pos, int radius )
267 {
268  MoveTo( wxPoint( pos.x, pos.y - radius ) );
269  FinishTo( wxPoint( pos.x, pos.y + radius ) );
270 }
271 
272 
273 void PLOTTER::Marker( const wxPoint& position, int diametre, unsigned aShapeId )
274 {
275  int radius = diametre / 2;
276  /* Marker are composed by a series of 'parts' superimposed; not every
277  combination make sense, obviously. Since they are used in order I
278  tried to keep the uglier/more complex constructions at the end.
279  Also I avoided the |/ |\ -/ -\ construction because they're *very*
280  ugly... if needed they could be added anyway... I'd like to see
281  a board with more than 58 drilling/slotting tools!
282  If Visual C++ supported the 0b literals they would be optimally
283  and easily encoded as an integer array. We have to do with octal */
284  static const unsigned char marker_patterns[MARKER_COUNT] = {
285  // Bit order: O Square Lozenge - | \ /
286  // First choice: simple shapes
287  0003, // X
288  0100, // O
289  0014, // +
290  0040, // Sq
291  0020, // Lz
292  // Two simple shapes
293  0103, // X O
294  0017, // X +
295  0043, // X Sq
296  0023, // X Lz
297  0114, // O +
298  0140, // O Sq
299  0120, // O Lz
300  0054, // + Sq
301  0034, // + Lz
302  0060, // Sq Lz
303  // Three simple shapes
304  0117, // X O +
305  0143, // X O Sq
306  0123, // X O Lz
307  0057, // X + Sq
308  0037, // X + Lz
309  0063, // X Sq Lz
310  0154, // O + Sq
311  0134, // O + Lz
312  0074, // + Sq Lz
313  // Four simple shapes
314  0174, // O Sq Lz +
315  0163, // X O Sq Lz
316  0157, // X O Sq +
317  0137, // X O Lz +
318  0077, // X Sq Lz +
319  // This draws *everything *
320  0177, // X O Sq Lz +
321  // Here we use the single bars... so the cross is forbidden
322  0110, // O -
323  0104, // O |
324  0101, // O /
325  0050, // Sq -
326  0044, // Sq |
327  0041, // Sq /
328  0030, // Lz -
329  0024, // Lz |
330  0021, // Lz /
331  0150, // O Sq -
332  0144, // O Sq |
333  0141, // O Sq /
334  0130, // O Lz -
335  0124, // O Lz |
336  0121, // O Lz /
337  0070, // Sq Lz -
338  0064, // Sq Lz |
339  0061, // Sq Lz /
340  0170, // O Sq Lz -
341  0164, // O Sq Lz |
342  0161, // O Sq Lz /
343  // Last resort: the backlash component (easy to confound)
344  0102, // \ O
345  0042, // \ Sq
346  0022, // \ Lz
347  0142, // \ O Sq
348  0122, // \ O Lz
349  0062, // \ Sq Lz
350  0162 // \ O Sq Lz
351  };
352  if( aShapeId >= MARKER_COUNT )
353  {
354  // Fallback shape
355  markerCircle( position, radius );
356  }
357  else
358  {
359  // Decode the pattern and draw the corresponding parts
360  unsigned char pat = marker_patterns[aShapeId];
361  if( pat & 0001 )
362  markerSlash( position, radius );
363  if( pat & 0002 )
364  markerBackSlash( position, radius );
365  if( pat & 0004 )
366  markerVBar( position, radius );
367  if( pat & 0010 )
368  markerHBar( position, radius );
369  if( pat & 0020 )
370  markerLozenge( position, radius );
371  if( pat & 0040 )
372  markerSquare( position, radius );
373  if( pat & 0100 )
374  markerCircle( position, radius );
375  }
376 }
377 
378 
379 void PLOTTER::segmentAsOval( const wxPoint& start, const wxPoint& end, int width,
380  EDA_DRAW_MODE_T tracemode )
381 {
382  wxPoint center( (start.x + end.x) / 2, (start.y + end.y) / 2 );
383  wxSize size( end.x - start.x, end.y - start.y );
384  double orient;
385 
386  if( size.y == 0 )
387  orient = 0;
388  else if( size.x == 0 )
389  orient = 900;
390  else
391  orient = -ArcTangente( size.y, size.x );
392 
393  size.x = KiROUND( EuclideanNorm( size ) ) + width;
394  size.y = width;
395 
396  FlashPadOval( center, size, orient, tracemode, NULL );
397 }
398 
399 
400 void PLOTTER::sketchOval( const wxPoint& pos, const wxSize& aSize, double orient, int width )
401 {
402  SetCurrentLineWidth( width );
403  width = currentPenWidth;
404  int radius, deltaxy, cx, cy;
405  wxSize size( aSize );
406 
407  if( size.x > size.y )
408  {
409  std::swap( size.x, size.y );
410  orient = AddAngles( orient, 900 );
411  }
412 
413  deltaxy = size.y - size.x; /* distance between centers of the oval */
414  radius = ( size.x - width ) / 2;
415  cx = -radius;
416  cy = -deltaxy / 2;
417  RotatePoint( &cx, &cy, orient );
418  MoveTo( wxPoint( cx + pos.x, cy + pos.y ) );
419  cx = -radius;
420  cy = deltaxy / 2;
421  RotatePoint( &cx, &cy, orient );
422  FinishTo( wxPoint( cx + pos.x, cy + pos.y ) );
423 
424  cx = radius;
425  cy = -deltaxy / 2;
426  RotatePoint( &cx, &cy, orient );
427  MoveTo( wxPoint( cx + pos.x, cy + pos.y ) );
428  cx = radius;
429  cy = deltaxy / 2;
430  RotatePoint( &cx, &cy, orient );
431  FinishTo( wxPoint( cx + pos.x, cy + pos.y ) );
432 
433  cx = 0;
434  cy = deltaxy / 2;
435  RotatePoint( &cx, &cy, orient );
436  Arc( wxPoint( cx + pos.x, cy + pos.y ),
437  orient + 1800, orient + 3600,
438  radius, NO_FILL );
439  cx = 0;
440  cy = -deltaxy / 2;
441  RotatePoint( &cx, &cy, orient );
442  Arc( wxPoint( cx + pos.x, cy + pos.y ),
443  orient, orient + 1800,
444  radius, NO_FILL );
445 }
446 
447 
448 void PLOTTER::ThickSegment( const wxPoint& start, const wxPoint& end, int width,
449  EDA_DRAW_MODE_T tracemode, void* aData )
450 {
451  if( tracemode == FILLED )
452  {
453  SetCurrentLineWidth( width );
454  MoveTo( start );
455  FinishTo( end );
456  }
457  else
458  {
459  SetCurrentLineWidth( -1 );
460  segmentAsOval( start, end, width, tracemode );
461  }
462 }
463 
464 
465 void PLOTTER::ThickArc( const wxPoint& centre, double StAngle, double EndAngle,
466  int radius, int width, EDA_DRAW_MODE_T tracemode, void* aData )
467 {
468  if( tracemode == FILLED )
469  Arc( centre, StAngle, EndAngle, radius, NO_FILL, width );
470  else
471  {
472  SetCurrentLineWidth( -1 );
473  Arc( centre, StAngle, EndAngle,
474  radius - ( width - currentPenWidth ) / 2, NO_FILL, -1 );
475  Arc( centre, StAngle, EndAngle,
476  radius + ( width - currentPenWidth ) / 2, NO_FILL, -1 );
477  }
478 }
479 
480 
481 void PLOTTER::ThickRect( const wxPoint& p1, const wxPoint& p2, int width,
482  EDA_DRAW_MODE_T tracemode, void* aData )
483 {
484  if( tracemode == FILLED )
485  Rect( p1, p2, NO_FILL, width );
486  else
487  {
488  SetCurrentLineWidth( -1 );
489  wxPoint offsetp1( p1.x - (width - currentPenWidth) / 2,
490  p1.y - (width - currentPenWidth) / 2 );
491  wxPoint offsetp2( p2.x + (width - currentPenWidth) / 2,
492  p2.y + (width - currentPenWidth) / 2 );
493  Rect( offsetp1, offsetp2, NO_FILL, -1 );
494  offsetp1.x += (width - currentPenWidth);
495  offsetp1.y += (width - currentPenWidth);
496  offsetp2.x -= (width - currentPenWidth);
497  offsetp2.y -= (width - currentPenWidth);
498  Rect( offsetp1, offsetp2, NO_FILL, -1 );
499  }
500 }
501 
502 
503 void PLOTTER::ThickCircle( const wxPoint& pos, int diametre, int width, EDA_DRAW_MODE_T tracemode, void* aData )
504 {
505  if( tracemode == FILLED )
506  Circle( pos, diametre, NO_FILL, width );
507  else
508  {
509  SetCurrentLineWidth( -1 );
510  Circle( pos, diametre - width + currentPenWidth, NO_FILL, -1 );
511  Circle( pos, diametre + width - currentPenWidth, NO_FILL, -1 );
512  }
513 }
514 
515 
516 void PLOTTER::SetPageSettings( const PAGE_INFO& aPageSettings )
517 {
518  wxASSERT( !outputFile );
519  pageInfo = aPageSettings;
520 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:104
void FinishTo(const wxPoint &pos)
Definition: plot_common.h:241
void markerHBar(const wxPoint &pos, int radius)
Plot a - bar centered on the position.
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
virtual void ThickCircle(const wxPoint &pos, int diametre, int width, EDA_DRAW_MODE_T tracemode, void *aData)
static const unsigned MARKER_COUNT
Draw a marker (used for the drill map)
Definition: plot_common.h:382
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
bool colorMode
Definition: plot_common.h:537
virtual ~PLOTTER()
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
char penState
Current pen state: 'U', 'D' or 'Z' (see PenTo)
Definition: plot_common.h:542
double m_IUsPerDecimil
Definition: plot_common.h:519
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL)=0
Function PlotPoly.
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
wxPoint plotOffset
Plot offset (in IUs)
Definition: plot_common.h:525
static const int delta[8][2]
Definition: solve.cpp:112
PAGE_INFO pageInfo
Definition: plot_common.h:548
virtual void ThickArc(const wxPoint &centre, double StAngle, double EndAngle, int rayon, int width, EDA_DRAW_MODE_T tracemode, void *aData)
This file contains miscellaneous commonly used macros and functions.
virtual void ThickRect(const wxPoint &p1, const wxPoint &p2, int width, EDA_DRAW_MODE_T tracemode, void *aData)
double m_dashMarkLength_mm
Dashed line parameter in mm: segment.
Definition: plot_common.h:89
bool m_yaxisReversed
true to mirror horizontally (else vertically)
Definition: plot_common.h:531
void LineTo(const wxPoint &pos)
Definition: plot_common.h:236
bool m_plotMirror
X axis orientation (SVG) and plot mirrored (only for PS, PDF HPGL and SVG)
Definition: plot_common.h:529
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:271
T AddAngles(T a1, T2 a2)
Add two angles (keeping the result normalized). T2 is here.
Definition: trigo.h:246
Base window classes and related definitions.
EDA_DRAW_MODE_T
Definition: eda_text.h:62
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
double plotScale
Plot scale - chosen by the user (even implicitly with 'fit in a4')
Definition: plot_common.h:513
Common plot library Plot settings, and plotting engines (Postscript, Gerber, HPGL and DXF) ...
virtual DPOINT userToDeviceSize(const wxSize &size)
Modifies size according to the plotter scale factors (wxSize version, returns a DPOINT) ...
void markerSlash(const wxPoint &pos, int radius)
Plot a / bar centered on the position.
void Marker(const wxPoint &position, int diametre, unsigned aShapeId)
Draw a pattern shape number aShapeId, to coord x0, y0.
double m_dashGapLength_mm
Dashed line parameter in mm: gap.
Definition: plot_common.h:90
void MoveTo(const wxPoint &pos)
Definition: plot_common.h:231
virtual DPOINT userToDeviceCoordinates(const wxPoint &aCoordinate)
Modifies coordinates according to the orientation, scale factor, and offsets trace.
double cosdecideg(double r, double a)
Circle generation utility: computes r * cos(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:311
virtual void PlotImage(const wxImage &aImage, const wxPoint &aPos, double aScaleFactor)
Function PlotImage Only Postscript plotters can plot bitmaps for plotters that cannot plot a bitmap...
double sindecideg(double r, double a)
Circle generation utility: computes r * sin(a) Where a is in decidegrees, not in radians.
Definition: trigo.h:302
BASE_SCREEN class implementation.
int currentPenWidth
Definition: plot_common.h:540
virtual int GetCurrentLineWidth() const
Definition: plot_common.h:142
int defaultPenWidth
true to generate a negative image (PS mode mainly)
Definition: plot_common.h:539
virtual void FlashPadOval(const wxPoint &aPadPos, const wxSize &aSize, double aPadOrient, EDA_DRAW_MODE_T aTraceMode, void *aData)=0
virtual function FlashPadOval
virtual void ThickSegment(const wxPoint &start, const wxPoint &end, int width, EDA_DRAW_MODE_T tracemode, void *aData)
void markerLozenge(const wxPoint &position, int radius)
Plot a lozenge centered on the position.
FILE * outputFile
true if the Y axis is top to bottom (SVG)
Definition: plot_common.h:534
double GetDashGapLenIU() const
The common library.
void markerCircle(const wxPoint &pos, int radius)
Plot a circle centered on the position.
virtual void Rect(const wxPoint &p1, const wxPoint &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
virtual void Arc(const wxPoint &centre, double StAngle, double EndAngle, int rayon, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)
Generic fallback: arc rendered as a polyline.
FILL_T
Enum FILL_T is the set of fill types used in plotting or drawing enclosed areas.
Definition: base_struct.h:56
This file is part of the common libary.
Basic classes for most KiCad items.
double GetDashMarkLenIU() const
double iuPerDeviceUnit
Device scale (from IUs to plotter device units - usually decimils)
Definition: plot_common.h:522
void segmentAsOval(const wxPoint &start, const wxPoint &end, int width, EDA_DRAW_MODE_T tracemode)
Cdonvert a thick segment and plot it as an oval.
VECTOR2< double > DPOINT
Definition: vector2d.h:595
wxString filename
Definition: plot_common.h:546
void markerVBar(const wxPoint &pos, int radius)
Plot a | bar centered on the position.
void markerSquare(const wxPoint &position, int radius)
Plot a square centered on the position.
void markerBackSlash(const wxPoint &pos, int radius)
Plot a \ bar centered on the position.
void sketchOval(const wxPoint &pos, const wxSize &size, double orient, int width)
virtual void Circle(const wxPoint &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
wxSize paperSize
Paper size in IU - not in mils.
Definition: plot_common.h:550
bool m_mirrorIsHorizontal
Definition: plot_common.h:530
virtual void SetCurrentLineWidth(int width, void *aData=NULL)=0
Set the line width for the next drawing.
bool negativeMode
true to plot in color, false to plot in black and white
Definition: plot_common.h:538