You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1063 lines
28 KiB

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