diff --git a/common/geometry/geometry_utils.cpp b/common/geometry/geometry_utils.cpp index 03f575c32e..75ce88c9a6 100644 --- a/common/geometry/geometry_utils.cpp +++ b/common/geometry/geometry_utils.cpp @@ -27,6 +27,7 @@ * @brief a few functions useful in geometry calculations. */ +#include #include int GetArcToSegmentCount( int aRadius, int aErrorMax, double aArcAngleDegree ) @@ -61,3 +62,87 @@ double GetCircletoPolyCorrectionFactor( int aSegCountforCircle ) return 1.0 / cos( M_PI / aSegCountforCircle ); } + +/*** + * Utility for the line clipping code, returns the boundary code of + * a point. Bit allocation is arbitrary + */ +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; +} + + +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; +} + diff --git a/common/gr_basic.cpp b/common/gr_basic.cpp index 692cb7aaaf..92503fe54e 100644 --- a/common/gr_basic.cpp +++ b/common/gr_basic.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #if defined(__WXMAC__) && defined(USE_WX_GRAPHICS_CONTEXT) #include #endif @@ -99,102 +100,6 @@ static COLOR4D s_DC_lastbrushcolor( 0, 0, 0, 0 ); 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; @@ -204,7 +109,7 @@ static void WinClipAndDrawLine( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int { EDA_RECT clipbox(*ClipBox); clipbox.Inflate(width/2); - if( clipLine( &clipbox, x1, y1, x2, y2 ) ) + if( ClipLine( &clipbox, x1, y1, x2, y2 ) ) return; } @@ -478,7 +383,7 @@ void GRLineArray( EDA_RECT* aClipBox, wxDC* aDC, std::vector& aLines, 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 ) ) + if( ( aClipBox == NULL ) || !ClipLine( aClipBox, x1, y1, x2, y2 ) ) { path.MoveToPoint( x1, y1 ); path.AddLineToPoint( x2, y2 ); @@ -496,7 +401,7 @@ void GRLineArray( EDA_RECT* aClipBox, wxDC* aDC, std::vector& aLines, 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 ) ) + if( ( aClipBox == NULL ) || !ClipLine( aClipBox, x1, y1, x2, y2 ) ) aDC->DrawLine( x1, y1, x2, y2 ); } } @@ -518,7 +423,7 @@ void GRCSegm( EDA_RECT* ClipBox, wxDC* DC, int x1, int y1, int x2, int y2, EDA_RECT clipbox(*ClipBox); clipbox.Inflate(width/2); - if( clipLine( &clipbox, x1, y1, x2, y2 ) ) + if( ClipLine( &clipbox, x1, y1, x2, y2 ) ) return; } diff --git a/common/plotters/plotter.cpp b/common/plotters/plotter.cpp index 489508cc90..d692e67e71 100644 --- a/common/plotters/plotter.cpp +++ b/common/plotters/plotter.cpp @@ -48,7 +48,7 @@ #include #include #include - +#include PLOTTER::PLOTTER( ) { @@ -65,9 +65,6 @@ PLOTTER::PLOTTER( ) // Temporary init to avoid not initialized vars, will be set later m_IUsPerDecimil = 1; // will be set later to the actual value iuPerDeviceUnit = 1; // will be set later to the actual value - m_dotMarkLength_mm = 0.1; // Dotted line parameter in mm: segment - // Dashed line parameter is 5 * dotted line mark - // Dashed line gap is 3 * dotted line mark } PLOTTER::~PLOTTER() @@ -134,24 +131,26 @@ double PLOTTER::userToDeviceSize( double size ) const } +#define IU_PER_MILS ( m_IUsPerDecimil * 10 ) + double PLOTTER::GetDotMarkLenIU() const { - return userToDeviceSize( std::max( 1.0, - m_dotMarkLength_mm * 10000 / 25.4 * m_IUsPerDecimil - GetCurrentLineWidth() ) ); + return userToDeviceSize( DOT_MARK_LEN( GetCurrentLineWidth() ) ); } double PLOTTER::GetDashMarkLenIU() const { - return std::max( GetDashGapLenIU(), 5.0 * GetDotMarkLenIU() ); + return userToDeviceSize( DASH_MARK_LEN( GetCurrentLineWidth() ) ); } double PLOTTER::GetDashGapLenIU() const { - return 3.0 * GetDotMarkLenIU() + userToDeviceSize( 2 * GetCurrentLineWidth() ); + return userToDeviceSize( DASH_GAP_LEN( GetCurrentLineWidth() ) ); } + void PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius, FILL_T fill, int width ) { diff --git a/eeschema/sch_painter.cpp b/eeschema/sch_painter.cpp index 57f384e9fa..3b2428fb43 100644 --- a/eeschema/sch_painter.cpp +++ b/eeschema/sch_painter.cpp @@ -44,9 +44,9 @@ #include #include #include - +#include #include - +#include #include #include #include @@ -57,8 +57,6 @@ #include "sch_painter.h" -#include - namespace KIGFX { @@ -899,10 +897,58 @@ void SCH_PAINTER::draw( SCH_LINE *aLine, int aLayer ) int width = aLine->GetPenSize(); - m_gal->SetIsStroke(true); + m_gal->SetIsStroke( true ); m_gal->SetStrokeColor(color); m_gal->SetLineWidth( width ); - m_gal->DrawLine( aLine->GetStartPoint(), aLine->GetEndPoint() ); + + if( aLine->GetLineStyle() <= PLOTDASHTYPE_SOLID ) + { + m_gal->DrawLine( aLine->GetStartPoint(), aLine->GetEndPoint() ); + } + else + { + VECTOR2D start = aLine->GetStartPoint(); + VECTOR2D end = aLine->GetEndPoint(); + + EDA_RECT clip( wxPoint( start.x, start.y ), wxSize( end.x - start.x, end.y - start.y ) ); + clip.Normalize(); + + double theta = atan2( end.y - start.y, end.x - start.x ); + double strokes[] = { 1.0, DASH_GAP_LEN( width ), 1.0, DASH_GAP_LEN( width ) }; + + switch( aLine->GetLineStyle() ) + { + case PLOTDASHTYPE_DASH: + strokes[0] = strokes[2] = DASH_MARK_LEN( width ); + break; + case PLOTDASHTYPE_DOT: + strokes[0] = strokes[2] = DOT_MARK_LEN( width ); + break; + case PLOTDASHTYPE_DASHDOT: + strokes[0] = DASH_MARK_LEN( width ); + strokes[2] = DOT_MARK_LEN( width ); + break; + } + + for( size_t i = 0; i < 100000; ++i ) + { + // Calculations MUST be done in doubles to keep from accumulating rounding + // errors as we go. + VECTOR2D next( start.x + strokes[ i % 4 ] * cos( theta ), + start.y + strokes[ i % 4 ] * sin( theta ) ); + + // Drawing each segment can be done rounded. + wxPoint segStart( KiROUND( start.x ), KiROUND( start.y ) ); + wxPoint segEnd( KiROUND( next.x ), KiROUND( next.y ) ); + + if( ClipLine( &clip, segStart.x, segStart.y, segEnd.x, segEnd.y ) ) + break; + else if( i % 2 == 0 ) + m_gal->DrawLine( segStart, segEnd ); + + start = next; + } + } if( aLine->IsStartDangling() ) drawDanglingSymbol( m_gal, aLine->GetStartPoint()); diff --git a/include/geometry/geometry_utils.h b/include/geometry/geometry_utils.h index bad991971a..3acc3f1620 100644 --- a/include/geometry/geometry_utils.h +++ b/include/geometry/geometry_utils.h @@ -32,6 +32,9 @@ #include +class EDA_RECT; + + /** * @return the number of segments to approximate a arc by segments * with a given max error (this number is >= 1) @@ -95,5 +98,42 @@ VECTOR2 GetVectorSnapped45( const VECTOR2& aVec ) return newVec; } + +/** + * 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. + */ +bool ClipLine( const EDA_RECT *aClipBox, int &x1, int &y1, int &x2, int &y2 ); + + +/** + * Dashed and dotted line patterns. + * + * Note: these are all macros because they're included from files with different + * IU definitions. + */ + +#define DOT_WIDTH_MILS 0.0254 + +#define DOT_MARK_LEN( aLineWidth ) \ + ( std::max( 1.0, IU_PER_MILS * DOT_WIDTH_MILS - aLineWidth ) ) + +#define DASH_GAP_LEN( aLineWidth ) \ + ( 3.0 * DOT_MARK_LEN( aLineWidth ) + ( 2.0 * aLineWidth ) ) + +#define DASH_MARK_LEN( aLineWidth ) \ + ( std::max( DASH_GAP_LEN( aLineWidth ), 5.0 * DOT_MARK_LEN( aLineWidth ) ) ) + + + #endif // #ifndef GEOMETRY_UTILS_H diff --git a/include/plotter.h b/include/plotter.h index 4791ed0770..053d243887 100644 --- a/include/plotter.h +++ b/include/plotter.h @@ -96,9 +96,6 @@ enum PlotDashType { */ class PLOTTER { -private: - double m_dotMarkLength_mm ; ///< Dotted line parameter in mm: segment - public: // These values are used as flag for pen or aperture selection static const int DO_NOT_SET_LINE_WIDTH = -2; // Skip selection