Fixed some issues with arcs (Arcs are a nightmare in graphic applications).

This commit is contained in:
jean-pierre charras 2010-10-11 22:57:25 +02:00
parent c5668298a1
commit fffd3be6a7
6 changed files with 149 additions and 108 deletions

View File

@ -57,7 +57,7 @@
GERBER::GERBER( WinEDA_GerberFrame* aParent, int aLayer ) GERBER::GERBER( WinEDA_GerberFrame* aParent, int aLayer )
{ {
m_Parent = aParent; m_Parent = aParent;
m_Layer = aLayer; // Layer Number m_GraphicLayer = aLayer; // Graphic layer Number
m_Selected_Tool = FIRST_DCODE; m_Selected_Tool = FIRST_DCODE;
@ -157,6 +157,7 @@ void GERBER::ResetDefaultValues()
m_FilesPtr = 0; m_FilesPtr = 0;
m_PolygonFillMode = false; m_PolygonFillMode = false;
m_PolygonFillModeState = 0; m_PolygonFillModeState = 0;
m_Selected_Tool = FIRST_DCODE;
} }

View File

@ -33,7 +33,7 @@ public:
wxString m_FileName; // Full File Name for this layer wxString m_FileName; // Full File Name for this layer
wxString m_ImageName; // Image name, from IN <name>* command wxString m_ImageName; // Image name, from IN <name>* command
wxString m_LayerName; // Layer name, from LN <name>* command wxString m_LayerName; // Layer name, from LN <name>* command
int m_Layer; // Layer Number int m_GraphicLayer; // Graphic layer Number
bool m_LayerNegative; // true = Negative Layer bool m_LayerNegative; // true = Negative Layer
bool m_GerbMetric; // false = Inches, true = metric bool m_GerbMetric; // false = Inches, true = metric
bool m_Relative; // false = absolute Coord, true = relative Coord bool m_Relative; // false = absolute Coord, true = relative Coord

View File

