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.

1526 lines
42 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
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
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
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
  1. /********************************/
  2. /* Low level graphics routines */
  3. /********************************/
  4. #include <fctsys.h>
  5. #include <gr_basic.h>
  6. #include <common.h>
  7. #include <trigo.h>
  8. #include <macros.h>
  9. #include <base_struct.h>
  10. #include <class_base_screen.h>
  11. #include <bezier_curves.h>
  12. #include <math_for_graphics.h>
  13. #include <wx/graphics.h>
  14. static const bool FILLED = true;
  15. static const bool NOT_FILLED = false;
  16. /* Important Note:
  17. * These drawing functions clip draw item before send these items to wxDC draw
  18. * functions. For guy who asks why i did it, see a sample of problems encountered
  19. * when pixels
  20. * coordinates overflow 16 bits values:
  21. * http://trac.wxwidgets.org/ticket/10446
  22. * Problems can be found under Windows **and** Linux (mainly when drawing arcs)
  23. * (mainly at low zoom values (2, 1 or 0.5), in Pcbnew)
  24. * some of these problems could be now fixed in recent distributions.
  25. *
  26. * Currently (feb 2009) there are overflow problems when drawing solid (filled)
  27. * polygons under linux without clipping
  28. *
  29. * So before removing clipping functions, be aware these bug (they are not in
  30. * KiCad or wxWidgets) are fixed by testing how are drawn complex lines arcs
  31. * and solid polygons under Windows and Linux and remember users can have old
  32. * versions with bugs
  33. */
  34. /* Definitions for enabling and disabling debugging features in gr_basic.cpp.
  35. * Please remember to set these back to 0 before making LAUNCHPAD commits.
  36. */
  37. #define DEBUG_DUMP_CLIP_ERROR_COORDS 0 // Set to 1 to dump clip algorithm errors.
  38. #define DEBUG_DUMP_CLIP_COORDS 0 // Set to 1 to dump clipped coordinates.
  39. // For draw mode = XOR GR_XOR or GR_NXOR by background color
  40. GR_DRAWMODE g_XorMode = GR_NXOR;
  41. // Background color of the design frame
  42. EDA_COLOR_T g_DrawBgColor = WHITE;
  43. static void ClipAndDrawPoly( EDA_RECT * ClipBox, wxDC * DC, wxPoint Points[],
  44. int n );
  45. /* These functions are used by corresponding functions
  46. * ( GRSCircle is called by GRCircle for instance) after mapping coordinates
  47. * from user units to screen units(pixels coordinates)
  48. */
  49. static void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1,
  50. int x2, int y2, int aWidth, EDA_COLOR_T aColor,
  51. wxPenStyle aStyle = wxPENSTYLE_SOLID );
  52. /**/
  53. static int GRLastMoveToX, GRLastMoveToY;
  54. static bool s_ForceBlackPen; /* if true: draws in black instead of
  55. * color for printing. */
  56. static int xcliplo = 0,
  57. ycliplo = 0,
  58. xcliphi = 2000,
  59. ycliphi = 2000;
  60. static EDA_COLOR_T s_DC_lastcolor = UNSPECIFIED_COLOR;
  61. static int s_DC_lastwidth = -1;
  62. static int s_DC_lastpenstyle = -1;
  63. static EDA_COLOR_T s_DC_lastbrushcolor = UNSPECIFIED_COLOR;
  64. static bool s_DC_lastbrushfill = false;
  65. static wxDC* s_DC_lastDC = NULL;
  66. /**
  67. * Test if any part of a line falls within the bounds of a rectangle.
  68. *
  69. * Please note that this is only accurate for lines that are one pixel wide.
  70. *
  71. * @param aClipBox - The rectangle to test.
  72. * @param x1 - X coordinate of one end of a line.
  73. * @param y1 - Y coordinate of one end of a line.
  74. * @param x2 - X coordinate of the other end of a line.
  75. * @param y2 - Y coordinate of the other end of a line.
  76. *
  77. * @return - False if any part of the line lies within the rectangle.
  78. */
  79. static bool clipLine( EDA_RECT* aClipBox, int& x1, int& y1, int& x2, int& y2 )
  80. {
  81. if( aClipBox->Contains( x1, y1 ) && aClipBox->Contains( x2, y2 ) )
  82. return false;
  83. wxRect rect = *aClipBox;
  84. int minX = rect.GetLeft();
  85. int maxX = rect.GetRight();
  86. int minY = rect.GetTop();
  87. int maxY = rect.GetBottom();
  88. int clippedX, clippedY;
  89. #if DEBUG_DUMP_CLIP_COORDS
  90. int tmpX1, tmpY1, tmpX2, tmpY2;
  91. tmpX1 = x1;
  92. tmpY1 = y1;
  93. tmpX2 = x2;
  94. tmpY2 = y2;
  95. #endif
  96. if( aClipBox->Contains( x1, y1 ) )
  97. {
  98. if( x1 == x2 ) /* Vertical line, clip Y. */
  99. {
  100. if( y2 < minY )
  101. {
  102. y2 = minY;
  103. return false;
  104. }
  105. if( y2 > maxY )
  106. {
  107. y2 = maxY;
  108. return false;
  109. }
  110. }
  111. else if( y1 == y2 ) /* Horizontal line, clip X. */
  112. {
  113. if( x2 < minX )
  114. {
  115. x2 = minX;
  116. return false;
  117. }
  118. if( x2 > maxX )
  119. {
  120. x2 = maxX;
  121. return false;
  122. }
  123. }
  124. /* If we're here, it's a diagonal line. */
  125. if( TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, minY, minX, maxY,
  126. &clippedX, &clippedY ) /* Left */
  127. || TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, minY, maxX, minY,
  128. &clippedX, &clippedY ) /* Top */
  129. || TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, maxX, minY, maxX, maxY,
  130. &clippedX, &clippedY ) /* Right */
  131. || TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, maxY, maxX, maxY,
  132. &clippedX, &clippedY ) ) /* Bottom */
  133. {
  134. if( x2 != clippedX )
  135. x2 = clippedX;
  136. if( y2 != clippedY )
  137. y2 = clippedY;
  138. return false;
  139. }
  140. /* If we're here, something has gone terribly wrong. */
  141. #if DEBUG_DUMP_CLIP_ERROR_COORDS
  142. wxLogDebug( wxT( "Line (%d,%d):(%d,%d) in rectangle (%d,%d,%d,%d) clipped to (%d,%d,%d,%d)" ),
  143. tmpX1, tmpY1, tmpX2, tmpY2, minX, minY, maxX, maxY, x1, y1, x2, y2 );
  144. #endif
  145. return false;
  146. }
  147. else if( aClipBox->Contains( x2, y2 ) )
  148. {
  149. if( x1 == x2 ) /* Vertical line, clip Y. */
  150. {
  151. if( y2 < minY )
  152. {
  153. y2 = minY;
  154. return false;
  155. }
  156. if( y2 > maxY )
  157. {
  158. y2 = maxY;
  159. return false;
  160. }
  161. }
  162. else if( y1 == y2 ) /* Horizontal line, clip X. */
  163. {
  164. if( x2 < minX )
  165. {
  166. x2 = minX;
  167. return false;
  168. }
  169. if( x2 > maxX )
  170. {
  171. x2 = maxX;
  172. return false;
  173. }
  174. }
  175. if( TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, minY, minX, maxY,
  176. &clippedX, &clippedY ) /* Left */
  177. || TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, minY, maxX, minY,
  178. &clippedX, &clippedY ) /* Top */
  179. || TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, maxX, minY, maxX, maxY,
  180. &clippedX, &clippedY ) /* Right */
  181. || TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, maxY, maxX, maxY,
  182. &clippedX, &clippedY ) ) /* Bottom */
  183. {
  184. if( x1 != clippedX )
  185. x1 = clippedX;
  186. if( y1 != clippedY )
  187. y1 = clippedY;
  188. return false;
  189. }
  190. /* If we're here, something has gone terribly wrong. */
  191. #if DEBUG_DUMP_CLIP_ERROR_COORDS
  192. wxLogDebug( wxT( "Line (%d,%d):(%d,%d) in rectangle (%d,%d,%d,%d) clipped to (%d,%d,%d,%d)" ),
  193. tmpX1, tmpY1, tmpX2, tmpY2, minX, minY, maxX, maxY, x1, y1, x2, y2 );
  194. #endif
  195. return false;
  196. }
  197. else
  198. {
  199. int* intersectX;
  200. int* intersectY;
  201. int intersectX1, intersectY1, intersectX2, intersectY2;
  202. bool haveFirstPoint = false;
  203. intersectX = &intersectX1;
  204. intersectY = &intersectY1;
  205. /* Left clip rectangle line. */
  206. if( TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, minY, minX, maxY,
  207. intersectX, intersectY ) )
  208. {
  209. intersectX = &intersectX2;
  210. intersectY = &intersectY2;
  211. haveFirstPoint = true;
  212. }
  213. /* Top clip rectangle line. */
  214. if( TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, minY, maxX, minY,
  215. intersectX, intersectY ) )
  216. {
  217. intersectX = &intersectX2;
  218. intersectY = &intersectY2;
  219. if( haveFirstPoint )
  220. {
  221. x1 = intersectX1;
  222. y1 = intersectY1;
  223. x2 = intersectX2;
  224. y2 = intersectY2;
  225. return false;
  226. }
  227. haveFirstPoint = true;
  228. }
  229. /* Right clip rectangle line. */
  230. if( TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, maxX, minY, maxX, maxY,
  231. intersectX, intersectY ) )
  232. {
  233. intersectX = &intersectX2;
  234. intersectY = &intersectY2;
  235. if( haveFirstPoint )
  236. {
  237. x1 = intersectX1;
  238. y1 = intersectY1;
  239. x2 = intersectX2;
  240. y2 = intersectY2;
  241. return false;
  242. }
  243. haveFirstPoint = true;
  244. }
  245. /* Bottom clip rectangle line. */
  246. if( TestForIntersectionOfStraightLineSegments( x1, y1, x2, y2, minX, maxY, maxX, maxY,
  247. intersectX, intersectY ) )
  248. {
  249. intersectX = &intersectX2;
  250. intersectY = &intersectY2;
  251. if( haveFirstPoint )
  252. {
  253. x1 = intersectX1;
  254. y1 = intersectY1;
  255. x2 = intersectX2;
  256. y2 = intersectY2;
  257. return false;
  258. }
  259. }
  260. /* If we're here and only one line of the clip box has been intersected,
  261. * something has gone terribly wrong. */
  262. #if DEBUG_DUMP_CLIP_ERROR_COORDS
  263. if( haveFirstPoint )
  264. wxLogDebug( wxT( "Line (%d,%d):(%d,%d) in rectangle (%d,%d,%d,%d) clipped to (%d,%d,%d,%d)" ),
  265. tmpX1, tmpY1, tmpX2, tmpY2, minX, minY, maxX, maxY, x1, y1, x2, y2 );
  266. #endif
  267. }
  268. /* Set this to one to verify that diagonal lines get clipped properly. */
  269. #if DEBUG_DUMP_CLIP_COORDS
  270. if( !( x1 == x2 || y1 == y2 ) )
  271. wxLogDebug( wxT( "Clipped line (%d,%d):(%d,%d) from rectangle (%d,%d,%d,%d)" ),
  272. tmpX1, tmpY1, tmpX2, tmpY2, minX, minY, maxX, maxY );
  273. #endif
  274. return true;
  275. }
  276. static void WinClipAndDrawLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  277. EDA_COLOR_T Color, int width = 1 )
  278. {
  279. GRLastMoveToX = x2;
  280. GRLastMoveToY = y2;
  281. if( ClipBox )
  282. {
  283. EDA_RECT clipbox(*ClipBox);
  284. clipbox.Inflate(width/2);
  285. if( clipLine( &clipbox, x1, y1, x2, y2 ) )
  286. return;
  287. }
  288. GRSetColorPen( DC, Color, width );
  289. DC->DrawLine( x1, y1, x2, y2 );
  290. }
  291. /* Forcing a reset of the current pen.
  292. * Must be called after changing the graphical device before any trace.
  293. */
  294. void GRResetPenAndBrush( wxDC* DC )
  295. {
  296. GRSetBrush( DC, BLACK ); // Force no fill
  297. s_DC_lastbrushcolor = UNSPECIFIED_COLOR;
  298. s_DC_lastcolor = UNSPECIFIED_COLOR;
  299. s_DC_lastDC = NULL;
  300. }
  301. /**
  302. * Function GRSetColorPen
  303. * sets a pen style, width, color, and alpha into the given device context.
  304. */
  305. void GRSetColorPen( wxDC* DC, EDA_COLOR_T Color, int width, wxPenStyle style )
  306. {
  307. if( width < 0 )
  308. width = 0;
  309. #ifdef __WXMAC__
  310. // Under OSX when wxPen is set to 0, cocoa follows the request drawing nothing &
  311. // in the bitmap world the minimum is enough to light a pixel, in vectorial one not
  312. if( width <= 1 )
  313. width = DC->DeviceToLogicalXRel( 1 );
  314. #endif
  315. if( s_ForceBlackPen )
  316. {
  317. Color = BLACK;
  318. }
  319. if( s_DC_lastcolor != Color
  320. || s_DC_lastwidth != width
  321. || s_DC_lastpenstyle != style
  322. || s_DC_lastDC != DC )
  323. {
  324. wxPen pen;
  325. wxColour wx_color = MakeColour( Color );
  326. pen.SetColour( wx_color );
  327. pen.SetWidth( width );
  328. pen.SetStyle( style );
  329. DC->SetPen( pen );
  330. s_DC_lastcolor = Color;
  331. s_DC_lastwidth = width;
  332. s_DC_lastpenstyle = style;
  333. s_DC_lastDC = DC;
  334. }
  335. }
  336. void GRSetBrush( wxDC* DC, EDA_COLOR_T Color, bool fill )
  337. {
  338. if( s_ForceBlackPen )
  339. Color = BLACK;
  340. if( s_DC_lastbrushcolor != Color
  341. || s_DC_lastbrushfill != fill
  342. || s_DC_lastDC != DC )
  343. {
  344. wxBrush brush;
  345. brush.SetColour( MakeColour( Color ) );
  346. if( fill )
  347. #if wxCHECK_VERSION( 3, 0, 0 )
  348. brush.SetStyle( wxBRUSHSTYLE_SOLID );
  349. else
  350. brush.SetStyle( wxBRUSHSTYLE_TRANSPARENT );
  351. #else
  352. brush.SetStyle( wxSOLID );
  353. else
  354. brush.SetStyle( wxTRANSPARENT );
  355. #endif
  356. DC->SetBrush( brush );
  357. s_DC_lastbrushcolor = Color;
  358. s_DC_lastbrushfill = fill;
  359. s_DC_lastDC = DC;
  360. }
  361. }
  362. /**
  363. * Function GRForceBlackPen
  364. * @param flagforce True to force a black pen whenever the asked color
  365. */
  366. void GRForceBlackPen( bool flagforce )
  367. {
  368. s_ForceBlackPen = flagforce;
  369. }
  370. /**
  371. * Function GetGRForceBlackPenState
  372. * @return s_ForceBlackPen (True if a black pen was forced)
  373. */
  374. bool GetGRForceBlackPenState( void )
  375. {
  376. return s_ForceBlackPen;
  377. }
  378. /*************************************/
  379. /* Set the device context draw mode. */
  380. /*************************************/
  381. void GRSetDrawMode( wxDC* DC, GR_DRAWMODE draw_mode )
  382. {
  383. if( draw_mode & GR_OR )
  384. #if defined(__WXMAC__) && (wxMAC_USE_CORE_GRAPHICS || wxCHECK_VERSION( 2, 9, 0 ) )
  385. DC->SetLogicalFunction( wxCOPY );
  386. #elif defined( USE_WX_GRAPHICS_CONTEXT )
  387. DC->SetLogicalFunction( wxCOPY );
  388. #else
  389. DC->SetLogicalFunction( wxOR );
  390. #endif
  391. else if( draw_mode & GR_XOR )
  392. #if defined( USE_WX_GRAPHICS_CONTEXT )
  393. DC->SetLogicalFunction( wxCOPY );
  394. #else
  395. DC->SetLogicalFunction( wxXOR );
  396. #endif
  397. else if( draw_mode & GR_NXOR )
  398. #if defined(__WXMAC__) && (wxMAC_USE_CORE_GRAPHICS || wxCHECK_VERSION( 2, 9, 0 ) )
  399. DC->SetLogicalFunction( wxXOR );
  400. #elif defined( USE_WX_GRAPHICS_CONTEXT )
  401. DC->SetLogicalFunction( wxCOPY );
  402. #else
  403. DC->SetLogicalFunction( wxEQUIV );
  404. #endif
  405. else if( draw_mode & GR_INVERT )
  406. #if defined( USE_WX_GRAPHICS_CONTEXT )
  407. DC->SetLogicalFunction( wxCOPY );
  408. #else
  409. DC->SetLogicalFunction( wxINVERT );
  410. #endif
  411. else
  412. DC->SetLogicalFunction( wxCOPY );
  413. #ifdef USE_WX_OVERLAY
  414. DC->SetLogicalFunction( wxCOPY );
  415. #endif
  416. }
  417. void GRPutPixel( EDA_RECT* ClipBox, wxDC* DC, int x, int y, EDA_COLOR_T Color )
  418. {
  419. if( ClipBox && !ClipBox->Contains( x, y ) )
  420. return;
  421. GRSetColorPen( DC, Color );
  422. DC->DrawPoint( x, y );
  423. }
  424. /*
  425. * Draw a line, in object space.
  426. */
  427. void GRLine( EDA_RECT* ClipBox,
  428. wxDC* DC,
  429. int x1,
  430. int y1,
  431. int x2,
  432. int y2,
  433. int width,
  434. EDA_COLOR_T Color )
  435. {
  436. WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, Color, width );
  437. GRLastMoveToX = x2;
  438. GRLastMoveToY = y2;
  439. }
  440. void GRLine( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd, int aWidth, EDA_COLOR_T aColor )
  441. {
  442. GRLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, aColor );
  443. }
  444. void GRDashedLineTo( EDA_RECT* ClipBox, wxDC* DC, int x2, int y2, int width, EDA_COLOR_T Color )
  445. {
  446. s_DC_lastcolor = UNSPECIFIED_COLOR;
  447. GRSetColorPen( DC, Color, width, wxPENSTYLE_SHORT_DASH );
  448. GRLine( ClipBox, DC, GRLastMoveToX, GRLastMoveToY, x2, y2, width, Color );
  449. s_DC_lastcolor = UNSPECIFIED_COLOR;
  450. GRSetColorPen( DC, Color, width );
  451. GRLastMoveToX = x2;
  452. GRLastMoveToY = y2;
  453. }
  454. void GRDashedLine( EDA_RECT* ClipBox,
  455. wxDC* DC,
  456. int x1,
  457. int y1,
  458. int x2,
  459. int y2,
  460. int width,
  461. EDA_COLOR_T Color )
  462. {
  463. GRLastMoveToX = x2;
  464. GRLastMoveToY = y2;
  465. s_DC_lastcolor = UNSPECIFIED_COLOR;
  466. GRSetColorPen( DC, Color, width, wxPENSTYLE_SHORT_DASH );
  467. GRLine( ClipBox, DC, x1, y1, x2, y2, width, Color );
  468. s_DC_lastcolor = UNSPECIFIED_COLOR;
  469. GRSetColorPen( DC, Color, width );
  470. }
  471. /*
  472. * Move to a new position, in object space.
  473. */
  474. void GRMoveTo( int x, int y )
  475. {
  476. GRLastMoveToX = x;
  477. GRLastMoveToY = y;
  478. }
  479. /*
  480. * Draw line to a new position, in object space.
  481. */
  482. void GRLineTo( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int width, EDA_COLOR_T Color )
  483. {
  484. int GRLineToX, GRLineToY;
  485. GRLineToX = x;
  486. GRLineToY = y;
  487. GRLine( ClipBox, DC, GRLastMoveToX, GRLastMoveToY, GRLineToX, GRLineToY, width, Color );
  488. }
  489. void GRMixedLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  490. int width, EDA_COLOR_T Color )
  491. {
  492. GRSetColorPen( DC, Color, width, wxPENSTYLE_DOT_DASH );
  493. GRLine( ClipBox, DC, x1, y1, x2, y2, width, Color );
  494. GRSetColorPen( DC, Color, width );
  495. }
  496. /**
  497. * Function GRLineArray
  498. * draws an array of lines (not a polygon).
  499. * @param aClipBox = the clip box
  500. * @param aDC = the device context into which drawing should occur.
  501. * @param aLines = a list of pair of coordinate in user space: a pair for each line.
  502. * @param aWidth = the width of each line.
  503. * @param aColor = an index into our color table of RGB colors.
  504. * @see EDA_COLOR_T and colors.h
  505. */
  506. void GRLineArray( EDA_RECT* aClipBox, wxDC* aDC, std::vector<wxPoint>& aLines,
  507. int aWidth, EDA_COLOR_T aColor )
  508. {
  509. GRSetColorPen( aDC, aColor, aWidth );
  510. if( aClipBox )
  511. aClipBox->Inflate(aWidth/2);
  512. for( unsigned i = 0; i < aLines.size(); i += 2)
  513. {
  514. int x1 = aLines[i].x;
  515. int y1 = aLines[i].y;
  516. int x2 = aLines[i+1].x;
  517. int y2 = aLines[i+1].y;
  518. GRLastMoveToX = x2;
  519. GRLastMoveToY = y2;
  520. if( ( aClipBox == NULL ) || !clipLine( aClipBox, x1, y1, x2, y2 ) )
  521. aDC->DrawLine( x1, y1, x2, y2 );
  522. }
  523. if( aClipBox )
  524. aClipBox->Inflate(-aWidth/2);
  525. }
  526. void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  527. int width, int aPenSize, EDA_COLOR_T Color )
  528. {
  529. long radius;
  530. int dwx, dwy;
  531. long dx, dy, dwx2, dwy2;
  532. long sx1, sy1, ex1, ey1;
  533. long sx2, sy2, ex2, ey2;
  534. bool swap_ends = false;
  535. GRLastMoveToX = x2;
  536. GRLastMoveToY = y2;
  537. if( ClipBox )
  538. {
  539. EDA_RECT clipbox(*ClipBox);
  540. clipbox.Inflate(width/2);
  541. if( clipLine( &clipbox, x1, y1, x2, y2 ) )
  542. return;
  543. }
  544. if( width <= 2 ) /* single line or 2 pixels */
  545. {
  546. GRSetColorPen( DC, Color, width );
  547. DC->DrawLine( x1, y1, x2, y2 );
  548. return;
  549. }
  550. GRSetColorPen( DC, Color, aPenSize );
  551. GRSetBrush( DC, Color, false );
  552. radius = (width + 1) >> 1;
  553. dx = x2 - x1;
  554. dy = y2 - y1;
  555. if( dx == 0 ) /* segment vertical */
  556. {
  557. dwx = radius;
  558. if( dy >= 0 )
  559. dwx = -dwx;
  560. sx1 = x1 - dwx;
  561. sy1 = y1;
  562. ex1 = x2 - dwx;
  563. ey1 = y2;
  564. DC->DrawLine( sx1, sy1, ex1, ey1 );
  565. sx2 = x1 + dwx;
  566. sy2 = y1;
  567. ex2 = x2 + dwx;
  568. ey2 = y2;
  569. DC->DrawLine( sx2, sy2, ex2, ey2 );
  570. }
  571. else if( dy == 0 ) /* segment horizontal */
  572. {
  573. dwy = radius;
  574. if( dx < 0 )
  575. dwy = -dwy;
  576. sx1 = x1;
  577. sy1 = y1 - dwy;
  578. ex1 = x2;
  579. ey1 = y2 - dwy;
  580. DC->DrawLine( sx1, sy1, ex1, ey1 );
  581. sx2 = x1;
  582. sy2 = y1 + dwy;
  583. ex2 = x2;
  584. ey2 = y2 + dwy;
  585. DC->DrawLine( sx2, sy2, ex2, ey2 );
  586. }
  587. else
  588. {
  589. if( std::abs( dx ) == std::abs( dy ) ) // segment 45 degrees
  590. {
  591. dwx = dwy = ( (width * 5) + 4 ) / 7; // = width / 2 * 0.707
  592. if( dy < 0 )
  593. {
  594. if( dx <= 0 )
  595. {
  596. dwx = -dwx; swap_ends = true;
  597. }
  598. }
  599. else // dy >= 0
  600. {
  601. if( dx > 0 )
  602. {
  603. dwy = -dwy; swap_ends = true;
  604. }
  605. else
  606. swap_ends = true;
  607. }
  608. }
  609. else
  610. {
  611. double delta_angle = ArcTangente( dy, dx );
  612. dwx = 0;
  613. dwy = width;
  614. RotatePoint( &dwx, &dwy, -delta_angle );
  615. }
  616. dwx2 = dwx >> 1;
  617. dwy2 = dwy >> 1;
  618. sx1 = x1 - dwx2;
  619. sy1 = y1 - dwy2;
  620. ex1 = x2 - dwx2;
  621. ey1 = y2 - dwy2;
  622. DC->DrawLine( sx1, sy1, ex1, ey1 );
  623. sx2 = x1 + dwx2;
  624. sy2 = y1 + dwy2;
  625. ex2 = x2 + dwx2;
  626. ey2 = y2 + dwy2;
  627. DC->DrawLine( sx2, sy2, ex2, ey2 );
  628. }
  629. if( swap_ends )
  630. {
  631. DC->DrawArc( sx2, sy2, sx1, sy1, x1, y1 );
  632. DC->DrawArc( ex1, ey1, ex2, ey2, x2, y2 );
  633. }
  634. else
  635. {
  636. DC->DrawArc( sx1, sy1, sx2, sy2, x1, y1 );
  637. DC->DrawArc( ex2, ey2, ex1, ey1, x2, y2 );
  638. }
  639. }
  640. void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  641. int width, EDA_COLOR_T Color )
  642. {
  643. GRCSegm( ClipBox, DC, x1, y1, x2, y2, width, 0, Color );
  644. }
  645. void GRCSegm( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd,
  646. int aWidth, EDA_COLOR_T aColor )
  647. {
  648. GRCSegm( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, 0, aColor );
  649. }
  650. /*
  651. * Draw segment (full) with rounded ends in object space (real coords.).
  652. */
  653. void GRFillCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  654. int width, EDA_COLOR_T Color )
  655. {
  656. WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, Color, width );
  657. }
  658. void GRFilledSegment( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd,
  659. int aWidth, EDA_COLOR_T aColor )
  660. {
  661. WinClipAndDrawLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aColor, aWidth );
  662. }
  663. static bool IsGRSPolyDrawable( EDA_RECT* ClipBox, int n, wxPoint Points[] )
  664. {
  665. if( !ClipBox )
  666. return true;
  667. if( n <= 0 )
  668. return false;
  669. int Xmin, Xmax, Ymin, Ymax;
  670. Xmin = Xmax = Points[0].x;
  671. Ymin = Ymax = Points[0].y;
  672. for( int ii = 1; ii < n; ii++ ) // calculate rectangle
  673. {
  674. Xmin = std::min( Xmin, Points[ii].x );
  675. Xmax = std::max( Xmax, Points[ii].x );
  676. Ymin = std::min( Ymin, Points[ii].y );
  677. Ymax = std::max( Ymax, Points[ii].y );
  678. }
  679. xcliplo = ClipBox->GetX();
  680. ycliplo = ClipBox->GetY();
  681. xcliphi = ClipBox->GetRight();
  682. ycliphi = ClipBox->GetBottom();
  683. if( Xmax < xcliplo )
  684. return false;
  685. if( Xmin > xcliphi )
  686. return false;
  687. if( Ymax < ycliplo )
  688. return false;
  689. if( Ymin > ycliphi )
  690. return false;
  691. return true;
  692. }
  693. /*
  694. * Draw a new polyline and fill it if Fill, in screen space.
  695. */
  696. static void GRSPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
  697. bool Fill, int width,
  698. EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  699. {
  700. if( !IsGRSPolyDrawable( ClipBox, n, Points ) )
  701. return;
  702. GRSetColorPen( DC, Color, width );
  703. if( Fill && ( n > 2 ) )
  704. {
  705. GRSetBrush( DC, BgColor, FILLED );
  706. /* clip before send the filled polygon to wxDC, because under linux
  707. * (GTK?) polygons having large coordinates are incorrectly drawn
  708. * (integer overflow in coordinates, I am guessing)
  709. */
  710. ClipAndDrawPoly( ClipBox, DC, Points, n );
  711. }
  712. else
  713. {
  714. wxPoint endPt = Points[n - 1];
  715. GRSetBrush( DC, Color );
  716. DC->DrawLines( n, Points );
  717. // The last point is not drawn by DrawLine and DrawLines
  718. // Add it if the polygon is not closed
  719. if( endPt != Points[0] )
  720. DC->DrawPoint( endPt.x, endPt.y );
  721. }
  722. }
  723. /*
  724. * Draw a new closed polyline and fill it if Fill, in screen space.
  725. */
  726. static void GRSClosedPoly( EDA_RECT* aClipBox, wxDC* aDC,
  727. int aPointCount, wxPoint aPoints[],
  728. bool aFill, int aWidth,
  729. EDA_COLOR_T aColor,
  730. EDA_COLOR_T aBgColor )
  731. {
  732. if( !IsGRSPolyDrawable( aClipBox, aPointCount, aPoints ) )
  733. return;
  734. GRSetColorPen( aDC, aColor, aWidth );
  735. if( aFill && ( aPointCount > 2 ) )
  736. {
  737. GRLastMoveToX = aPoints[aPointCount - 1].x;
  738. GRLastMoveToY = aPoints[aPointCount - 1].y;
  739. GRSetBrush( aDC, aBgColor, FILLED );
  740. ClipAndDrawPoly( aClipBox, aDC, aPoints, aPointCount );
  741. }
  742. else
  743. {
  744. GRSetBrush( aDC, aBgColor );
  745. aDC->DrawLines( aPointCount, aPoints );
  746. int lastpt = aPointCount - 1;
  747. /* Close the polygon. */
  748. if( aPoints[lastpt] != aPoints[0] )
  749. {
  750. GRLine( aClipBox, aDC, aPoints[0].x, aPoints[0].y,
  751. aPoints[lastpt].x, aPoints[lastpt].y,
  752. aWidth, aColor );
  753. }
  754. }
  755. }
  756. /*
  757. * Draw a new polyline and fill it if Fill, in drawing space.
  758. */
  759. void GRPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
  760. bool Fill, int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  761. {
  762. GRSPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
  763. }
  764. /*
  765. * Draw a closed polyline and fill it if Fill, in object space.
  766. */
  767. void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
  768. bool Fill, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  769. {
  770. GRClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor );
  771. }
  772. void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
  773. bool Fill, int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  774. {
  775. GRSClosedPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
  776. }
  777. void GRCircle( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, int r, int width, EDA_COLOR_T Color )
  778. {
  779. /* Clip circles off screen. */
  780. if( ClipBox )
  781. {
  782. int x0, y0, xm, ym;
  783. x0 = ClipBox->GetX();
  784. y0 = ClipBox->GetY();
  785. xm = ClipBox->GetRight();
  786. ym = ClipBox->GetBottom();
  787. if( xc < ( x0 - r - width ) )
  788. return;
  789. if( yc < ( y0 - r - width ) )
  790. return;
  791. if( xc > ( r + xm + width ) )
  792. return;
  793. if( yc > ( r + ym + width ) )
  794. return;
  795. }
  796. GRSetColorPen( DC, Color, width );
  797. GRSetBrush( DC, Color, false );
  798. DC->DrawEllipse( xc - r, yc - r, r + r, r + r );
  799. }
  800. void GRCircle( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int r, EDA_COLOR_T Color )
  801. {
  802. GRCircle( ClipBox, DC, x, y, r, 0, Color );
  803. }
  804. void GRCircle( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aPos, int aRadius, int aWidth, EDA_COLOR_T aColor )
  805. {
  806. GRCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, aWidth, aColor );
  807. }
  808. void GRFilledCircle( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int r,
  809. int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  810. {
  811. /* Clip circles off screen. */
  812. if( ClipBox )
  813. {
  814. int x0, y0, xm, ym;
  815. x0 = ClipBox->GetX();
  816. y0 = ClipBox->GetY();
  817. xm = ClipBox->GetRight();
  818. ym = ClipBox->GetBottom();
  819. if( x < (x0 - r) )
  820. return;
  821. if( y < (y0 - r) )
  822. return;
  823. if( x > (r + xm) )
  824. return;
  825. if( y > (r + ym) )
  826. return;
  827. }
  828. GRSetColorPen( DC, Color, width );
  829. GRSetBrush( DC, BgColor, FILLED );
  830. DC->DrawEllipse( x - r, y - r, r + r, r + r );
  831. }
  832. void GRFilledCircle( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aPos, int aRadius, EDA_COLOR_T aColor )
  833. {
  834. GRFilledCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, 0, aColor, aColor );
  835. }
  836. /*
  837. * Draw an arc in user space.
  838. */
  839. void GRArc1( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  840. int xc, int yc, EDA_COLOR_T Color )
  841. {
  842. GRArc1( ClipBox, DC, x1, y1, x2, y2, xc, yc, 0, Color );
  843. }
  844. /*
  845. * Draw an arc, width = width in user space.
  846. */
  847. void GRArc1( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  848. int xc, int yc, int width, EDA_COLOR_T Color )
  849. {
  850. /* Clip arcs off screen. */
  851. if( ClipBox )
  852. {
  853. int x0, y0, xm, ym, r;
  854. x0 = ClipBox->GetX();
  855. y0 = ClipBox->GetY();
  856. xm = ClipBox->GetRight();
  857. ym = ClipBox->GetBottom();
  858. r = KiROUND( Distance( x1, y1, xc, yc ) );
  859. if( xc < ( x0 - r ) )
  860. return;
  861. if( yc < ( y0 - r ) )
  862. return;
  863. if( xc > ( r + xm ) )
  864. return;
  865. if( yc > ( r + ym ) )
  866. return;
  867. }
  868. GRSetColorPen( DC, Color, width );
  869. GRSetBrush( DC, Color );
  870. DC->DrawArc( x1, y1, x2, y2, xc, yc );
  871. }
  872. void GRArc1( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd,
  873. wxPoint aCenter, int aWidth, EDA_COLOR_T aColor )
  874. {
  875. GRArc1( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aCenter.x, aCenter.y,
  876. aWidth, aColor );
  877. }
  878. /*
  879. * Draw a filled arc in drawing space.
  880. */
  881. void GRFilledArc( EDA_RECT* ClipBox,
  882. wxDC* DC,
  883. int x,
  884. int y,
  885. double StAngle,
  886. double EndAngle,
  887. int r,
  888. int width,
  889. EDA_COLOR_T Color,
  890. EDA_COLOR_T BgColor )
  891. {
  892. int x1, y1, x2, y2;
  893. /* Clip arcs off screen */
  894. if( ClipBox )
  895. {
  896. int x0, y0, xm, ym;
  897. x0 = ClipBox->GetX();
  898. y0 = ClipBox->GetY();
  899. xm = ClipBox->GetRight();
  900. ym = ClipBox->GetBottom();
  901. if( x < ( x0 - r - 1 ) )
  902. return;
  903. if( y < ( y0 - r - 1 ) )
  904. return;
  905. if( x > ( r + xm + 1 ) )
  906. return;
  907. if( y > ( r + ym + 1 ) )
  908. return;
  909. }
  910. x1 = r;
  911. y1 = 0;
  912. RotatePoint( &x1, &y1, EndAngle );
  913. x2 = r;
  914. y2 = 0;
  915. RotatePoint( &x2, &y2, StAngle );
  916. GRSetBrush( DC, BgColor, FILLED );
  917. GRSetColorPen( DC, Color, width );
  918. DC->DrawArc( x + x1, y - y1, x + x2, y - y2, x, y );
  919. }
  920. void GRFilledArc( EDA_RECT* ClipBox, wxDC* DC, int x, int y,
  921. double StAngle, double EndAngle, int r,
  922. EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  923. {
  924. GRFilledArc( ClipBox, DC, x, y, StAngle, EndAngle, r, 0, Color, BgColor );
  925. }
  926. /*
  927. * Draw an arc in drawing space.
  928. */
  929. void GRArc( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, double StAngle,
  930. double EndAngle, int r, EDA_COLOR_T Color )
  931. {
  932. int x1, y1, x2, y2;
  933. /* Clip arcs off screen */
  934. if( ClipBox )
  935. {
  936. int radius = r + 1;
  937. int x0, y0, xm, ym, x, y;
  938. x0 = ClipBox->GetX();
  939. y0 = ClipBox->GetY();
  940. xm = ClipBox->GetRight();
  941. ym = ClipBox->GetBottom();
  942. x = xc;
  943. y = yc;
  944. if( x < ( x0 - radius ) )
  945. return;
  946. if( y < ( y0 - radius ) )
  947. return;
  948. if( x > ( xm + radius ) )
  949. return;
  950. if( y > ( ym + radius ) )
  951. return;
  952. }
  953. x1 = r;
  954. y1 = 0;
  955. RotatePoint( &x1, &y1, EndAngle );
  956. x2 = r;
  957. y2 = 0;
  958. RotatePoint( &x2, &y2, StAngle );
  959. GRSetColorPen( DC, Color );
  960. GRSetBrush( DC, Color, false );
  961. DC->DrawArc( xc + x1, yc - y1, xc + x2, yc - y2, xc, yc );
  962. }
  963. /*
  964. * Draw an arc with width = width in drawing space.
  965. */
  966. void GRArc( EDA_RECT* ClipBox,
  967. wxDC* DC,
  968. int x,
  969. int y,
  970. double StAngle,
  971. double EndAngle,
  972. int r,
  973. int width,
  974. EDA_COLOR_T Color )
  975. {
  976. int x1, y1, x2, y2;
  977. /* Clip arcs off screen. */
  978. if( ClipBox )
  979. {
  980. int x0, y0, xm, ym;
  981. x0 = ClipBox->GetX();
  982. y0 = ClipBox->GetY();
  983. xm = ClipBox->GetRight();
  984. ym = ClipBox->GetBottom();
  985. if( x < ( x0 - r - width ) )
  986. return;
  987. if( y < ( y0 - r - width ) )
  988. return;
  989. if( x > ( r + xm + width ) )
  990. return;
  991. if( y > ( r + ym + width ) )
  992. return;
  993. }
  994. x1 = r;
  995. y1 = 0;
  996. RotatePoint( &x1, &y1, EndAngle );
  997. x2 = r;
  998. y2 = 0;
  999. RotatePoint( &x2, &y2, StAngle );
  1000. GRSetColorPen( DC, Color, width );
  1001. GRSetBrush( DC, Color );
  1002. DC->DrawArc( x + x1, y - y1, x + x2, y - y2, x, y );
  1003. }
  1004. /*
  1005. * Draw a rectangle in drawing space.
  1006. */
  1007. void GRRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2, EDA_COLOR_T aColor )
  1008. {
  1009. GRSRect( aClipBox, aDC, x1, y1, x2, y2, 0, aColor );
  1010. }
  1011. void GRRectPs( EDA_RECT* aClipBox, wxDC* aDC, const EDA_RECT& aRect, EDA_COLOR_T aColor, wxPenStyle aStyle )
  1012. {
  1013. int x1 = aRect.GetX();
  1014. int y1 = aRect.GetY();
  1015. int x2 = aRect.GetRight();
  1016. int y2 = aRect.GetBottom();
  1017. GRSRect( aClipBox, aDC, x1, y1, x2, y2, 0, aColor, aStyle );
  1018. }
  1019. /*
  1020. * Draw a rectangle (thick lines) in drawing space.
  1021. */
  1022. void GRRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width, EDA_COLOR_T Color )
  1023. {
  1024. GRSRect( ClipBox, DC, x1, y1, x2, y2, width, Color );
  1025. }
  1026. void GRRect( EDA_RECT* aClipBox, wxDC* aDC, const EDA_RECT& aRect, int aWidth, EDA_COLOR_T aColor )
  1027. {
  1028. int x1 = aRect.GetX();
  1029. int y1 = aRect.GetY();
  1030. int x2 = aRect.GetRight();
  1031. int y2 = aRect.GetBottom();
  1032. GRSRect( aClipBox, aDC, x1, y1, x2, y2, aWidth, aColor );
  1033. }
  1034. /*
  1035. * Draw a rectangle (filled with AreaColor) in drawing space.
  1036. */
  1037. void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  1038. EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  1039. {
  1040. GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, 0, Color, BgColor );
  1041. }
  1042. /*
  1043. * Draw a rectangle (filled with AreaColor) in drawing space.
  1044. */
  1045. void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
  1046. int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
  1047. {
  1048. GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, width, Color, BgColor );
  1049. }
  1050. /*
  1051. * Draw a rectangle in screen space.
  1052. */
  1053. void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2,
  1054. int aWidth, EDA_COLOR_T aColor, wxPenStyle aStyle )
  1055. {
  1056. wxPoint points[5];
  1057. points[0] = wxPoint(x1, y1);
  1058. points[1] = wxPoint(x1, y2);
  1059. points[2] = wxPoint(x2, y2);
  1060. points[3] = wxPoint(x2, y1);
  1061. points[4] = points[0];
  1062. GRSClosedPoly( aClipBox, aDC, 5, points, NOT_FILLED, aWidth,
  1063. aColor, aColor );
  1064. }
  1065. void GRSFilledRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2,
  1066. int aWidth, EDA_COLOR_T aColor, EDA_COLOR_T aBgColor )
  1067. {
  1068. wxPoint points[5];
  1069. points[0] = wxPoint(x1, y1);
  1070. points[1] = wxPoint(x1, y2);
  1071. points[2] = wxPoint(x2, y2);
  1072. points[3] = wxPoint(x2, y1);
  1073. points[4] = points[0];
  1074. GRSetBrush( aDC, aBgColor, FILLED );
  1075. GRSetColorPen( aDC, aBgColor, aWidth );
  1076. if( aClipBox && (aWidth > 0) )
  1077. {
  1078. EDA_RECT clipbox(*aClipBox);
  1079. clipbox.Inflate(aWidth);
  1080. ClipAndDrawPoly(&clipbox, aDC, points, 5); // polygon approach is more accurate
  1081. }
  1082. else
  1083. ClipAndDrawPoly(aClipBox, aDC, points, 5 );
  1084. }
  1085. /**
  1086. * Function ClipAndDrawPoly
  1087. * Used to clip a polygon and draw it as Filled Polygon
  1088. * uses the Sutherland and Hodgman algo to clip the given poly against a
  1089. * rectangle. This rectangle is the drawing area this is useful under
  1090. * Linux (2009) because filled polygons are incorrectly drawn if they have
  1091. * too large coordinates (seems due to integer overflows in calculations)
  1092. * Could be removed in some years, if become unnecessary.
  1093. */
  1094. /* Note: aClipBox == NULL is legal, so if aClipBox == NULL,
  1095. * the polygon is drawn, but not clipped
  1096. */
  1097. #include <SutherlandHodgmanClipPoly.h>
  1098. void ClipAndDrawPoly( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aPoints[], int n )
  1099. {
  1100. if( aClipBox == NULL )
  1101. {
  1102. aDC->DrawPolygon( n, aPoints );
  1103. return;
  1104. }
  1105. // A clip box exists: clip and draw the polygon.
  1106. static std::vector<wxPoint> clippedPolygon;
  1107. static pointVector inputPolygon, outputPolygon;
  1108. inputPolygon.clear();
  1109. outputPolygon.clear();
  1110. clippedPolygon.clear();
  1111. for( int ii = 0; ii < n; ii++ )
  1112. inputPolygon.push_back( PointF( (REAL) aPoints[ii].x, (REAL) aPoints[ii].y ) );
  1113. RectF window( (REAL) aClipBox->GetX(), (REAL) aClipBox->GetY(),
  1114. (REAL) aClipBox->GetWidth(), (REAL) aClipBox->GetHeight() );
  1115. SutherlandHodgman sh( window );
  1116. sh.Clip( inputPolygon, outputPolygon );
  1117. for( cpointIterator cit = outputPolygon.begin(); cit != outputPolygon.end(); ++cit )
  1118. {
  1119. clippedPolygon.push_back( wxPoint( KiROUND( cit->X ), KiROUND( cit->Y ) ) );
  1120. }
  1121. if( clippedPolygon.size() )
  1122. aDC->DrawPolygon( clippedPolygon.size(), &clippedPolygon[0] );
  1123. }
  1124. void GRBezier( EDA_RECT* ClipBox,
  1125. wxDC* DC,
  1126. int x1,
  1127. int y1,
  1128. int x2,
  1129. int y2,
  1130. int x3,
  1131. int y3,
  1132. int width,
  1133. EDA_COLOR_T Color )
  1134. {
  1135. std::vector<wxPoint> Points = Bezier2Poly( x1, y1, x2, y2, x3, y3 );
  1136. GRPoly( ClipBox, DC, Points.size(), &Points[0], false, width, Color, Color );
  1137. }
  1138. void GRBezier( EDA_RECT* ClipBox,
  1139. wxDC* DC,
  1140. int x1,
  1141. int y1,
  1142. int x2,
  1143. int y2,
  1144. int x3,
  1145. int y3,
  1146. int x4,
  1147. int y4,
  1148. int width,
  1149. EDA_COLOR_T Color )
  1150. {
  1151. std::vector<wxPoint> Points = Bezier2Poly( x1, y1, x2, y2, x3, y3, x4, y4 );
  1152. GRPoly( ClipBox, DC, Points.size(), &Points[0], false, width, Color, Color );
  1153. }
  1154. EDA_COLOR_T ColorMix( EDA_COLOR_T aColor1, EDA_COLOR_T aColor2 )
  1155. {
  1156. /* Memoization storage. This could be potentially called for each
  1157. * color merge so a cache is useful (there are few colours anyway) */
  1158. static EDA_COLOR_T mix_cache[NBCOLORS][NBCOLORS];
  1159. // TODO how is alpha used? it's a mac only thing, I have no idea
  1160. aColor1 = ColorGetBase( aColor1 );
  1161. aColor2 = ColorGetBase( aColor2 );
  1162. // First easy thing: a black gives always the other colour
  1163. if( aColor1 == BLACK )
  1164. return aColor2;
  1165. if( aColor2 == BLACK)
  1166. return aColor1;
  1167. /* Now we are sure that black can't occur, so the rule is:
  1168. * BLACK means not computed yet. If we're lucky we already have
  1169. * an answer */
  1170. EDA_COLOR_T candidate = mix_cache[aColor1][aColor2];
  1171. if( candidate != BLACK )
  1172. return candidate;
  1173. // Blend the two colors (i.e. OR the RGB values)
  1174. const StructColors &c1 = g_ColorRefs[aColor1];
  1175. const StructColors &c2 = g_ColorRefs[aColor2];
  1176. // Ask the palette for the nearest color to the mix
  1177. wxColour mixed( c1.m_Red | c2.m_Red,
  1178. c1.m_Green | c2.m_Green,
  1179. c1.m_Blue | c2.m_Blue );
  1180. candidate = ColorFindNearest( mixed );
  1181. /* Here, BLACK is *not* a good answer, since it would recompute the next time.
  1182. * Even theorically its not possible (with the current rules), but
  1183. * maybe the metric will change in the future */
  1184. if( candidate == BLACK)
  1185. candidate = DARKDARKGRAY;
  1186. // Store the result in the cache. The operation is commutative, too
  1187. mix_cache[aColor1][aColor2] = candidate;
  1188. mix_cache[aColor2][aColor1] = candidate;
  1189. return candidate;
  1190. }
  1191. EDA_COLOR_T ColorByName( const wxString& aName )
  1192. {
  1193. // look for a match in the palette itself
  1194. for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) )
  1195. {
  1196. if( 0 == aName.CmpNoCase( g_ColorRefs[trying].m_Name ) )
  1197. return trying;
  1198. }
  1199. // Not found, no idea...
  1200. return UNSPECIFIED_COLOR;
  1201. }
  1202. bool ColorIsLight( EDA_COLOR_T aColor )
  1203. {
  1204. const StructColors &c = g_ColorRefs[ColorGetBase( aColor )];
  1205. int r = c.m_Red;
  1206. int g = c.m_Green;
  1207. int b = c.m_Blue;
  1208. return ((r * r) + (g * g) + (b * b)) > (128 * 128 * 3);
  1209. }
  1210. EDA_COLOR_T ColorFindNearest( const wxColour &aColor )
  1211. {
  1212. return ColorFindNearest( aColor.Red(), aColor.Green(), aColor.Blue() );
  1213. }
  1214. EDA_COLOR_T ColorFindNearest( int aR, int aG, int aB )
  1215. {
  1216. EDA_COLOR_T candidate = BLACK;
  1217. /* Find the 'nearest' color in the palette. This is fun. There is
  1218. a gazilion of metrics for the color space and no one of the
  1219. useful one is in the RGB color space. Who cares, this is a CAD,
  1220. not a photosomething...
  1221. I hereby declare that the distance is the sum of the square of the
  1222. component difference. Think about the RGB color cube. Now get the
  1223. euclidean distance, but without the square root... for ordering
  1224. purposes it's the same, obviously. Also each component can't be
  1225. less of the target one, since I found this currently work better...
  1226. */
  1227. int nearest_distance = 255 * 255 * 3 + 1; // Can't beat this
  1228. for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) )
  1229. {
  1230. const StructColors &c = g_ColorRefs[trying];
  1231. int distance = (aR - c.m_Red) * (aR - c.m_Red) +
  1232. (aG - c.m_Green) * (aG - c.m_Green) +
  1233. (aB - c.m_Blue) * (aB - c.m_Blue);
  1234. if( distance < nearest_distance && c.m_Red >= aR &&
  1235. c.m_Green >= aG && c.m_Blue >= aB )
  1236. {
  1237. nearest_distance = distance;
  1238. candidate = trying;
  1239. }
  1240. }
  1241. return candidate;
  1242. }
  1243. void GRDrawAnchor( EDA_RECT *aClipBox, wxDC *aDC, int x, int y,
  1244. int aSize, EDA_COLOR_T aColor )
  1245. {
  1246. int anchor_size = aDC->DeviceToLogicalXRel( aSize );
  1247. GRLine( aClipBox, aDC,
  1248. x - anchor_size, y,
  1249. x + anchor_size, y, 0, aColor );
  1250. GRLine( aClipBox, aDC,
  1251. x, y - anchor_size,
  1252. x, y + anchor_size, 0, aColor );
  1253. }