summaryrefslogtreecommitdiff
path: root/common/gr_basic.cpp
diff options
context:
space:
mode:
authorsaurabhb172020-02-26 16:11:59 +0530
committerGitHub2020-02-26 16:11:59 +0530
commite255d0622297488c1c52755be670733418c994cf (patch)
tree1392c90227aeea231c1d86371131e04c40382918 /common/gr_basic.cpp
parent0db48f6533517ecebfd9f0693f89deca28408b76 (diff)
parentc38609295ad4b617aef472b9c575aee18710a50f (diff)
downloadKiCad-eSim-e255d0622297488c1c52755be670733418c994cf.tar.gz
KiCad-eSim-e255d0622297488c1c52755be670733418c994cf.tar.bz2
KiCad-eSim-e255d0622297488c1c52755be670733418c994cf.zip
Merge pull request #1 from saurabhb17/develop
Secondary files
Diffstat (limited to 'common/gr_basic.cpp')
-rw-r--r--common/gr_basic.cpp1268
1 files changed, 1268 insertions, 0 deletions
diff --git a/common/gr_basic.cpp b/common/gr_basic.cpp
new file mode 100644
index 0000000..1e913cb
--- /dev/null
+++ b/common/gr_basic.cpp
@@ -0,0 +1,1268 @@
+/********************************/
+/* Low level graphics routines */
+/********************************/
+
+
+#include <fctsys.h>
+#include <gr_basic.h>
+#include <common.h>
+#include <trigo.h>
+#include <macros.h>
+#include <base_struct.h>
+#include <class_base_screen.h>
+#include <bezier_curves.h>
+#include <math_for_graphics.h>
+#include <wx/graphics.h>
+#if defined(__WXMAC__) && defined(USE_WX_GRAPHICS_CONTEXT)
+#include <wx/dcgraph.h>
+#endif
+
+static const bool FILLED = true;
+static const bool NOT_FILLED = false;
+
+/* Important Note:
+ * These drawing functions clip draw item before send these items to wxDC draw
+ * functions. For guy who asks why i did it, see a sample of problems encountered
+ * when pixels
+ * coordinates overflow 16 bits values:
+ * http://trac.wxwidgets.org/ticket/10446
+ * Problems can be found under Windows **and** Linux (mainly when drawing arcs)
+ * (mainly at low zoom values (2, 1 or 0.5), in Pcbnew)
+ * some of these problems could be now fixed in recent distributions.
+ *
+ * Currently (feb 2009) there are overflow problems when drawing solid (filled)
+ * polygons under linux without clipping
+ *
+ * So before removing clipping functions, be aware these bug (they are not in
+ * KiCad or wxWidgets) are fixed by testing how are drawn complex lines arcs
+ * and solid polygons under Windows and Linux and remember users can have old
+ * versions with bugs
+ */
+
+
+/* Definitions for enabling and disabling debugging features in gr_basic.cpp.
+ * Please remember to set these back to 0 before making LAUNCHPAD commits.
+ */
+#define DEBUG_DUMP_CLIP_ERROR_COORDS 0 // Set to 1 to dump clip algorithm errors.
+#define DEBUG_DUMP_CLIP_COORDS 0 // Set to 1 to dump clipped coordinates.
+
+
+// For draw mode = XOR GR_XOR or GR_NXOR by background color
+GR_DRAWMODE g_XorMode = GR_NXOR;
+
+
+static void ClipAndDrawPoly( EDA_RECT * ClipBox, wxDC * DC, wxPoint Points[],
+ int n );
+
+/* These functions are used by corresponding functions
+ * ( GRSCircle is called by GRCircle for instance) after mapping coordinates
+ * from user units to screen units(pixels coordinates)
+ */
+static void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1,
+ int x2, int y2, int aWidth, EDA_COLOR_T aColor,
+ wxPenStyle aStyle = wxPENSTYLE_SOLID );
+
+/**/
+
+static int GRLastMoveToX, GRLastMoveToY;
+static bool s_ForceBlackPen; /* if true: draws in black instead of
+ * color for printing. */
+static int xcliplo = 0,
+ ycliplo = 0,
+ xcliphi = 2000,
+ ycliphi = 2000;
+
+static EDA_COLOR_T s_DC_lastcolor = UNSPECIFIED_COLOR;
+static EDA_COLOR_T s_DC_lastbrushcolor = UNSPECIFIED_COLOR;
+static bool s_DC_lastbrushfill = false;
+static wxDC* s_DC_lastDC = NULL;
+
+/***
+ * Utility for the line clipping code, returns the boundary code of
+ * a point. Bit allocation is arbitrary
+ */
+static inline int clipOutCode( const EDA_RECT *aClipBox, int x, int y )
+{
+ int code;
+ if( y < aClipBox->GetY() )
+ code = 2;
+ else if( y > aClipBox->GetBottom() )
+ code = 1;
+ else
+ code = 0;
+ if( x < aClipBox->GetX() )
+ code |= 4;
+ else if( x > aClipBox->GetRight() )
+ code |= 8;
+ return code;
+}
+
+
+/**
+ * Test if any part of a line falls within the bounds of a rectangle.
+ *
+ * Please note that this is only accurate for lines that are one pixel wide.
+ *
+ * @param aClipBox - The rectangle to test.
+ * @param x1 - X coordinate of one end of a line.
+ * @param y1 - Y coordinate of one end of a line.
+ * @param x2 - X coordinate of the other end of a line.
+ * @param y2 - Y coordinate of the other end of a line.
+ *
+ * @return - False if any part of the line lies within the rectangle.
+ */
+static bool clipLine( const EDA_RECT *aClipBox, int &x1, int &y1, int &x2, int &y2 )
+{
+ // Stock Cohen-Sutherland algorithm; check *any* CG book for details
+ int outcode1 = clipOutCode( aClipBox, x1, y1 );
+ int outcode2 = clipOutCode( aClipBox, x2, y2 );
+
+ while( outcode1 || outcode2 )
+ {
+ // Fast reject
+ if( outcode1 & outcode2 )
+ return true;
+
+ // Choose a side to clip
+ int thisoutcode, x, y;
+ if( outcode1 )
+ thisoutcode = outcode1;
+ else
+ thisoutcode = outcode2;
+
+ /* One clip round
+ * Since we use the full range of 32 bit ints, the proportion
+ * computation has to be done in 64 bits to avoid horrible
+ * results */
+ if( thisoutcode & 1 ) // Clip the bottom
+ {
+ y = aClipBox->GetBottom();
+ x = x1 + (x2 - x1) * int64_t(y - y1) / (y2 - y1);
+ }
+ else if( thisoutcode & 2 ) // Clip the top
+ {
+ y = aClipBox->GetY();
+ x = x1 + (x2 - x1) * int64_t(y - y1) / (y2 - y1);
+ }
+ else if( thisoutcode & 8 ) // Clip the right
+ {
+ x = aClipBox->GetRight();
+ y = y1 + (y2 - y1) * int64_t(x - x1) / (x2 - x1);
+ }
+ else // if( thisoutcode & 4), obviously, clip the left
+ {
+ x = aClipBox->GetX();
+ y = y1 + (y2 - y1) * int64_t(x - x1) / (x2 - x1);
+ }
+
+ // Put the result back and update the boundary code
+ // No ambiguity, otherwise it would have been a fast reject
+ if( thisoutcode == outcode1 )
+ {
+ x1 = x;
+ y1 = y;
+ outcode1 = clipOutCode( aClipBox, x1, y1 );
+ }
+ else
+ {
+ x2 = x;
+ y2 = y;
+ outcode2 = clipOutCode( aClipBox, x2, y2 );
+ }
+ }
+ return false;
+}
+
+static void WinClipAndDrawLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width )
+{
+ GRLastMoveToX = x2;
+ GRLastMoveToY = y2;
+
+ if( ClipBox )
+ {
+ EDA_RECT clipbox(*ClipBox);
+ clipbox.Inflate(width/2);
+ if( clipLine( &clipbox, x1, y1, x2, y2 ) )
+ return;
+ }
+
+ DC->DrawLine( x1, y1, x2, y2 );
+}
+
+
+/* Forcing a reset of the current pen.
+ * Must be called after changing the graphical device before any trace.
+ */
+void GRResetPenAndBrush( wxDC* DC )
+{
+ GRSetBrush( DC, BLACK ); // Force no fill
+ s_DC_lastbrushcolor = UNSPECIFIED_COLOR;
+ s_DC_lastcolor = UNSPECIFIED_COLOR;
+ s_DC_lastDC = NULL;
+}
+
+
+/**
+ * Function GRSetColorPen
+ * sets a pen style, width, color, and alpha into the given device context.
+ */
+void GRSetColorPen( wxDC* DC, EDA_COLOR_T Color, int width, wxPenStyle style )
+{
+ // Under OSX and while printing when wxPen is set to 0, renderer follows the request drawing
+ // nothing & in the bitmap world the minimum is enough to light a pixel, in vectorial one not
+ if( width <= 1 )
+ width = DC->DeviceToLogicalXRel( 1 );
+
+ if( s_ForceBlackPen )
+ Color = BLACK;
+
+ wxColour wx_color = MakeColour( Color );
+ const wxPen& curr_pen = DC->GetPen();
+
+ if( !curr_pen.IsOk() || curr_pen.GetColour() != wx_color
+ || curr_pen.GetWidth() != width
+ || curr_pen.GetStyle() != style )
+ {
+ wxPen pen;
+ pen.SetColour( wx_color );
+ pen.SetWidth( width );
+ pen.SetStyle( style );
+ DC->SetPen( pen );
+ }
+ else
+ // Should be not needed, but on Linux, in printing process
+ // the curr pen settings needs to be sometimes re-initialized
+ // Clearly, this is due to a bug, related to SetBrush(),
+ // but we have to live with it, at least on wxWidgets 3.0
+ DC->SetPen( curr_pen );
+}
+
+
+void GRSetBrush( wxDC* DC, EDA_COLOR_T Color, bool fill )
+{
+ if( s_ForceBlackPen )
+ Color = BLACK;
+
+ if( s_DC_lastbrushcolor != Color
+ || s_DC_lastbrushfill != fill
+ || s_DC_lastDC != DC )
+ {
+ wxBrush brush;
+
+ brush.SetColour( MakeColour( Color ) );
+
+ if( fill )
+ brush.SetStyle( wxBRUSHSTYLE_SOLID );
+ else
+ brush.SetStyle( wxBRUSHSTYLE_TRANSPARENT );
+
+ DC->SetBrush( brush );
+
+ s_DC_lastbrushcolor = Color;
+ s_DC_lastbrushfill = fill;
+ s_DC_lastDC = DC;
+ }
+}
+
+
+/**
+ * Function GRForceBlackPen
+ * @param flagforce True to force a black pen whenever the asked color
+ */
+void GRForceBlackPen( bool flagforce )
+{
+ s_ForceBlackPen = flagforce;
+}
+
+
+/**
+ * Function GetGRForceBlackPenState
+ * @return s_ForceBlackPen (True if a black pen was forced)
+ */
+bool GetGRForceBlackPenState( void )
+{
+ return s_ForceBlackPen;
+}
+
+
+/*************************************/
+/* Set the device context draw mode. */
+/*************************************/
+void GRSetDrawMode( wxDC* DC, GR_DRAWMODE draw_mode )
+{
+ if( draw_mode & GR_OR )
+#if defined(__WXMAC__) && (wxMAC_USE_CORE_GRAPHICS || wxCHECK_VERSION( 2, 9, 0 ) )
+
+ DC->SetLogicalFunction( wxCOPY );
+#elif defined( USE_WX_GRAPHICS_CONTEXT )
+
+ DC->SetLogicalFunction( wxCOPY );
+#else
+
+ DC->SetLogicalFunction( wxOR );
+#endif
+ else if( draw_mode & GR_XOR )
+#if defined( USE_WX_GRAPHICS_CONTEXT )
+
+ DC->SetLogicalFunction( wxCOPY );
+#else
+
+ DC->SetLogicalFunction( wxXOR );
+#endif
+ else if( draw_mode & GR_NXOR )
+#if defined(__WXMAC__) && (wxMAC_USE_CORE_GRAPHICS || wxCHECK_VERSION( 2, 9, 0 ) )
+
+ DC->SetLogicalFunction( wxXOR );
+#elif defined( USE_WX_GRAPHICS_CONTEXT )
+
+ DC->SetLogicalFunction( wxCOPY );
+#else
+
+ DC->SetLogicalFunction( wxEQUIV );
+#endif
+ else if( draw_mode & GR_INVERT )
+#if defined( USE_WX_GRAPHICS_CONTEXT )
+
+ DC->SetLogicalFunction( wxCOPY );
+#else
+
+ DC->SetLogicalFunction( wxINVERT );
+#endif
+ else if( draw_mode & GR_COPY )
+ DC->SetLogicalFunction( wxCOPY );
+
+#ifdef USE_WX_OVERLAY
+ DC->SetLogicalFunction( wxCOPY );
+#endif
+}
+
+
+void GRPutPixel( EDA_RECT* ClipBox, wxDC* DC, int x, int y, EDA_COLOR_T Color )
+{
+ if( ClipBox && !ClipBox->Contains( x, y ) )
+ return;
+
+ GRSetColorPen( DC, Color );
+ DC->DrawPoint( x, y );
+}
+
+
+/*
+ * Draw a line, in object space.
+ */
+void GRLine( EDA_RECT* ClipBox,
+ wxDC* DC,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int width,
+ EDA_COLOR_T Color )
+{
+ GRSetColorPen( DC, Color, width );
+ WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, width );
+ GRLastMoveToX = x2;
+ GRLastMoveToY = y2;
+}
+
+
+void GRLine( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd, int aWidth, EDA_COLOR_T aColor )
+{
+ GRLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, aColor );
+}
+
+
+void GRDashedLine( EDA_RECT* ClipBox, wxDC* DC,
+ int x1, int y1, int x2, int y2,
+ int width, EDA_COLOR_T Color )
+{
+ GRLastMoveToX = x2;
+ GRLastMoveToY = y2;
+ s_DC_lastcolor = UNSPECIFIED_COLOR;
+ GRSetColorPen( DC, Color, width, wxPENSTYLE_SHORT_DASH );
+ WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, width );
+ s_DC_lastcolor = UNSPECIFIED_COLOR;
+ GRSetColorPen( DC, Color, width );
+}
+
+
+/*
+ * Move to a new position, in object space.
+ */
+void GRMoveTo( int x, int y )
+{
+ GRLastMoveToX = x;
+ GRLastMoveToY = y;
+}
+
+
+/*
+ * Draw line to a new position, in object space.
+ */
+void GRLineTo( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int width, EDA_COLOR_T Color )
+{
+ GRLine( ClipBox, DC, GRLastMoveToX, GRLastMoveToY, x, y, width, Color );
+}
+
+
+void GRMixedLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ int width, EDA_COLOR_T Color )
+{
+ GRSetColorPen( DC, Color, width, wxPENSTYLE_DOT_DASH );
+ GRLine( ClipBox, DC, x1, y1, x2, y2, width, Color );
+ GRSetColorPen( DC, Color, width );
+}
+
+
+
+/**
+ * Function GRLineArray
+ * draws an array of lines (not a polygon).
+ * @param aClipBox = the clip box
+ * @param aDC = the device context into which drawing should occur.
+ * @param aLines = a list of pair of coordinate in user space: a pair for each line.
+ * @param aWidth = the width of each line.
+ * @param aColor = an index into our color table of RGB colors.
+ * @see EDA_COLOR_T and colors.h
+ */
+void GRLineArray( EDA_RECT* aClipBox, wxDC* aDC, std::vector<wxPoint>& aLines,
+ int aWidth, EDA_COLOR_T aColor )
+{
+ GRSetColorPen( aDC, aColor, aWidth );
+
+ if( aClipBox )
+ aClipBox->Inflate(aWidth/2);
+
+#if defined( __WXMAC__ ) && defined( USE_WX_GRAPHICS_CONTEXT )
+ wxGCDC *gcdc = wxDynamicCast( aDC, wxGCDC );
+ if( gcdc )
+ {
+ wxGraphicsContext *gc = gcdc->GetGraphicsContext();
+
+ // create path
+ wxGraphicsPath path = gc->CreatePath();
+ for( unsigned i = 0; i < aLines.size(); i += 2 )
+ {
+ int x1 = aLines[i].x;
+ int y1 = aLines[i].y;
+ int x2 = aLines[i+1].x;
+ int y2 = aLines[i+1].y;
+ if( ( aClipBox == NULL ) || !clipLine( aClipBox, x1, y1, x2, y2 ) )
+ {
+ path.MoveToPoint( x1, y1 );
+ path.AddLineToPoint( x2, y2 );
+ }
+ }
+ // draw path
+ gc->StrokePath( path );
+ }
+ else
+#endif
+ {
+ for( unsigned i = 0; i < aLines.size(); i += 2 )
+ {
+ int x1 = aLines[i].x;
+ int y1 = aLines[i].y;
+ int x2 = aLines[i+1].x;
+ int y2 = aLines[i+1].y;
+ if( ( aClipBox == NULL ) || !clipLine( aClipBox, x1, y1, x2, y2 ) )
+ aDC->DrawLine( x1, y1, x2, y2 );
+ }
+ }
+ GRMoveTo( aLines[aLines.size() - 1].x, aLines[aLines.size() - 1].y );
+
+ if( aClipBox )
+ aClipBox->Inflate(-aWidth/2);
+}
+
+// Draw the outline of a thick segment wih rounded ends
+void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ int width, int aPenSize, EDA_COLOR_T Color )
+{
+ GRLastMoveToX = x2;
+ GRLastMoveToY = y2;
+
+ if( ClipBox )
+ {
+ EDA_RECT clipbox(*ClipBox);
+ clipbox.Inflate(width/2);
+
+ if( clipLine( &clipbox, x1, y1, x2, y2 ) )
+ return;
+ }
+
+
+ if( width <= 2 ) /* single line or 2 pixels */
+ {
+ GRSetColorPen( DC, Color, width );
+ DC->DrawLine( x1, y1, x2, y2 );
+ return;
+ }
+
+ GRSetBrush( DC, Color, NOT_FILLED );
+ GRSetColorPen( DC, Color, aPenSize );
+
+ int radius = (width + 1) >> 1;
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+ double angle = -ArcTangente( dy, dx );
+ wxPoint start;
+ wxPoint end;
+ wxPoint org( x1, y1);
+ int len = (int) hypot( dx, dy );
+
+ // We know if the DC is mirrored, to draw arcs
+ int slx = DC->DeviceToLogicalX( 1 ) - DC->DeviceToLogicalX( 0 );
+ int sly = DC->DeviceToLogicalY( 1 ) - DC->DeviceToLogicalY( 0 );
+ bool mirrored = (slx > 0 && sly < 0) || (slx < 0 && sly > 0);
+
+ // first edge
+ start.x = 0;
+ start.y = radius;
+ end.x = len;
+ end.y = radius;
+ RotatePoint( &start, angle);
+ RotatePoint( &end, angle);
+
+ start += org;
+ end += org;
+
+ DC->DrawLine( start, end );
+
+ // first rounded end
+ end.x = 0;
+ end.y = -radius;
+ RotatePoint( &end, angle);
+ end += org;
+
+ if( !mirrored )
+ DC->DrawArc( end, start, org );
+ else
+ DC->DrawArc( start, end, org );
+
+
+ // second edge
+ start.x = len;
+ start.y = -radius;
+ RotatePoint( &start, angle);
+ start += org;
+
+ DC->DrawLine( start, end );
+
+ // second rounded end
+ end.x = len;
+ end.y = radius;
+ RotatePoint( &end, angle);
+ end += org;
+
+ if( !mirrored )
+ DC->DrawArc( end.x, end.y, start.x, start.y, x2, y2 );
+ else
+ DC->DrawArc( start.x, start.y, end.x, end.y, x2, y2 );
+}
+
+
+void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ int width, EDA_COLOR_T Color )
+{
+ GRCSegm( ClipBox, DC, x1, y1, x2, y2, width, 0, Color );
+}
+
+
+void GRCSegm( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd,
+ int aWidth, EDA_COLOR_T aColor )
+{
+ GRCSegm( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth, 0, aColor );
+}
+
+
+/*
+ * Draw segment (full) with rounded ends in object space (real coords.).
+ */
+void GRFillCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ int width, EDA_COLOR_T Color )
+{
+ GRSetColorPen( DC, Color, width );
+ WinClipAndDrawLine( ClipBox, DC, x1, y1, x2, y2, width );
+}
+
+
+void GRFilledSegment( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd,
+ int aWidth, EDA_COLOR_T aColor )
+{
+ GRSetColorPen( aDC, aColor, aWidth );
+ WinClipAndDrawLine( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aWidth );
+}
+
+
+static bool IsGRSPolyDrawable( EDA_RECT* ClipBox, int n, wxPoint Points[] )
+{
+ if( !ClipBox )
+ return true;
+
+ if( n <= 0 )
+ return false;
+
+ int Xmin, Xmax, Ymin, Ymax;
+
+ Xmin = Xmax = Points[0].x;
+ Ymin = Ymax = Points[0].y;
+
+ for( int ii = 1; ii < n; ii++ ) // calculate rectangle
+ {
+ Xmin = std::min( Xmin, Points[ii].x );
+ Xmax = std::max( Xmax, Points[ii].x );
+ Ymin = std::min( Ymin, Points[ii].y );
+ Ymax = std::max( Ymax, Points[ii].y );
+ }
+
+ xcliplo = ClipBox->GetX();
+ ycliplo = ClipBox->GetY();
+ xcliphi = ClipBox->GetRight();
+ ycliphi = ClipBox->GetBottom();
+
+ if( Xmax < xcliplo )
+ return false;
+ if( Xmin > xcliphi )
+ return false;
+ if( Ymax < ycliplo )
+ return false;
+ if( Ymin > ycliphi )
+ return false;
+
+ return true;
+}
+
+
+/*
+ * Draw a new polyline and fill it if Fill, in screen space.
+ */
+static void GRSPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
+ bool Fill, int width,
+ EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ if( !IsGRSPolyDrawable( ClipBox, n, Points ) )
+ return;
+
+ if( Fill && ( n > 2 ) )
+ {
+ GRSetBrush( DC, BgColor, FILLED );
+ GRSetColorPen( DC, Color, width );
+
+ /* clip before send the filled polygon to wxDC, because under linux
+ * (GTK?) polygons having large coordinates are incorrectly drawn
+ * (integer overflow in coordinates, I am guessing)
+ */
+ ClipAndDrawPoly( ClipBox, DC, Points, n );
+ }
+ else
+ {
+#if defined( __WXMAC__ ) && defined( USE_WX_GRAPHICS_CONTEXT )
+ wxGCDC *gcdc = wxDynamicCast( DC, wxGCDC );
+ if( gcdc )
+ {
+ wxGraphicsContext *gc = gcdc->GetGraphicsContext();
+
+ // set pen
+ GRSetColorPen( DC, Color, width );
+
+ // create path
+ wxGraphicsPath path = gc->CreatePath();
+ path.MoveToPoint( Points[0].x, Points[0].y );
+ for( int i = 1; i < n; ++i )
+ {
+ path.AddLineToPoint( Points[i].x, Points[i].y );
+ }
+ // draw path
+ gc->StrokePath( path );
+
+ // correctly update last position
+ GRMoveTo( Points[n - 1].x, Points[n - 1].y );
+ }
+ else
+#endif
+ {
+ GRMoveTo( Points[0].x, Points[0].y );
+ for( int i = 1; i < n; ++i )
+ {
+ GRLineTo( ClipBox, DC, Points[i].x, Points[i].y, width, Color );
+ }
+ }
+ }
+}
+
+
+/*
+ * Draw a new closed polyline and fill it if Fill, in screen space.
+ */
+static void GRSClosedPoly( EDA_RECT* aClipBox, wxDC* aDC,
+ int aPointCount, wxPoint aPoints[],
+ bool aFill, int aWidth,
+ EDA_COLOR_T aColor,
+ EDA_COLOR_T aBgColor )
+{
+ if( !IsGRSPolyDrawable( aClipBox, aPointCount, aPoints ) )
+ return;
+
+ if( aFill && ( aPointCount > 2 ) )
+ {
+ GRLastMoveToX = aPoints[aPointCount - 1].x;
+ GRLastMoveToY = aPoints[aPointCount - 1].y;
+ GRSetBrush( aDC, aBgColor, FILLED );
+ GRSetColorPen( aDC, aColor, aWidth );
+ ClipAndDrawPoly( aClipBox, aDC, aPoints, aPointCount );
+ }
+ else
+ {
+#if defined( __WXMAC__ ) && defined( USE_WX_GRAPHICS_CONTEXT )
+ wxGCDC *gcdc = wxDynamicCast( aDC, wxGCDC );
+ if( gcdc )
+ {
+ wxGraphicsContext *gc = gcdc->GetGraphicsContext();
+
+ // set pen
+ GRSetColorPen( aDC, aColor, aWidth );
+
+ // create path
+ wxGraphicsPath path = gc->CreatePath();
+ path.MoveToPoint( aPoints[0].x, aPoints[0].y );
+ for( int i = 1; i < aPointCount; ++i )
+ {
+ path.AddLineToPoint( aPoints[i].x, aPoints[i].y );
+ }
+ if( aPoints[aPointCount - 1] != aPoints[0] )
+ path.AddLineToPoint( aPoints[0].x, aPoints[0].y );
+ // draw path
+ gc->StrokePath( path );
+
+ // correctly update last position
+ GRMoveTo( aPoints[aPointCount - 1].x, aPoints[aPointCount - 1].y );
+ }
+ else
+#endif
+ {
+ GRMoveTo( aPoints[0].x, aPoints[0].y );
+ for( int i = 1; i < aPointCount; ++i )
+ {
+ GRLineTo( aClipBox, aDC, aPoints[i].x, aPoints[i].y, aWidth, aColor );
+ }
+
+ int lastpt = aPointCount - 1;
+
+ // Close the polygon
+ if( aPoints[lastpt] != aPoints[0] )
+ {
+ GRLineTo( aClipBox, aDC, aPoints[0].x, aPoints[0].y, aWidth, aColor );
+ }
+ }
+ }
+}
+
+
+/*
+ * Draw a new polyline and fill it if Fill, in drawing space.
+ */
+void GRPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
+ bool Fill, int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ GRSPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
+}
+
+
+/*
+ * Draw a closed polyline and fill it if Fill, in object space.
+ */
+void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
+ bool Fill, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ GRClosedPoly( ClipBox, DC, n, Points, Fill, 0, Color, BgColor );
+}
+
+
+void GRClosedPoly( EDA_RECT* ClipBox, wxDC* DC, int n, wxPoint Points[],
+ bool Fill, int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ GRSClosedPoly( ClipBox, DC, n, Points, Fill, width, Color, BgColor );
+}
+
+
+void GRCircle( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, int r, int width, EDA_COLOR_T Color )
+{
+ /* Clip circles off screen. */
+ if( ClipBox )
+ {
+ int x0, y0, xm, ym;
+ x0 = ClipBox->GetX();
+ y0 = ClipBox->GetY();
+ xm = ClipBox->GetRight();
+ ym = ClipBox->GetBottom();
+
+ if( xc < ( x0 - r - width ) )
+ return;
+
+ if( yc < ( y0 - r - width ) )
+ return;
+
+ if( xc > ( r + xm + width ) )
+ return;
+
+ if( yc > ( r + ym + width ) )
+ return;
+ }
+
+ GRSetBrush( DC, Color, NOT_FILLED );
+ GRSetColorPen( DC, Color, width );
+ DC->DrawEllipse( xc - r, yc - r, r + r, r + r );
+}
+
+
+void GRCircle( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int r, EDA_COLOR_T Color )
+{
+ GRCircle( ClipBox, DC, x, y, r, 0, Color );
+}
+
+
+void GRCircle( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aPos, int aRadius, int aWidth, EDA_COLOR_T aColor )
+{
+ GRCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, aWidth, aColor );
+}
+
+
+void GRFilledCircle( EDA_RECT* ClipBox, wxDC* DC, int x, int y, int r,
+ int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ /* Clip circles off screen. */
+ if( ClipBox )
+ {
+ int x0, y0, xm, ym;
+ x0 = ClipBox->GetX();
+ y0 = ClipBox->GetY();
+ xm = ClipBox->GetRight();
+ ym = ClipBox->GetBottom();
+
+ if( x < ( x0 - r ) )
+ return;
+
+ if( y < ( y0 - r ) )
+ return;
+
+ if( x > ( r + xm ) )
+ return;
+
+ if( y > ( r + ym ) )
+ return;
+ }
+
+ GRSetBrush( DC, BgColor, FILLED );
+ GRSetColorPen( DC, Color, width );
+ DC->DrawEllipse( x - r, y - r, r + r, r + r );
+}
+
+
+void GRFilledCircle( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aPos, int aRadius, EDA_COLOR_T aColor )
+{
+ GRFilledCircle( aClipBox, aDC, aPos.x, aPos.y, aRadius, 0, aColor, aColor );
+}
+
+
+/*
+ * Draw an arc in user space.
+ */
+void GRArc1( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ int xc, int yc, EDA_COLOR_T Color )
+{
+ GRArc1( ClipBox, DC, x1, y1, x2, y2, xc, yc, 0, Color );
+}
+
+
+/*
+ * Draw an arc, width = width in user space.
+ */
+void GRArc1( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ int xc, int yc, int width, EDA_COLOR_T Color )
+{
+ /* Clip arcs off screen. */
+ if( ClipBox )
+ {
+ int x0, y0, xm, ym, r;
+ x0 = ClipBox->GetX();
+ y0 = ClipBox->GetY();
+ xm = ClipBox->GetRight();
+ ym = ClipBox->GetBottom();
+ r = KiROUND( Distance( x1, y1, xc, yc ) );
+ if( xc < ( x0 - r ) )
+ return;
+ if( yc < ( y0 - r ) )
+ return;
+ if( xc > ( r + xm ) )
+ return;
+ if( yc > ( r + ym ) )
+ return;
+ }
+
+ GRSetBrush( DC, Color );
+ GRSetColorPen( DC, Color, width );
+ DC->DrawArc( x1, y1, x2, y2, xc, yc );
+}
+
+
+void GRArc1( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aStart, wxPoint aEnd,
+ wxPoint aCenter, int aWidth, EDA_COLOR_T aColor )
+{
+ GRArc1( aClipBox, aDC, aStart.x, aStart.y, aEnd.x, aEnd.y, aCenter.x, aCenter.y,
+ aWidth, aColor );
+}
+
+
+/*
+ * Draw a filled arc in drawing space.
+ */
+void GRFilledArc( EDA_RECT* ClipBox,
+ wxDC* DC,
+ int x,
+ int y,
+ double StAngle,
+ double EndAngle,
+ int r,
+ int width,
+ EDA_COLOR_T Color,
+ EDA_COLOR_T BgColor )
+{
+ int x1, y1, x2, y2;
+
+ /* Clip arcs off screen */
+ if( ClipBox )
+ {
+ int x0, y0, xm, ym;
+ x0 = ClipBox->GetX();
+ y0 = ClipBox->GetY();
+ xm = ClipBox->GetRight();
+ ym = ClipBox->GetBottom();
+
+ if( x < ( x0 - r - 1 ) )
+ return;
+
+ if( y < ( y0 - r - 1 ) )
+ return;
+
+ if( x > ( r + xm + 1 ) )
+ return;
+
+ if( y > ( r + ym + 1 ) )
+ return;
+ }
+
+ x1 = r;
+ y1 = 0;
+ RotatePoint( &x1, &y1, EndAngle );
+
+ x2 = r;
+ y2 = 0;
+ RotatePoint( &x2, &y2, StAngle );
+
+ GRSetBrush( DC, BgColor, FILLED );
+ GRSetColorPen( DC, Color, width );
+ DC->DrawArc( x + x1, y - y1, x + x2, y - y2, x, y );
+}
+
+
+void GRFilledArc( EDA_RECT* ClipBox, wxDC* DC, int x, int y,
+ double StAngle, double EndAngle, int r,
+ EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ GRFilledArc( ClipBox, DC, x, y, StAngle, EndAngle, r, 0, Color, BgColor );
+}
+
+
+/*
+ * Draw an arc in drawing space.
+ */
+void GRArc( EDA_RECT* ClipBox, wxDC* DC, int xc, int yc, double StAngle,
+ double EndAngle, int r, EDA_COLOR_T Color )
+{
+ int x1, y1, x2, y2;
+
+ /* Clip arcs off screen */
+ if( ClipBox )
+ {
+ int radius = r + 1;
+ int x0, y0, xm, ym, x, y;
+ x0 = ClipBox->GetX();
+ y0 = ClipBox->GetY();
+ xm = ClipBox->GetRight();
+ ym = ClipBox->GetBottom();
+ x = xc;
+ y = yc;
+
+ if( x < ( x0 - radius ) )
+ return;
+ if( y < ( y0 - radius ) )
+ return;
+ if( x > ( xm + radius ) )
+ return;
+ if( y > ( ym + radius ) )
+ return;
+ }
+
+ x1 = r;
+ y1 = 0;
+ RotatePoint( &x1, &y1, EndAngle );
+
+ x2 = r;
+ y2 = 0;
+ RotatePoint( &x2, &y2, StAngle );
+
+ GRSetBrush( DC, Color, NOT_FILLED );
+ GRSetColorPen( DC, Color );
+ DC->DrawArc( xc + x1, yc - y1, xc + x2, yc - y2, xc, yc );
+}
+
+
+/*
+ * Draw an arc with width = width in drawing space.
+ */
+void GRArc( EDA_RECT* ClipBox,
+ wxDC* DC,
+ int x,
+ int y,
+ double StAngle,
+ double EndAngle,
+ int r,
+ int width,
+ EDA_COLOR_T Color )
+{
+ int x1, y1, x2, y2;
+
+ /* Clip arcs off screen. */
+ if( ClipBox )
+ {
+ int x0, y0, xm, ym;
+ x0 = ClipBox->GetX();
+ y0 = ClipBox->GetY();
+ xm = ClipBox->GetRight();
+ ym = ClipBox->GetBottom();
+
+ if( x < ( x0 - r - width ) )
+ return;
+
+ if( y < ( y0 - r - width ) )
+ return;
+
+ if( x > ( r + xm + width ) )
+ return;
+
+ if( y > ( r + ym + width ) )
+ return;
+ }
+
+ x1 = r;
+ y1 = 0;
+ RotatePoint( &x1, &y1, EndAngle );
+
+ x2 = r;
+ y2 = 0;
+ RotatePoint( &x2, &y2, StAngle );
+
+ GRSetBrush( DC, Color );
+ GRSetColorPen( DC, Color, width );
+ DC->DrawArc( x + x1, y - y1, x + x2, y - y2, x, y );
+}
+
+
+/*
+ * Draw a rectangle in drawing space.
+ */
+void GRRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2, EDA_COLOR_T aColor )
+{
+ GRSRect( aClipBox, aDC, x1, y1, x2, y2, 0, aColor );
+}
+
+
+void GRRectPs( EDA_RECT* aClipBox, wxDC* aDC, const EDA_RECT& aRect, EDA_COLOR_T aColor, wxPenStyle aStyle )
+{
+ int x1 = aRect.GetX();
+ int y1 = aRect.GetY();
+ int x2 = aRect.GetRight();
+ int y2 = aRect.GetBottom();
+
+ GRSRect( aClipBox, aDC, x1, y1, x2, y2, 0, aColor, aStyle );
+}
+
+
+/*
+ * Draw a rectangle (thick lines) in drawing space.
+ */
+void GRRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, int width, EDA_COLOR_T Color )
+{
+ GRSRect( ClipBox, DC, x1, y1, x2, y2, width, Color );
+}
+
+
+void GRRect( EDA_RECT* aClipBox, wxDC* aDC, const EDA_RECT& aRect, int aWidth, EDA_COLOR_T aColor )
+{
+ int x1 = aRect.GetX();
+ int y1 = aRect.GetY();
+ int x2 = aRect.GetRight();
+ int y2 = aRect.GetBottom();
+
+ GRSRect( aClipBox, aDC, x1, y1, x2, y2, aWidth, aColor );
+}
+
+
+/*
+ * Draw a rectangle (filled with AreaColor) in drawing space.
+ */
+void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, 0, Color, BgColor );
+}
+
+
+/*
+ * Draw a rectangle (filled with AreaColor) in drawing space.
+ */
+void GRFilledRect( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2,
+ int width, EDA_COLOR_T Color, EDA_COLOR_T BgColor )
+{
+ GRSFilledRect( ClipBox, DC, x1, y1, x2, y2, width, Color, BgColor );
+}
+
+
+/*
+ * Draw a rectangle in screen space.
+ */
+
+void GRSRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2,
+ int aWidth, EDA_COLOR_T aColor, wxPenStyle aStyle )
+{
+ wxPoint points[5];
+ points[0] = wxPoint(x1, y1);
+ points[1] = wxPoint(x1, y2);
+ points[2] = wxPoint(x2, y2);
+ points[3] = wxPoint(x2, y1);
+ points[4] = points[0];
+ GRSClosedPoly( aClipBox, aDC, 5, points, NOT_FILLED, aWidth,
+ aColor, aColor );
+}
+
+
+void GRSFilledRect( EDA_RECT* aClipBox, wxDC* aDC, int x1, int y1, int x2, int y2,
+ int aWidth, EDA_COLOR_T aColor, EDA_COLOR_T aBgColor )
+{
+ wxPoint points[5];
+ points[0] = wxPoint(x1, y1);
+ points[1] = wxPoint(x1, y2);
+ points[2] = wxPoint(x2, y2);
+ points[3] = wxPoint(x2, y1);
+ points[4] = points[0];
+
+ GRSetBrush( aDC, aBgColor, FILLED );
+ GRSetColorPen( aDC, aBgColor, aWidth );
+
+ if( aClipBox && (aWidth > 0) )
+ {
+ EDA_RECT clipbox(*aClipBox);
+ clipbox.Inflate(aWidth);
+ ClipAndDrawPoly(&clipbox, aDC, points, 5); // polygon approach is more accurate
+ }
+ else
+ ClipAndDrawPoly(aClipBox, aDC, points, 5 );
+}
+
+/**
+ * Function ClipAndDrawPoly
+ * Used to clip a polygon and draw it as Filled Polygon
+ * uses the Sutherland and Hodgman algo to clip the given poly against a
+ * rectangle. This rectangle is the drawing area this is useful under
+ * Linux (2009) because filled polygons are incorrectly drawn if they have
+ * too large coordinates (seems due to integer overflows in calculations)
+ * Could be removed in some years, if become unnecessary.
+ */
+
+/* Note: aClipBox == NULL is legal, so if aClipBox == NULL,
+ * the polygon is drawn, but not clipped
+ */
+#include <SutherlandHodgmanClipPoly.h>
+
+void ClipAndDrawPoly( EDA_RECT* aClipBox, wxDC* aDC, wxPoint aPoints[], int n )
+{
+ if( aClipBox == NULL )
+ {
+ aDC->DrawPolygon( n, aPoints );
+ return;
+ }
+
+ // A clip box exists: clip and draw the polygon.
+ static std::vector<wxPoint> clippedPolygon;
+ static pointVector inputPolygon, outputPolygon;
+
+ inputPolygon.clear();
+ outputPolygon.clear();
+ clippedPolygon.clear();
+
+ for( int ii = 0; ii < n; ii++ )
+ inputPolygon.push_back( PointF( (REAL) aPoints[ii].x, (REAL) aPoints[ii].y ) );
+
+ RectF window( (REAL) aClipBox->GetX(), (REAL) aClipBox->GetY(),
+ (REAL) aClipBox->GetWidth(), (REAL) aClipBox->GetHeight() );
+
+ SutherlandHodgman sh( window );
+ sh.Clip( inputPolygon, outputPolygon );
+
+ for( cpointIterator cit = outputPolygon.begin(); cit != outputPolygon.end(); ++cit )
+ {
+ clippedPolygon.push_back( wxPoint( KiROUND( cit->X ), KiROUND( cit->Y ) ) );
+ }
+
+ if( clippedPolygon.size() )
+ aDC->DrawPolygon( clippedPolygon.size(), &clippedPolygon[0] );
+}
+
+
+void GRBezier( EDA_RECT* ClipBox,
+ wxDC* DC,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int x3,
+ int y3,
+ int width,
+ EDA_COLOR_T Color )
+{
+ std::vector<wxPoint> Points = Bezier2Poly( x1, y1, x2, y2, x3, y3 );
+ GRPoly( ClipBox, DC, Points.size(), &Points[0], false, width, Color, Color );
+}
+
+
+void GRBezier( EDA_RECT* ClipBox,
+ wxDC* DC,
+ int x1,
+ int y1,
+ int x2,
+ int y2,
+ int x3,
+ int y3,
+ int x4,
+ int y4,
+ int width,
+ EDA_COLOR_T Color )
+{
+ std::vector<wxPoint> Points = Bezier2Poly( x1, y1, x2, y2, x3, y3, x4, y4 );
+ GRPoly( ClipBox, DC, Points.size(), &Points[0], false, width, Color, Color );
+}
+
+
+void GRDrawAnchor( EDA_RECT *aClipBox, wxDC *aDC, int x, int y,
+ int aSize, EDA_COLOR_T aColor )
+{
+ int anchor_size = aDC->DeviceToLogicalXRel( aSize );
+
+ GRLine( aClipBox, aDC,
+ x - anchor_size, y,
+ x + anchor_size, y, 0, aColor );
+ GRLine( aClipBox, aDC,
+ x, y - anchor_size,
+ x, y + anchor_size, 0, aColor );
+}