@ -352,6 +352,12 @@ void GERBER_DRAW_ITEM::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDrawMode,
break; break;
case GBR_ARC: case GBR_ARC:
#if 0 // for arc debug only
GRLine( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),
GetABPosition( m_ArcCentre ), 0, color );
GRLine( &aPanel->m_ClipBox, aDC, GetABPosition( m_End ),
GetABPosition( m_ArcCentre ), 0, color );
#endif
if( !isFilled ) if( !isFilled )
{ {
GRArc1( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ), GRArc1( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ),

View File

@ -0,0 +1,18 @@
G04 Draw a rectangle with a rounded right side
G04 Hand coded by Julian Lamb *
%MOIN*%
%FSLAX23Y23*%
%ADD10C,0.050*%
G04 Draw a rectangle with a rounded right side*
G36*
G01X0Y0D02*
X00200Y0D01*
G75*
G03X00200Y00200I0J00100D01*
G01X0Y00200D01*
G04 Do not close with a final line, so let gerbv automatically close*
G37*
M02*

View File

@ -3,12 +3,15 @@
/********************/ /********************/
#include "fctsys.h" #include "fctsys.h"
//#include "polygons_defs.h" //#include "polygons_defs.h"
#include "common.h" #include "common.h"
//#include "confirm.h" //#include "confirm.h"
//#include "macros.h" //#include "macros.h"
#include "gerbview.h" #include "gerbview.h"
#include "trigo.h" #include "trigo.h"
#include "macros.h"
#include "class_gerber_draw_item.h" #include "class_gerber_draw_item.h"
#include "class_GERBER.h" #include "class_GERBER.h"
@ -20,8 +23,8 @@
/* Gerber: NOTES about some important commands found in RS274D and RS274X (G codes): /* Gerber: NOTES about some important commands found in RS274D and RS274X (G codes):
* Gn = * Gn =
* G01 linear interpolation (right trace) * G01 linear interpolation (right trace)
* G02, G20, G21 Circular interpolation, meaning trig <0 * G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise)
* G03, G30, G31 Circular interpolation, meaning trigo> 0 * G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise)
* G04 = comment * G04 = comment
* G06 parabolic interpolation * G06 parabolic interpolation
* G07 Cubic Interpolation * G07 Cubic Interpolation
@ -174,7 +177,7 @@ static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth; aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
aGbrItem->m_Start = aStart; aGbrItem->m_Start = aStart;
aGbrItem->m_End = aEnd; aGbrItem->m_End = aEnd;
aGbrItem->m_DCode = Dcode_index; aGbrItem->m_DCode = Dcode_index;
aGbrItem->m_LayerNegative = aLayerNegative; aGbrItem->m_LayerNegative = aLayerNegative;
@ -224,8 +227,8 @@ static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
*/ */
static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer, static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer,
const wxPoint& aStart, const wxPoint& aEnd, const wxPoint& aStart, const wxPoint& aEnd,
const wxPoint& rel_center, int aWidth, const wxPoint& aRelCenter, int aWidth,
bool clockwise, bool multiquadrant, bool aClockwise, bool aMultiquadrant,
bool aLayerNegative, bool aLayerNegative,
bool aImageNegative ) bool aImageNegative )
{ {
@ -236,66 +239,88 @@ static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aL
aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth; aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
aGbrItem->m_Flashed = false; aGbrItem->m_Flashed = false;
if( multiquadrant )
{
center.x = aStart.x + rel_center.x;
center.y = aStart.y + rel_center.y;
if( clockwise ) if( aMultiquadrant )
{ center = aStart + aRelCenter;
aGbrItem->m_Start = aStart;
aGbrItem->m_End = aEnd;
}
else
{
aGbrItem->m_Start = aEnd;
aGbrItem->m_End = aStart;
}
}
else else
{ {
center = rel_center; // in single quadrant mode the relative coordinate aRelCenter is always >= 0
// So we must recalculate the actual sign of aRelCenter.x and aRelCenter.y
center = aRelCenter;
// calculate arc end coordinate relative to the staring point,
// because center is relative to the center point
delta = aEnd - aStart; delta = aEnd - aStart;
// now calculate the relative to aStart center position, for a draw function
// that use trigonometric arc angle (or counter-clockwise)
/* Quadrants:
* Y
* 2 | 1
* -------X
* 3 | 4
* C = actual relative arc center, S = arc start (axis origin) E = relative arc end
*/
if( (delta.x >= 0) && (delta.y >= 0) ) if( (delta.x >= 0) && (delta.y >= 0) )
{ {
// Quadrant 2 /* Quadrant 1 (trigo or cclockwise):
* C | E
* ---S---
* 3 | 4
*/
NEGATE( center.x);
} }
else if( (delta.x >= 0) && (delta.y < 0) ) else if( (delta.x >= 0) && (delta.y < 0) )
{ {
// Quadrant 1 /* Quadrant 4 (trigo or cclockwise):
center.y = -center.y; * 2 | C
* ---S---
* 3 | E
*/
// Nothing to do
} }
else if( (delta.x < 0) && (delta.y >= 0) ) else if( (delta.x < 0) && (delta.y >= 0) )
{ {
// Quadrant 4 /* Quadrant 2 (trigo or cclockwise):
center.x = -center.x; * E | 1
* ---S---
* C | 4
*/
NEGATE( center.x);
NEGATE( center.y);
} }
else else
{ {
// Quadrant 3 /* Quadrant 3 (trigo or cclockwise):
center.x = -center.x; * 2 | 1
center.y = -center.y; * ---S---
* E | C
*/
NEGATE( center.y);
} }
center.x += aStart.x; // Due to your draw arc function, we need this:
center.y += aStart.y; if( !aClockwise )
center = - center;
if( clockwise ) // Calculate actual arc center coordinate:
{ center += aStart;
aGbrItem->m_Start = aStart; }
aGbrItem->m_End = aEnd;
} if( aClockwise )
else {
{ aGbrItem->m_Start = aStart;
aGbrItem->m_Start = aEnd; aGbrItem->m_End = aEnd;
aGbrItem->m_End = aStart; }
} else
{
aGbrItem->m_Start = aEnd;
aGbrItem->m_End = aStart;
} }
aGbrItem->m_DCode = Dcode_index;
aGbrItem->m_ArcCentre = center; aGbrItem->m_ArcCentre = center;
aGbrItem->m_DCode = Dcode_index;
aGbrItem->m_LayerNegative = aLayerNegative; aGbrItem->m_LayerNegative = aLayerNegative;
aGbrItem->m_ImageNegative = aImageNegative; aGbrItem->m_ImageNegative = aImageNegative;
@ -370,68 +395,51 @@ static void fillArcPOLY( BOARD* aPcb, GERBER_DRAW_ITEM* aGbrItem,
aStart, aEnd, rel_center, 0, aStart, aEnd, rel_center, 0,
clockwise, multiquadrant, aLayerNegative, aImageNegative ); clockwise, multiquadrant, aLayerNegative, aImageNegative );
// dummyTrack has right geometric parameters, and has its Y coordinates negated (to match the pcbnew Y axis).
// Approximate arc by 36 segments per 360 degree
const int increment_angle = 360 / 36;
wxPoint center; wxPoint center;
center = dummyGbrItem.m_ArcCentre; center = dummyGbrItem.m_ArcCentre;
// Calculate relative coordinates; // Calculate coordinates relative to arc center;
wxPoint start = dummyGbrItem.m_Start - center; wxPoint start = dummyGbrItem.m_Start - center;
wxPoint end = dummyGbrItem.m_End - center; wxPoint end = dummyGbrItem.m_End - center;
/* Calculate angle arc /* Calculate angle arc
* angle is here clockwise because Y axis is reversed * angles are in 0.1 deg
* angle is trigonometrical (counter-clockwise),
* and axis is the X,Y gerber coordinates
*/ */
double start_angle = atan2( (double) start.y, (double) start.x ); int start_angle = wxRound(atan2( (double) start.y, (double) start.x ) * 1800 / M_PI);
start_angle = 180 * start_angle / M_PI; int end_angle = wxRound(atan2( (double) end.y, (double) end.x ) * 1800 / M_PI);
double end_angle = atan2( (double) end.y, (double) end.x );
end_angle = 180 * end_angle / M_PI;
double angle = start_angle - end_angle;
// D( printf( " >>>> st %d,%d angle %f, end %d,%d angle %f delta %f\n", // dummyTrack has right geometric parameters, but
// start.x, start.y, start_angle, end.x, end.y, end_angle, angle ) ); // fillArcGBRITEM calculate arc parameters for a draw function that expects
if( !clockwise ) // start_angle < end_angle. So ensure this is the case here:
{ // Due to the fact atan2 returns angles between -180 to + 180 degrees,
EXCHG( start, end ); // this not always the case ( a modulo 360.0 degrees can be lost )
D( printf( " >>>> reverse arc\n" ) ); if( start_angle > end_angle )
} end_angle += 3600;
// Normalize angle int arc_angle = start_angle - end_angle;
while( angle > 360.0 ) // Approximate arc by 36 segments per 360 degree
angle -= 360.0; int increment_angle = 3600 / 36;
int count = ABS( arc_angle / increment_angle );
while( angle < 0.0 ) // calculate polygon corners
angle += 360.0; // when not clockwise, dummyGbrItem arc goes from end to start
int count = (int) ( angle / increment_angle );
if( count <= 0 )
count = 1;
// D( printf( " >>>> angle %f, cnt %d sens %d\n", angle, count, clockwise ) );
// calculate segments
wxPoint start_arc = start; wxPoint start_arc = start;
for( int ii = 1; ii <= count; ii++ ) for( int ii = 0; ii <= count; ii++ )
{ {
int rot;
wxPoint end_arc = start; wxPoint end_arc = start;
int rot = 10 * ii * increment_angle; // rot is in 0.1 deg if( clockwise )
if( ii < count ) rot = ii * increment_angle; // rot is in 0.1 deg
{
if( clockwise )
RotatePoint( &end_arc, rot );
else
RotatePoint( &end_arc, -rot );
}
else else
end_arc = end; rot = (count - ii) * increment_angle; // rot is in 0.1 deg
// D( printf( " >> Add arc %d rot %d, edge poly item %d,%d to %d,%d\n", if( ii < count )
// ii, rot, start_arc.x, start_arc.y,end_arc.x, end_arc.y ); ) RotatePoint( &end_arc, -rot );
else // last point
end_arc = clockwise ? end : start;
if( aGbrItem->m_PolyCorners.size() == 0 )
aGbrItem->m_PolyCorners.push_back( start_arc + center );
aGbrItem->m_PolyCorners.push_back( end_arc + center ); aGbrItem->m_PolyCorners.push_back( end_arc + center );
start_arc = end_arc; start_arc = end_arc;
@ -466,17 +474,18 @@ wxPoint GERBER::ReadXYCoord( char*& Text )
{ {
type_coord = *Text; type_coord = *Text;
Text++; Text++;
text = line; text = line;
nbdigits = 0; nbdigits = 0;
while( IsNumber( *Text ) ) while( IsNumber( *Text ) )
{ {
if( *Text == '.' ) if( *Text == '.' )
is_float = true; is_float = true;
// count digits only (sign and decimal point are not counted) // count digits only (sign and decimal point are not counted)
if( (*Text >= '0') && (*Text <='9') ) if( (*Text >= '0') && (*Text <='9') )
nbdigits++; nbdigits++;
*(text++) = *(Text++); *(text++) = *(Text++);
} }
*text = 0; *text = 0;
if( is_float ) if( is_float )
@ -502,7 +511,7 @@ wxPoint GERBER::ReadXYCoord( char*& Text )
*text = 0; *text = 0;
} }
current_coord = atoi( line ); current_coord = atoi( line );
double real_scale = 1.0; double real_scale = 1.0;
double scale_list[10] = double scale_list[10] =
{ {
10000.0, 1000.0, 100.0, 10.0, 10000.0, 1000.0, 100.0, 10.0,
@ -562,12 +571,13 @@ wxPoint GERBER::ReadIJCoord( char*& Text )
{ {
type_coord = *Text; type_coord = *Text;
Text++; Text++;
text = line; text = line;
nbdigits = 0; nbdigits = 0;
while( IsNumber( *Text ) ) while( IsNumber( *Text ) )
{ {
if( *Text == '.' ) if( *Text == '.' )
is_float = true; is_float = true;
// count digits only (sign and decimal point are not counted) // count digits only (sign and decimal point are not counted)
if( (*Text >= '0') && (*Text <='9') ) if( (*Text >= '0') && (*Text <='9') )
nbdigits++; nbdigits++;
@ -736,8 +746,8 @@ bool GERBER::Execute_G_Command( char*& text, int G_commande )
break; break;
case GC_TURN_OFF_360_INTERPOL: // disable Multi cadran arc and Arc interpol case GC_TURN_OFF_360_INTERPOL: // disable Multi cadran arc and Arc interpol
m_360Arc_enbl = false; m_360Arc_enbl = false;
m_Iterpolation = GERB_INTERPOL_LINEAR_1X; m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // not sure it should be done
break; break;
case GC_TURN_ON_360_INTERPOL: case GC_TURN_ON_360_INTERPOL:
@ -857,7 +867,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
pcb->m_Drawings.Append( gbritem ); pcb->m_Drawings.Append( gbritem );
gbritem->m_Shape = GBR_POLYGON; gbritem->m_Shape = GBR_POLYGON;
gbritem->SetLayer( activeLayer ); gbritem->SetLayer( activeLayer );
gbritem->m_Flashed = false; gbritem->m_Flashed = false;
} }
switch( m_Iterpolation ) switch( m_Iterpolation )
@ -865,18 +875,20 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
case GERB_INTERPOL_ARC_NEG: case GERB_INTERPOL_ARC_NEG:
case GERB_INTERPOL_ARC_POS: case GERB_INTERPOL_ARC_POS:
gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() ); gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
// D( printf( "Add arc poly %d,%d to %d,%d fill %d interpol %d 360_enb %d\n",
// m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x, // D( printf( "Add arc poly %d,%d to %d,%d fill %d interpol %d 360_enb %d\n",
// m_CurrentPos.y, m_PolygonFillModeState, // m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
// m_CurrentPos.y, m_PolygonFillModeState,
// m_Iterpolation, m_360Arc_enbl ); ) // m_Iterpolation, m_360Arc_enbl ); )
fillArcPOLY( pcb, gbritem, m_PreviousPos, fillArcPOLY( pcb, gbritem, m_PreviousPos,
m_CurrentPos, m_IJPos, m_CurrentPos, m_IJPos,
( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true, ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true,
m_360Arc_enbl, m_LayerNegative, m_ImageNegative ); m_360Arc_enbl, m_LayerNegative, m_ImageNegative );
break; break;
default: default:
gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() ); gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
// D( printf( "Add poly edge %d,%d to %d,%d fill %d\n", // D( printf( "Add poly edge %d,%d to %d,%d fill %d\n",
// m_PreviousPos.x, m_PreviousPos.y, // m_PreviousPos.x, m_PreviousPos.y,
// m_CurrentPos.x, m_CurrentPos.y, m_Iterpolation ); ) // m_CurrentPos.x, m_CurrentPos.y, m_Iterpolation ); )
@ -931,11 +943,12 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
case GERB_INTERPOL_LINEAR_1X: case GERB_INTERPOL_LINEAR_1X:
gbritem = new GERBER_DRAW_ITEM( pcb, this ); gbritem = new GERBER_DRAW_ITEM( pcb, this );
pcb->m_Drawings.Append( gbritem ); pcb->m_Drawings.Append( gbritem );
// D( printf( "Add line %d,%d to %d,%d\n", // D( printf( "Add line %d,%d to %d,%d\n",
// m_PreviousPos.x, m_PreviousPos.y, // m_PreviousPos.x, m_PreviousPos.y,
// m_CurrentPos.x, m_CurrentPos.y ); ) // m_CurrentPos.x, m_CurrentPos.y ); )
fillLineGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos, fillLineGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos,
m_CurrentPos, size.x, m_LayerNegative, m_ImageNegative ); m_CurrentPos, size.x, m_LayerNegative, m_ImageNegative );
break; break;
case GERB_INTERPOL_LINEAR_01X: case GERB_INTERPOL_LINEAR_01X:
@ -948,14 +961,15 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
case GERB_INTERPOL_ARC_POS: case GERB_INTERPOL_ARC_POS:
gbritem = new GERBER_DRAW_ITEM( pcb, this ); gbritem = new GERBER_DRAW_ITEM( pcb, this );
pcb->m_Drawings.Append( gbritem ); pcb->m_Drawings.Append( gbritem );
// D( printf( "Add arc %d,%d to %d,%d center %d, %d interpol %d 360_enb %d\n", // D( printf( "Add arc %d,%d to %d,%d center %d, %d interpol %d 360_enb %d\n",
// m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x, // m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
// m_CurrentPos.y, m_IJPos.x, // m_CurrentPos.y, m_IJPos.x,
// m_IJPos.y, m_Iterpolation, m_360Arc_enbl ); ) // m_IJPos.y, m_Iterpolation, m_360Arc_enbl ); )
fillArcGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos, fillArcGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos,
m_CurrentPos, m_IJPos, size.x, m_CurrentPos, m_IJPos, size.x,
( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ?
false : true, m_360Arc_enbl, false : true, m_360Arc_enbl,
m_LayerNegative, m_ImageNegative ); m_LayerNegative, m_ImageNegative );
break; break;
@ -970,7 +984,8 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
break; break;
case 2: // code D2: exposure OFF (i.e. "move to") case 2: // code D2: exposure OFF (i.e. "move to")
m_Exposure = false; m_Exposure = false;
// D( printf( "Move to %d,%d to %d,%d\n", // D( printf( "Move to %d,%d to %d,%d\n",
// m_PreviousPos.x, m_PreviousPos.y, // m_PreviousPos.x, m_PreviousPos.y,
// m_CurrentPos.x, m_CurrentPos.y ); ) // m_CurrentPos.x, m_CurrentPos.y ); )
@ -988,6 +1003,7 @@ bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int
gbritem = new GERBER_DRAW_ITEM( pcb, this ); gbritem = new GERBER_DRAW_ITEM( pcb, this );
pcb->m_Drawings.Append( gbritem ); pcb->m_Drawings.Append( gbritem );
// D( printf( "Add flashed dcode %d layer %d at %d %d\n", dcode, activeLayer, // D( printf( "Add flashed dcode %d layer %d at %d %d\n", dcode, activeLayer,
// m_CurrentPos.x, m_CurrentPos.y ); ) // m_CurrentPos.x, m_CurrentPos.y ); )
fillFlashedGBRITEM( gbritem, aperture, fillFlashedGBRITEM( gbritem, aperture,

View File

@ -159,7 +159,7 @@ void Show_Items_DCode_Value( WinEDA_DrawPanel* aPanel, wxDC* aDC, BOARD* aPcb, i
if( gerb_item->m_DCode <= 0 ) if( gerb_item->m_DCode <= 0 )
continue; continue;
if( gerb_item->m_Flashed ) if( gerb_item->m_Flashed || gerb_item->m_Shape == GBR_ARC )
pos = gerb_item->m_Start; pos = gerb_item->m_Start;
else else
{ {