Commit cffe0cfc authored by charras's avatar charras

support for bezier curves

parent ed50bac8
......@@ -10,6 +10,7 @@ set(COMMON_SRCS
base_screen.cpp
base_struct.cpp
basicframe.cpp
bezier_curves.cpp
block_commande.cpp
class_drawpickedstruct.cpp
common.cpp
......
......@@ -9,29 +9,25 @@
#define BUILD_VERSION "(20090621-unstable)"
#ifndef KICAD_ABOUT_VERSION
#define KICAD_ABOUT_VERSION BUILD_VERSION
#endif
wxString g_BuildVersion
#ifdef HAVE_SVN_VERSION
#include "version.h"
( wxT( KICAD_SVN_VERSION ) )
wxString g_BuildVersion( wxT( KICAD_SVN_VERSION ) );
#else
( wxT( BUILD_VERSION ) )
wxString g_BuildVersion( wxT( BUILD_VERSION ) );
#endif
;
wxString g_BuildAboutVersion
#if defined(HAVE_SVN_VERSION) || defined(HAVE_SVN_REVISION)
# include "version.h"
( wxT( KICAD_ABOUT_VERSION ) )
#ifndef KICAD_ABOUT_VERSION
#define KICAD_ABOUT_VERSION BUILD_VERSION
#endif
wxString g_BuildAboutVersion( wxT( KICAD_ABOUT_VERSION ) );
#else
( wxT( BUILD_VERSION ) )
wxString g_BuildAboutVersion( wxT( BUILD_VERSION ) );
#endif
;
/**********************************/
......@@ -137,6 +133,7 @@ void InitKiCadAbout( wxAboutDialogInfo& info )
info.AddDeveloper( SetMsg( wxT( "Jerry Jacobs <jerkejacobs@gmail.com>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Jonas Diemer <diemer@gmx.de>" ) ) );
info.AddDeveloper( SetMsg( wxT( "KBool Library <http://boolean.klaasholwerda.nl/bool.html>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Marco Serantoni <marco.serantoni@gmail.com>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Rok Markovic <rok@kanardia.eu>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Tim Hanson <sideskate@gmail.com>" ) ) );
info.AddDeveloper( SetMsg( wxT( "Vesa Solonen <vesa.solonen@hut.fi>" ) ) );
......
/************************************/
/* routines to handle bezier curves */
/************************************/
#include "fctsys.h"
#include "bezier_curves.h"
#define add_segment(segment) if(bezier_points[bezier_points.size()-1] != segment) bezier_points.push_back(segment);
// Local variables:
static std::vector<wxPoint> bezier_points;
static int bezier_recursion_limit = 12;
static double bezier_approximation_scale = 0.5; // 1
static double bezier_curve_collinearity_epsilon = 1e-30;
static double bezier_curve_angle_tolerance_epsilon = 0.0001;
static double bezier_distance_tolerance_square; // derived by approximation_scale
static double bezier_angle_tolerance = 0.0;
static double bezier_cusp_limit = 0.0;
// Local functions:
static void recursive_bezier( int x1, int y1, int x2, int y2, int x3, int y3, int level );
static void recursive_bezier( int x1,
int y1,
int x2,
int y2,
int x3,
int y3,
int x4,
int y4,
int level );
/***********************************************************************************/
std::vector<wxPoint> Bezier2Poly( wxPoint c1, wxPoint c2, wxPoint c3, wxPoint c4 )
{
return Bezier2Poly( c1.x, c1.y, c2.x, c2.y, c3.x, c3.y, c4.x, c4.y );
}
std::vector<wxPoint> Bezier2Poly( wxPoint c1, wxPoint c2, wxPoint c3 )
{
return Bezier2Poly( c1.x, c1.y, c2.x, c2.y, c3.x, c3.y );
}
inline int calc_sq_distance( int x1, int y1, int x2, int y2 )
{
int dx = x2 - x1;
int dy = y2 - y1;
return dx * dx + dy * dy;
}
std::vector<wxPoint> Bezier2Poly( int x1, int y1, int x2, int y2, int x3, int y3 )
{
bezier_points.clear();
bezier_distance_tolerance_square = 0.5 / bezier_approximation_scale;
bezier_distance_tolerance_square *= bezier_distance_tolerance_square;
bezier_points.push_back( wxPoint( x1, y1 ) );
recursive_bezier( x1, y1, x2, y2, x3, y3, 0 );
bezier_points.push_back( wxPoint( x3, y3 ) );
wxLogDebug( wxT( "Bezier Conversion - End (%d vertex)" ), bezier_points.size() );
return bezier_points;
}
std::vector<wxPoint> Bezier2Poly( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 )
{
bezier_points.clear();
bezier_distance_tolerance_square = 0.5 / bezier_approximation_scale;
bezier_distance_tolerance_square *= bezier_distance_tolerance_square;
bezier_points.push_back( wxPoint( x1, y1 ) );
recursive_bezier( x1, y1, x2, y2, x3, y3, x4, y4, 0 );
bezier_points.push_back( wxPoint( x4, y4 ) );
wxLogDebug( wxT( "Bezier Conversion - End (%d vertex)" ), bezier_points.size() );
return bezier_points;
}
void recursive_bezier( int x1, int y1, int x2, int y2, int x3, int y3, int level )
{
if( abs( level ) > bezier_recursion_limit )
{
return;
}
// Calculate all the mid-points of the line segments
//----------------------
int x12 = (x1 + x2) / 2;
int y12 = (y1 + y2) / 2;
int x23 = (x2 + x3) / 2;
int y23 = (y2 + y3) / 2;
int x123 = (x12 + x23) / 2;
int y123 = (y12 + y23) / 2;
int dx = x3 - x1;
int dy = y3 - y1;
double d = fabs( ( (x2 - x3) * dy - (y2 - y3) * dx ) );
double da;
if( d > bezier_curve_collinearity_epsilon )
{
// Regular case
//-----------------
if( d * d <= bezier_distance_tolerance_square * (dx * dx + dy * dy) )
{
// If the curvature doesn't exceed the distance_tolerance value
// we tend to finish subdivisions.
//----------------------
if( bezier_angle_tolerance < bezier_curve_angle_tolerance_epsilon )
{
add_segment( wxPoint( x123, y123 ) );
return;
}
// Angle & Cusp Condition
//----------------------
da = fabs( atan2( y3 - y2, x3 - x2 ) - atan2( y2 - y1, x2 - x1 ) );
if( da >=M_PI )
da = 2 * M_PI - da;
if( da < bezier_angle_tolerance )
{
// Finally we can stop the recursion
//----------------------
add_segment( wxPoint( x123, y123 ) );
return;
}
}
}
else
{
// Collinear case
//------------------
da = dx * dx + dy * dy;
if( da == 0 )
{
d = calc_sq_distance( x1, y1, x2, y2 );
}
else
{
d = ( (x2 - x1) * dx + (y2 - y1) * dy ) / da;
if( d > 0 && d < 1 )
{
// Simple collinear case, 1---2---3
// We can leave just two endpoints
return;
}
if( d <= 0 )
d = calc_sq_distance( x2, y2, x1, y1 );
else if( d >= 1 )
d = calc_sq_distance( x2, y2, x3, y3 );
else
d = calc_sq_distance( x2, y2, x1 + d * dx, y1 + d * dy );
}
if( d < bezier_distance_tolerance_square )
{
add_segment( wxPoint( x2, y2 ) );
return;
}
}
// Continue subdivision
//----------------------
recursive_bezier( x1, y1, x12, y12, x123, y123, level + 1 );
recursive_bezier( x123, y123, x23, y23, x3, y3, -(level + 1) );
}
void recursive_bezier( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int level )
{
if( abs( level ) > bezier_recursion_limit )
{
return;
}
// Calculate all the mid-points of the line segments
//----------------------
int x12 = (x1 + x2) / 2;
int y12 = (y1 + y2) / 2;
int x23 = (x2 + x3) / 2;
int y23 = (y2 + y3) / 2;
int x34 = (x3 + x4) / 2;
int y34 = (y3 + y4) / 2;
int x123 = (x12 + x23) / 2;
int y123 = (y12 + y23) / 2;
int x234 = (x23 + x34) / 2;
int y234 = (y23 + y34) / 2;
int x1234 = (x123 + x234) / 2;
int y1234 = (y123 + y234) / 2;
// Try to approximate the full cubic curve by a single straight line
//------------------
int dx = x4 - x1;
int dy = y4 - y1;
double d2 = fabs( ( (x2 - x4) * dy - (y2 - y4) * dx ) );
double d3 = fabs( ( (x3 - x4) * dy - (y3 - y4) * dx ) );
double da1, da2, k;
switch( (int(d2 > bezier_curve_collinearity_epsilon) << 1) +
int(d3 > bezier_curve_collinearity_epsilon) )
{
case 0:
// All collinear OR p1==p4
//----------------------
k = dx * dx + dy * dy;
if( k == 0 )
{
d2 = calc_sq_distance( x1, y1, x2, y2 );
d3 = calc_sq_distance( x4, y4, x3, y3 );
}
else
{
k = 1 / k;
da1 = x2 - x1;
da2 = y2 - y1;
d2 = k * (da1 * dx + da2 * dy);
da1 = x3 - x1;
da2 = y3 - y1;
d3 = k * (da1 * dx + da2 * dy);
if( d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 )
{
// Simple collinear case, 1---2---3---4
// We can leave just two endpoints
return;
}
if( d2 <= 0 )
d2 = calc_sq_distance( x2, y2, x1, y1 );
else if( d2 >= 1 )
d2 = calc_sq_distance( x2, y2, x4, y4 );
else
d2 = calc_sq_distance( x2, y2, x1 + d2 * dx, y1 + d2 * dy );
if( d3 <= 0 )
d3 = calc_sq_distance( x3, y3, x1, y1 );
else if( d3 >= 1 )
d3 = calc_sq_distance( x3, y3, x4, y4 );
else
d3 = calc_sq_distance( x3, y3, x1 + d3 * dx, y1 + d3 * dy );
}
if( d2 > d3 )
{
if( d2 < bezier_distance_tolerance_square )
{
add_segment( wxPoint( x2, y2 ) );
return;
}
}
else
{
if( d3 < bezier_distance_tolerance_square )
{
add_segment( wxPoint( x3, y3 ) );
return;
}
}
break;
case 1:
// p1,p2,p4 are collinear, p3 is significant
//----------------------
if( d3 * d3 <= bezier_distance_tolerance_square * (dx * dx + dy * dy) )
{
if( bezier_angle_tolerance < bezier_curve_angle_tolerance_epsilon )
{
add_segment( wxPoint( x23, y23 ) );
return;
}
// Angle Condition
//----------------------
da1 = fabs( atan2( y4 - y3, x4 - x3 ) - atan2( y3 - y2, x3 - x2 ) );
if( da1 >= M_PI )
da1 = 2 * M_PI - da1;
if( da1 < bezier_angle_tolerance )
{
add_segment( wxPoint( x2, y2 ) );
add_segment( wxPoint( x3, y3 ) );
return;
}
if( bezier_cusp_limit != 0.0 )
{
if( da1 > bezier_cusp_limit )
{
add_segment( wxPoint( x3, y3 ) );
return;
}
}
}
break;
case 2:
// p1,p3,p4 are collinear, p2 is significant
//----------------------
if( d2 * d2 <= bezier_distance_tolerance_square * (dx * dx + dy * dy) )
{
if( bezier_angle_tolerance < bezier_curve_angle_tolerance_epsilon )
{
add_segment( wxPoint( x23, y23 ) );
return;
}
// Angle Condition
//----------------------
da1 = fabs( atan2( y3 - y2, x3 - x2 ) - atan2( y2 - y1, x2 - x1 ) );
if( da1 >= M_PI )
da1 = 2 * M_PI - da1;
if( da1 < bezier_angle_tolerance )
{
add_segment( wxPoint( x2, y2 ) );
add_segment( wxPoint( x3, y3 ) );
return;
}
if( bezier_cusp_limit != 0.0 )
{
if( da1 > bezier_cusp_limit )
{
add_segment( wxPoint( x2, y2 ) );
return;
}
}
}
break;
case 3:
// Regular case
//-----------------
if( (d2 + d3) * (d2 + d3) <= bezier_distance_tolerance_square * (dx * dx + dy * dy) )
{
// If the curvature doesn't exceed the distance_tolerance value
// we tend to finish subdivisions.
//----------------------
if( bezier_angle_tolerance < bezier_curve_angle_tolerance_epsilon )
{
add_segment( wxPoint( x23, y23 ) );
return;
}
// Angle & Cusp Condition
//----------------------
k = atan2( y3 - y2, x3 - x2 );
da1 = fabs( k - atan2( y2 - y1, x2 - x1 ) );
da2 = fabs( atan2( y4 - y3, x4 - x3 ) - k );
if( da1 >= M_PI )
da1 = 2 * M_PI - da1;
if( da2 >= M_PI )
da2 = 2 * M_PI - da2;
if( da1 + da2 < bezier_angle_tolerance )
{
// Finally we can stop the recursion
//----------------------
add_segment( wxPoint( x23, y23 ) );
return;
}
if( bezier_cusp_limit != 0.0 )
{
if( da1 > bezier_cusp_limit )
{
add_segment( wxPoint( x2, y2 ) );
return;
}
if( da2 > bezier_cusp_limit )
{
add_segment( wxPoint( x3, y3 ) );
return;
}
}
}
break;
}
// Continue subdivision
//----------------------
recursive_bezier( x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1 );
recursive_bezier( x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1 );
}
......@@ -289,8 +289,8 @@ void WinEDA_DrawPanel::PostDirtyRect( EDA_Rect aRect )
// The pcb units have finer granularity than the pixels, so it can happen
// that the rectangle is not large enough for the erase portion.
aRect.m_Size.x += 2; // += 1 is not enough!
aRect.m_Size.y += 2;
aRect.m_Size.x += 4; // += 1 is not enough!
aRect.m_Size.y += 4;
// D( printf( "2) PostDirtyRect( x=%d, y=%d, width=%d, height=%d)\n", aRect.m_Pos.x, aRect.m_Pos.y, aRect.m_Size.x, aRect.m_Size.y ); )
......
......@@ -10,6 +10,8 @@
#include "macros.h"
#include "base_struct.h"
#include "class_base_screen.h"
#include "bezier_curves.h"
#ifndef FILLED
#define FILLED 1
......@@ -33,7 +35,7 @@
/* variables generales */
// pour les tracs en mode XOR = GR_XOR ou GR_NXOR selon couleur de fond
// pour les tracÈs en mode XOR = GR_XOR ou GR_NXOR selon couleur de fond
int g_XorMode = GR_NXOR;
// couleur de fond de la frame de dessin
int g_DrawBgColor = WHITE;
......@@ -364,7 +366,7 @@ bool GetGRForceBlackPenState( void )
void GRSetDrawMode( wxDC* DC, int draw_mode )
{
if( draw_mode & GR_OR )
#if defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS
#if defined(__WXMAC__) && (wxMAC_USE_CORE_GRAPHICS || wxCHECK_VERSION(2,9,0) )
DC->SetLogicalFunction( wxCOPY );
#else
DC->SetLogicalFunction( wxOR );
......@@ -372,7 +374,7 @@ void GRSetDrawMode( wxDC* DC, int draw_mode )
else if( draw_mode & GR_XOR )
DC->SetLogicalFunction( wxXOR );
else if( draw_mode & GR_NXOR )
#if defined (__WXMAC__) && wxMAC_USE_CORE_GRAPHICS
#if defined (__WXMAC__) && (wxMAC_USE_CORE_GRAPHICS || wxCHECK_VERSION(2,9,0) )
DC->SetLogicalFunction( wxXOR );
#else
DC->SetLogicalFunction( wxEQUIV );
......@@ -1497,3 +1499,36 @@ void ClipAndDrawFilledPoly( EDA_Rect* aClipBox, wxDC* aDC, wxPoint aPoints[], in
aDC->DrawPolygon( clippedPolygon.size(), &clippedPolygon[0] );
}
#endif
void GRBezier( EDA_Rect* ClipBox,
wxDC* DC,
int x1,
int y1,
int x2,
int y2,
int x3,
int y3,
int width,
int Color )
{
std::vector<wxPoint> Points = Bezier2Poly( x1, y1, x2, y2, x3, y3 );
GRPoly( ClipBox, DC, Points.size(), &Points[0], false, width, Color, 0 );
}
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,
int Color )
{
std::vector<wxPoint> Points = Bezier2Poly( x1, y1, x2, y2, x3, y3, x4, y4 );
GRPoly( ClipBox, DC, Points.size(), &Points[0], false, width, Color, 0 );
}
......@@ -515,7 +515,7 @@ void DIALOG_BUILD_BOM::PrintFieldData( FILE* f, SCH_COMPONENT* DrawLibItem,
/*******************************************************************************************/
{
// @todo make this variable length
static const wxCheckBox* FieldListCtrl[] = {
const wxCheckBox* FieldListCtrl[] = {
m_AddField1,
m_AddField2,
m_AddField3,
......@@ -586,7 +586,7 @@ int DIALOG_BUILD_BOM::PrintComponentsListByRef(
if( CompactForm )
{
// @todo make this variable length
static const wxCheckBox* FieldListCtrl[FIELD8 - FIELD1 + 1] = {
const wxCheckBox* FieldListCtrl[FIELD8 - FIELD1 + 1] = {
m_AddField1,
m_AddField2,
m_AddField3,
......
......@@ -8,6 +8,7 @@
#include "class_drawpanel.h"
#include "drawtxt.h"
#include "trigo.h"
#include "bezier_curves.h"
#include "program.h"
#include "libcmp.h"
......@@ -1104,3 +1105,234 @@ void LibDrawPolyline::DisplayInfo( WinEDA_DrawFrame* frame )
frame->MsgPanel->Affiche_1_Parametre( 40, _( "Bounding box" ), msg, BROWN );
}
/***************************/
/** class LibDrawBezier **/
/***************************/
LibDrawBezier::LibDrawBezier( EDA_LibComponentStruct* aParent ) :
LibEDA_BaseStruct( COMPONENT_BEZIER_DRAW_TYPE, aParent )
{
m_Fill = NO_FILL;
m_Width = 0;
m_typeName = _( "Bezier" );
}
bool LibDrawBezier::Save( FILE* ExportFile ) const
{
int ccount = GetCornerCount();
fprintf( ExportFile, "B %d %d %d %d", ccount, m_Unit, m_Convert, m_Width );
for( unsigned i = 0; i < GetCornerCount(); i++ )
{
fprintf( ExportFile, " %d %d", m_BezierPoints[i].x, m_BezierPoints[i].y );
}
fprintf( ExportFile, " %c\n", fill_tab[m_Fill] );
return true;
}
bool LibDrawBezier::Load( char* line, wxString& errorMsg )
{
char* p;
int i, ccount = 0;
wxPoint pt;
i = sscanf( &line[2], "%d %d %d %d", &ccount, &m_Unit, &m_Convert,
&m_Width );
if( i !=4 )
{
errorMsg.Printf( _( "Bezier only had %d parameters of the required 4" ), i );
return false;
}
if( ccount <= 0 )
{
errorMsg.Printf( _( "Bezier count parameter %d is invalid" ),
ccount );
return false;
}
p = strtok( &line[2], " \t\n" );
p = strtok( NULL, " \t\n" );
p = strtok( NULL, " \t\n" );
p = strtok( NULL, " \t\n" );
for( i = 0; i < ccount; i++ )
{
wxPoint point;
p = strtok( NULL, " \t\n" );
if( sscanf( p, "%d", &pt.x ) != 1 )
{
errorMsg.Printf( _( "Bezier point %d X position not defined" ),
i );
return false;
}
p = strtok( NULL, " \t\n" );
if( sscanf( p, "%d", &pt.y ) != 1 )
{
errorMsg.Printf( _( "Bezier point %d Y position not defined" ),
i );
return false;
}
m_BezierPoints.push_back( pt );
}
m_Fill = NO_FILL;
if( ( p = strtok( NULL, " \t\n" ) ) != NULL )
{
if( p[0] == 'F' )
m_Fill = FILLED_SHAPE;
if( p[0] == 'f' )
m_Fill = FILLED_WITH_BG_BODYCOLOR;
}
return true;
}
LibDrawBezier* LibDrawBezier::GenCopy()
{
LibDrawBezier* newitem = new LibDrawBezier(GetParent());
newitem->m_BezierPoints = m_BezierPoints; // Vector copy
newitem->m_Width = m_Width;
newitem->m_Unit = m_Unit;
newitem->m_Convert = m_Convert;
newitem->m_Flags = m_Flags;
newitem->m_Fill = m_Fill;
return newitem;
}
void LibDrawBezier::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC,
const wxPoint& aOffset, int aColor, int aDrawMode,
void* aData, const int aTransformMatrix[2][2] )
{
wxPoint pos1;
std::vector<wxPoint> PolyPointsTraslated;
int color = ReturnLayerColor( LAYER_DEVICE );
int linewidth = (m_Width == 0) ? g_DrawDefaultLineThickness : m_Width;
m_PolyPoints = Bezier2Poly( m_BezierPoints[0] ,
m_BezierPoints[1] ,
m_BezierPoints[2] ,
m_BezierPoints[3]);
PolyPointsTraslated.clear();
for( unsigned int i = 0; i < m_PolyPoints.size() ; i++)
PolyPointsTraslated.push_back( TransformCoordinate( aTransformMatrix, m_PolyPoints[i] ) + aOffset);
if( aColor < 0 ) // Used normal color or selected color
{
if( m_Selected & IS_SELECTED )
color = g_ItemSelectetColor;
}
else
color = aColor;
FILL_T fill = aData ? NO_FILL : m_Fill;
if( aColor >= 0 )
fill = NO_FILL;
if( fill == FILLED_WITH_BG_BODYCOLOR )
GRPoly( &aPanel->m_ClipBox, aDC, m_PolyPoints.size(),
&PolyPointsTraslated[0], 1, linewidth, color,
ReturnLayerColor( LAYER_DEVICE_BACKGROUND ) );
else if( fill == FILLED_SHAPE )
GRPoly( &aPanel->m_ClipBox, aDC, m_PolyPoints.size(),
&PolyPointsTraslated[0], 1, linewidth, color, color );
else
GRPoly( &aPanel->m_ClipBox, aDC, m_PolyPoints.size(),
&PolyPointsTraslated[0], 0, linewidth, color, color );
}
/**
* Function HitTest
* tests if the given wxPoint is within the bounds of this object.
* @param aRefPos A wxPoint to test
* @return bool - true if a hit, else false
*/
bool LibDrawBezier::HitTest( const wxPoint& aRefPos )
{
int mindist = m_Width ? m_Width /2 : g_DrawDefaultLineThickness / 2;
// Have a minimal tolerance for hit test
if ( mindist < 3 )
mindist = 3; // = 3 mils
return HitTest( aRefPos, mindist, DefaultTransformMatrix );
}
/** Function HitTest
* @return true if the point aPosRef is near a segment
* @param aPosRef = a wxPoint to test
* @param aThreshold = max distance to a segment
* @param aTransMat = the transform matrix
*/
bool LibDrawBezier::HitTest( wxPoint aPosRef, int aThreshold,
const int aTransMat[2][2] )
{
wxPoint ref, start, end;
for( unsigned ii = 1; ii < GetCornerCount(); ii++ )
{
start = TransformCoordinate( aTransMat, m_PolyPoints[ii - 1] );
end = TransformCoordinate( aTransMat, m_PolyPoints[ii] );
if ( TestSegmentHit( aPosRef, start, end, aThreshold ) )
return true;
}
return false;
}
/** Function GetBoundingBox
* @return the boundary box for this, in library coordinates
*/
EDA_Rect LibDrawBezier::GetBoundingBox()
{
EDA_Rect rect;
int xmin, xmax, ymin, ymax;
if(!GetCornerCount())
return rect;
xmin = xmax = m_PolyPoints[0].x;
ymin = ymax = m_PolyPoints[0].y;
for( unsigned ii = 1; ii < GetCornerCount(); ii++ )
{
xmin = MIN( xmin, m_PolyPoints[ii].x );
xmax = MAX( xmax, m_PolyPoints[ii].x );
ymin = MIN( ymin, m_PolyPoints[ii].y );
ymax = MAX( ymax, m_PolyPoints[ii].y );
}
rect.SetOrigin( xmin, ymin * -1 );
rect.SetEnd( xmax, ymax * -1 );
rect.Inflate( m_Width / 2, m_Width / 2 );
return rect;
}
void LibDrawBezier::DisplayInfo( WinEDA_DrawFrame* frame )
{
wxString msg;
EDA_Rect bBox = GetBoundingBox();
LibEDA_BaseStruct::DisplayInfo( frame );
msg = ReturnStringFromValue( g_UnitMetric, m_Width,
EESCHEMA_INTERNAL_UNIT, true );
frame->MsgPanel->Affiche_1_Parametre( 20, _( "Line width" ), msg, BLUE );
msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x,
bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y );
frame->MsgPanel->Affiche_1_Parametre( 40, _( "Bounding box" ), msg, BROWN );
}
......@@ -658,4 +658,70 @@ public:
virtual void DisplayInfo( WinEDA_DrawFrame* frame );
};
/**********************************************************/
/* Graphic Body Item: Bezier Curve (set of lines) */
/**********************************************************/
class LibDrawBezier : public LibEDA_BaseStruct
{
public:
int m_Width; /* Line width */
std::vector<wxPoint> m_BezierPoints; // list of parameter (3|4)
std::vector<wxPoint> m_PolyPoints; // list of points (>= 2)
public:
LibDrawBezier(EDA_LibComponentStruct * aParent);
~LibDrawBezier() { }
virtual wxString GetClass() const
{
return wxT( "LibDrawBezier" );
}
/**
* Function Save
* writes the data structures for this object out to a FILE in "*.brd"
* format.
* @param aFile The FILE to write to.
* @return bool - true if success writing else false.
*/
virtual bool Save( FILE* aFile ) const;
virtual bool Load( char* line, wxString& errorMsg );
LibDrawBezier* GenCopy();
void AddPoint( const wxPoint& point );
/** Function GetCornerCount
* @return the number of corners
*/
unsigned GetCornerCount() const { return m_PolyPoints.size(); }
/**
* Function HitTest
* tests if the given wxPoint is within the bounds of this object.
* @param aRefPos A wxPoint to test
* @return bool - true if a hit, else false
*/
virtual bool HitTest( const wxPoint& aRefPos );
/** Function HitTest
* @return true if the point aPosRef is near a segment
* @param aPosRef = a wxPoint to test
* @param aThreshold = max distance to a segment
* @param aTransMat = the transform matrix
*/
virtual bool HitTest( wxPoint aPosRef, int aThreshold, const int aTransMat[2][2] );
/** Function GetBoundingBox
* @return the boundary box for this, in library coordinates
*/
virtual EDA_Rect GetBoundingBox();
void Draw( WinEDA_DrawPanel * aPanel, wxDC * aDC, const wxPoint &aOffset,
int aColor, int aDrawMode, void* aData,
const int aTransformMatrix[2][2] );
virtual void DisplayInfo( WinEDA_DrawFrame* frame );
};
#endif // CLASSES_BODY_ITEMS_H
......@@ -594,6 +594,11 @@ static LibEDA_BaseStruct* ReadDrawEntryItemDescription (EDA_LibComponentStruct*
entryLoaded = New->Load( Line, errorMsg );
break;
case 'B': /* Bezier */
New = ( LibEDA_BaseStruct* ) new LibDrawBezier(aParent);
entryLoaded = New->Load( Line, errorMsg );
break;
default:
MsgLine.Printf( wxT( "Undefined DRAW command in line %d\n%s, aborted." ),
*LineNum, Line );
......
......@@ -717,6 +717,13 @@ LibEDA_BaseStruct* LocateDrawItem( SCH_SCREEN* Screen,
return DrawItem;
break;
case COMPONENT_BEZIER_DRAW_TYPE:
if( (masque & LOCATE_COMPONENT_POLYLINE_DRAW_TYPE) == 0 )
break;
if( DrawItem->HitTest( aRefPoint ) )
return DrawItem;
break;
case COMPONENT_LINE_DRAW_TYPE:
if( (masque & LOCATE_COMPONENT_LINE_DRAW_TYPE) == 0 )
break;
......
......@@ -347,6 +347,29 @@ void PlotLibPart( SCH_COMPONENT* DrawLibItem )
}
break;
case COMPONENT_BEZIER_DRAW_TYPE:
{
LibDrawBezier* polyline = (LibDrawBezier*) DEntry;
Poly = (int*) MyMalloc( sizeof(int) * 2 * polyline->GetCornerCount() );
for( ii = 0; ii < (int) polyline->GetCornerCount(); ii++ )
{
pos = polyline->m_PolyPoints[ii];
pos = TransformCoordinate( TransMat, pos ) + DrawLibItem->m_Pos;
Poly[ii * 2] = pos.x;
Poly[ii * 2 + 1] = pos.y;
}
if( draw_bgfill && polyline->m_Fill == FILLED_WITH_BG_BODYCOLOR )
{
SetColorMapPS( ReturnLayerColor( LAYER_DEVICE_BACKGROUND ) );
PlotPoly( ii, Poly, true, 0 );
}
if( (g_PlotFormat == PLOT_FORMAT_POST) && g_PlotPSColorOpt )
SetColorMapPS( ReturnLayerColor( LAYER_DEVICE ) );
PlotPoly( ii, Poly, polyline->m_Fill == FILLED_SHAPE ? true : false, polyline->m_Width );
MyFree( Poly );
}
default:
D( printf( "Drawing Type=%d\n", DEntry->Type() ) );
}
......
......@@ -60,6 +60,10 @@ LibEDA_BaseStruct* CopyDrawEntryStruct( wxWindow* frame,
NewDrawItem = ( (LibDrawPolyline*) DrawItem )->GenCopy();
break;
case COMPONENT_BEZIER_DRAW_TYPE:
NewDrawItem = ( (LibDrawBezier*) DrawItem )->GenCopy();
break;
default:
msg.Printf( wxT( "CopyDrawLibEntryStruct: unknown Draw Type %d" ),
DrawItem->Type() );
......
......@@ -77,6 +77,7 @@ enum KICAD_T {
COMPONENT_LINE_DRAW_TYPE,
COMPONENT_PIN_DRAW_TYPE,
COMPONENT_FIELD_DRAW_TYPE,
COMPONENT_BEZIER_DRAW_TYPE,
// End value
MAX_STRUCT_TYPE_ID
......
#ifndef BEZIER_CURVES_H
#define BEZIER_CURVES_H
#include <vector>
std::vector<wxPoint> Bezier2Poly(wxPoint c1, wxPoint c2, wxPoint c3);
std::vector<wxPoint> Bezier2Poly(wxPoint c1, wxPoint c2, wxPoint c3,wxPoint c4);
std::vector<wxPoint> Bezier2Poly(int x1, int y1, int x2, int y2, int x3, int y3);
std::vector<wxPoint> Bezier2Poly(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
#endif // BEZIER_CURVES_H
......@@ -19,7 +19,8 @@ enum Track_Shapes {
S_SPOT_OVALE, /* Oblong spot (for GERBER)*/
S_SPOT_CIRCLE, /* rounded spot (for GERBER)*/
S_SPOT_RECT, /* Rectangular spott (for GERBER)*/
S_POLYGON /* polygonal shape */
S_POLYGON, /* polygonal shape */
S_CURVE /* Bezier Curve*/
};
......
......@@ -6,8 +6,7 @@
#define GR_BASIC
#include "colors.h"
#include <vector>
class EDA_Rect;
......@@ -86,6 +85,8 @@ void GRSLineRel(EDA_Rect * ClipBox, wxDC * DC, int x, int y, int width, int Colo
void GRPoly(EDA_Rect * ClipBox, wxDC * DC, int n, wxPoint Points[], bool Fill, int width, int Color, int BgColor);
void GRBezier(EDA_Rect* ClipBox, wxDC* DC,int x1, int y1, int x2, int y2, int x3, int y3,int width, int 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, int Color);
/**
* Function GRClosedPoly
......
......@@ -9,7 +9,6 @@
#include <vector>
#include <wx/socket.h>
#include "wx/log.h"
#include "wx/config.h"
......
......@@ -24,6 +24,7 @@ wxString BOARD_ITEM::ShowShape( Track_Shapes aShape )
case S_RECT: return _( "Rect" );
case S_ARC: return _( "Arc" );
case S_CIRCLE: return _( "Circle" );
case S_CURVE: return _( "Bezier Curve" );
// used in Gerbview:
case S_ARC_RECT: return wxT( "arc_rect" );
......
......@@ -5,6 +5,7 @@
#include "fctsys.h"
#include "wxstruct.h"
#include "gr_basic.h"
#include "bezier_curves.h"
#include "common.h"
#include "class_drawpanel.h"
#include "kicad_string.h"
......@@ -39,6 +40,8 @@ void DRAWSEGMENT::Copy( DRAWSEGMENT* source )
m_Shape = source->m_Shape;
m_Angle = source->m_Angle;
m_TimeStamp = source->m_TimeStamp;
m_BezierC1 = source->m_BezierC1;
m_BezierC2 = source->m_BezierC1;
}
......@@ -56,10 +59,17 @@ bool DRAWSEGMENT::Save( FILE* aFile ) const
m_Shape,
m_Start.x, m_Start.y,
m_End.x, m_End.y, m_Width );
if( m_Type != S_CURVE) {
fprintf( aFile, "De %d %d %d %lX %X\n",
m_Layer, m_Type, m_Angle,
m_TimeStamp, ReturnStatus() );
} else {
fprintf( aFile, "De %d %d %d %lX %X %d %d %d %d\n",
m_Layer, m_Type, m_Angle,
m_TimeStamp, ReturnStatus(),
m_BezierC1.x,m_BezierC1.y,
m_BezierC2.x,m_BezierC2.y);
}
if( fprintf( aFile, "$EndDRAWSEGMENT\n" ) != sizeof("$EndDRAWSEGMENT\n") - 1 )
goto out;
......@@ -96,9 +106,44 @@ bool DRAWSEGMENT::ReadDrawSegmentDescr( FILE* File, int* LineNum )
if( Line[0] == 'D' )
{
int status;
sscanf( Line + 2, " %d %d %d %lX %X",
&m_Layer, &m_Type, &m_Angle,
&m_TimeStamp, &status );
char* token=0;
token = strtok(Line," ");
for(int i=0; (token = strtok(NULL," ")) != NULL; i++){
switch(i){
case 0:
sscanf(token,"%d",&m_Layer);
break;
case 1:
sscanf(token,"%d",&m_Type);
break;
case 2:
sscanf(token,"%d",&m_Angle);
break;
case 3:
sscanf(token,"%lX",&m_TimeStamp);
break;
case 4:
sscanf(token,"%X",&status);
break;
/* Bezier Control Points*/
case 5:
sscanf(token,"%d",&m_BezierC1.x);
break;
case 6:
sscanf(token,"%d",&m_BezierC1.y);
break;
case 7:
sscanf(token,"%d",&m_BezierC2.x);
break;
case 8:
sscanf(token,"%d",&m_BezierC2.y);
break;
default:
break;
}
}
if( m_Layer < FIRST_NO_COPPER_LAYER )
m_Layer = FIRST_NO_COPPER_LAYER;
......@@ -235,7 +280,30 @@ void DRAWSEGMENT::Draw( WinEDA_DrawPanel* panel, wxDC* DC,
rayon, m_Width, color );
}
break;
case S_CURVE:
m_BezierPoints = Bezier2Poly(m_Start,m_BezierC1, m_BezierC2, m_End);
for (unsigned int i=1; i < m_BezierPoints.size(); i++) {
if( mode == FILAIRE )
GRLine( &panel->m_ClipBox, DC,
m_BezierPoints[i].x, m_BezierPoints[i].y,
m_BezierPoints[i-1].x, m_BezierPoints[i-1].y, 0, color );
else if( mode == SKETCH )
{
GRCSegm( &panel->m_ClipBox, DC,
m_BezierPoints[i].x, m_BezierPoints[i].y,
m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
m_Width, color );
}
else
{
GRFillCSegm( &panel->m_ClipBox, DC,
m_BezierPoints[i].x, m_BezierPoints[i].y,
m_BezierPoints[i-1].x, m_BezierPoints[i-1].y,
m_Width, color );
}
}
break;
default:
if( mode == FILAIRE )
GRLine( &panel->m_ClipBox, DC, ux0, uy0, dx, dy, 0, color );
......@@ -274,19 +342,24 @@ void DRAWSEGMENT::DisplayInfo( WinEDA_DrawFrame* frame )
wxString shape = _( "Shape" );
if( m_Shape == S_CIRCLE )
switch( m_Shape ) {
case S_CIRCLE:
Affiche_1_Parametre( frame, 10, shape, _( "Circle" ), RED );
break;
else if( m_Shape == S_ARC )
{
case S_ARC:
Affiche_1_Parametre( frame, 10, shape, _( "Arc" ), RED );
msg.Printf( wxT( "%d.%d" ), m_Angle/10, m_Angle % 10 );
Affiche_1_Parametre( frame, 18, _("Angle"), msg, RED );
}
else
Affiche_1_Parametre( frame, 10, shape, _( "Segment" ), RED );
break;
case S_CURVE:
Affiche_1_Parametre( frame, 10, shape, _( "Curve" ), RED );
break;
default:
Affiche_1_Parametre( frame, 10, shape, _( "Segment" ), RED );
}
wxString start;
start << GetStart();
......@@ -322,8 +395,10 @@ bool DRAWSEGMENT::HitTest( const wxPoint& ref_pos )
int spot_cX = ref_pos.x - ux0;
int spot_cY = ref_pos.y - uy0;
if( m_Shape==S_CIRCLE || m_Shape==S_ARC )
{
switch(m_Shape){
case S_CIRCLE:
case S_ARC:
int rayon, dist, stAngle, endAngle, mouseAngle;
rayon = (int) hypot( (double) (dx), (double) (dy) );
......@@ -348,9 +423,16 @@ bool DRAWSEGMENT::HitTest( const wxPoint& ref_pos )
if( mouseAngle >= stAngle && mouseAngle <= endAngle )
return true;
}
}
else
break;
case S_CURVE:
for( unsigned int i= 1; i < m_BezierPoints.size(); i++)
{
if( TestSegmentHit( ref_pos,m_BezierPoints[i-1],m_BezierPoints[i-1], m_Width / 2 ) )
return true;
}
break;
default:
if( DistanceTest( m_Width / 2, dx, dy, spot_cX, spot_cY ) )
return true;
}
......
......@@ -15,7 +15,10 @@ public:
int m_Shape; // Shape: line, Circle, Arc
int m_Type; // Used in complex associations ( Dimensions.. )
int m_Angle; // Used only for Arcs: Arc angle in 1/10 deg
wxPoint m_BezierC1; // Bezier Control Point 1
wxPoint m_BezierC2; // Bezier Control Point 1
std::vector<wxPoint> m_BezierPoints;
public:
DRAWSEGMENT( BOARD_ITEM* aParent, KICAD_T idtype = TYPE_DRAWSEGMENT );
~DRAWSEGMENT();
......
......@@ -46,8 +46,8 @@ void D_PAD::Draw( WinEDA_DrawPanel* panel, wxDC* DC, int draw_mode, const wxPoin
if( frame->m_DisplayPadFill == FILLED )
fillpad = 1;
#ifdef PCBNEW
if( m_Flags & IS_MOVED )
#if defined(PCBNEW) || defined(__WXMAC__)
if( m_Flags & IS_MOVED || !DisplayOpt.DisplayPadFill )
fillpad = 0;
#endif
......
......@@ -348,6 +348,8 @@ void WinEDA_PcbFrame::Install_Edit_Cotation( COTATION* Cotation,
WinEDA_CotationPropertiesFrame* frame = new WinEDA_CotationPropertiesFrame( this,
Cotation, DC, pos );
Ajuste_Details_Cotation( Cotation );
frame->ShowModal();
frame->Destroy();
}
......
......@@ -787,8 +787,11 @@ void DrawModuleOutlines( WinEDA_DrawPanel* panel, wxDC* DC, MODULE* module )
if( g_Show_Pads_Module_in_Move )
{
pad_fill_tmp = DisplayOpt.DisplayPadFill;
#ifndef __WXMAC__
DisplayOpt.DisplayPadFill = true; /* Trace en SKETCH en deplacement */
#else
DisplayOpt.DisplayPadFill = false;
#endif
pt_pad = module->m_Pads;
for( ; pt_pad != NULL; pt_pad = pt_pad->Next() )
{
......
......@@ -753,32 +753,69 @@ void PlotDrawSegment( DRAWSEGMENT* pt_segm, int Format, int masque_layer )
{
case PLOT_FORMAT_GERBER:
SelectD_CODE_For_LineDraw( thickness );
if( pt_segm->m_Shape == S_CIRCLE )
switch(pt_segm->m_Shape)
{
case S_CIRCLE:
PlotCircle( PLOT_FORMAT_GERBER, thickness, start, radius );
else if( pt_segm->m_Shape == S_ARC )
break;
case S_ARC:
PlotArc( PLOT_FORMAT_GERBER, start,
StAngle, EndAngle, radius, thickness );
else
break;
case S_CURVE:
for (unsigned int i=1; i < pt_segm->m_BezierPoints.size(); i++) {
PlotGERBERLine( pt_segm->m_BezierPoints[i-1], pt_segm->m_BezierPoints[i], thickness);
}
break;
default:
PlotGERBERLine( start, end, thickness );
}
break;
case PLOT_FORMAT_HPGL:
if( pt_segm->m_Shape == S_CIRCLE )
switch(pt_segm->m_Shape)
{
case S_CIRCLE:
PlotCircle( PLOT_FORMAT_HPGL, thickness, start, radius );
else if( pt_segm->m_Shape == S_ARC )
break;
case S_ARC:
PlotArc( PLOT_FORMAT_HPGL, start, StAngle, EndAngle, radius, thickness );
else
Plot_Filled_Segment_HPGL( start, end, thickness, (GRFillMode) g_Plot_Mode );
break;
case S_CURVE:
for (unsigned int i=1; i < pt_segm->m_BezierPoints.size(); i++) {
Plot_Filled_Segment_HPGL( pt_segm->m_BezierPoints[i-1], pt_segm->m_BezierPoints[i], thickness,(GRFillMode) g_Plot_Mode);
}
break;
default:
Plot_Filled_Segment_HPGL( start, end, thickness, (GRFillMode) g_Plot_Mode );
}
break;
case PLOT_FORMAT_POST:
if( pt_segm->m_Shape == S_CIRCLE )
switch(pt_segm->m_Shape)
{
case S_CIRCLE:
PlotCircle( PLOT_FORMAT_POST, thickness, start, radius );
else if( pt_segm->m_Shape == S_ARC )
break;
case S_ARC:
PlotArc( PLOT_FORMAT_POST, start,
StAngle, EndAngle, radius, thickness );
else
break;
case S_CURVE:
for (unsigned int i=1; i < pt_segm->m_BezierPoints.size(); i++) {
PlotFilledSegmentPS( pt_segm->m_BezierPoints[i-1], pt_segm->m_BezierPoints[i], thickness);
}
break;
default:
PlotFilledSegmentPS( start, end, thickness );
}
break;
}
}
......
......@@ -9,11 +9,13 @@
#include "fctsys.h"
#include "PolyLine.h"
#include "gr_basic.h"
#include "bezier_curves.h"
using namespace std;
#define pi 3.14159265359
#define pi M_PI
CPolyLine::CPolyLine()
{
......@@ -1571,3 +1573,21 @@ void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int n
Close( STRAIGHT );
}
// Bezier Support
void CPolyLine::AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3) {
std::vector<wxPoint> bezier_points;
bezier_points = Bezier2Poly(x1,y1,x2,y2,x3,y3);
for( unsigned int i = 0; i < bezier_points.size() ; i++)
AppendCorner( bezier_points[i].x, bezier_points[i].y);
}
void CPolyLine::AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4){
std::vector<wxPoint> bezier_points;
bezier_points = Bezier2Poly(x1,y1,x2,y2,x3,y3,x4,y4);
for( unsigned int i = 0; i < bezier_points.size() ; i++)
AppendCorner( bezier_points[i].x, bezier_points[i].y);
}
......@@ -243,6 +243,11 @@ public:
private:
Bool_Engine* m_Kbool_Poly_Engine; // polygons set in kbool engine data
bool bDrawn;
// Bezier Support
public:
void AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3);
void AppendBezier(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
};
#endif // #ifndef POLYLINE_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment