Add line style drawing.
This commit is contained in:
parent
808beed191
commit
fee52e127f
|
@ -27,6 +27,7 @@
|
|||
* @brief a few functions useful in geometry calculations.
|
||||
*/
|
||||
|
||||
#include <eda_rect.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <math_for_graphics.h>
|
||||
#include <wx/graphics.h>
|
||||
#include <wx/tokenzr.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#if defined(__WXMAC__) && defined(USE_WX_GRAPHICS_CONTEXT)
|
||||
#include <wx/dcgraph.h>
|
||||
#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<wxPoint>& 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<wxPoint>& 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include <base_screen.h>
|
||||
#include <draw_graphic_text.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
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 )
|
||||
{
|
||||
|
|
|
@ -44,9 +44,9 @@
|
|||
#include <sch_bus_entry.h>
|
||||
#include <sch_bitmap.h>
|
||||
#include <draw_graphic_text.h>
|
||||
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <lib_edit_frame.h>
|
||||
|
||||
#include <plotter.h>
|
||||
#include <template_fieldnames.h>
|
||||
#include <class_libentry.h>
|
||||
#include <class_library.h>
|
||||
|
@ -57,8 +57,6 @@
|
|||
|
||||
#include "sch_painter.h"
|
||||
|
||||
#include <draw_graphic_text.h>
|
||||
|
||||
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 );
|
||||
|
||||
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());
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
|
||||
#include <math/vector2d.h>
|
||||
|
||||
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<T> GetVectorSnapped45( const VECTOR2<T>& 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue