diff --git a/gerbview/class_gerber_draw_item.cpp b/gerbview/class_gerber_draw_item.cpp index b34aaef67a..0bfd7da252 100644 --- a/gerbview/class_gerber_draw_item.cpp +++ b/gerbview/class_gerber_draw_item.cpp @@ -88,8 +88,7 @@ GERBER_DRAW_ITEM::GERBER_DRAW_ITEM( const GERBER_DRAW_ITEM& aSource ) : m_mirrorA = aSource.m_mirrorA; m_mirrorB = aSource.m_mirrorB; m_layerOffset = aSource.m_layerOffset; - m_drawScale.x = aSource.m_drawScale.x; - m_drawScale.y = aSource.m_drawScale.y; + m_drawScale = aSource.m_drawScale; m_lyrRotation = aSource.m_lyrRotation; } @@ -222,7 +221,13 @@ wxString GERBER_DRAW_ITEM::ShowGBRShape() return wxT( "polygon" ); case GBR_SPOT_MACRO: - return wxT( "apt_macro" ); // TODO: add aperture macro name + { + wxString name = wxT( "apt_macro" ); + D_CODE* dcode = GetDcodeDescr(); + if( dcode && dcode->GetMacro() ) + name << wxT(" ") << dcode->GetMacro()->name; + return name; + } default: return wxT( "??" ); @@ -363,8 +368,8 @@ void GERBER_DRAW_ITEM::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDrawMode, break; case GBR_CIRCLE: - radius = (int) hypot( (double) ( m_End.x - m_Start.x ), - (double) ( m_End.y - m_Start.y ) ); + radius = wxRound(hypot( (double) ( m_End.x - m_Start.x ), + (double) ( m_End.y - m_Start.y ) )); halfPenWidth = m_Size.x >> 1; @@ -384,6 +389,8 @@ void GERBER_DRAW_ITEM::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDrawMode, break; case GBR_ARC: + // Currently, arcs plotted witha rectangular aperture are not supported. + // a round pen only is expected. #if 0 // for arc debug only GRLine( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ), GetABPosition( m_ArcCentre ), 0, color ); @@ -415,12 +422,30 @@ void GERBER_DRAW_ITEM::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDrawMode, break; case GBR_SEGMENT: - if( !isFilled ) - GRCSegm( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ), - GetABPosition( m_End ), m_Size.x, color ); + /* Plot a line from m_Start to m_End. + * Usually, a round pen is used, but some gerber files use a rectangular pen + * In fact, any aperture can be used to plot a line. + * currently: only a square pen is handled (I believe using a polygon gives a strange plot). + */ + if( d_codeDescr->m_Shape == APT_RECT ) + { + if( m_PolyCorners.size() == 0 ) + ConvertSegmentToPolygon( ); + DrawGbrPoly( &aPanel->m_ClipBox, aDC, color, aOffset, isFilled ); + } else - GRFilledSegment( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ), + { + if( !isFilled ) + { + GRCSegm( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ), GetABPosition( m_End ), m_Size.x, color ); + } + else + { + GRFilledSegment( &aPanel->m_ClipBox, aDC, GetABPosition( m_Start ), + GetABPosition( m_End ), m_Size.x, color ); + } + } break; default: @@ -433,9 +458,71 @@ void GERBER_DRAW_ITEM::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC, int aDrawMode, } } +/** function ConvertSegmentToPolygon + * convert a line to an equivalent polygon. + * Useful when a line is plotted using a rectangular pen. + * In this case, the usual segment plot cannot be used + * The equivalent polygon is the area paint by the rectancular pen + * from m_Start to m_End. + */ +void GERBER_DRAW_ITEM::ConvertSegmentToPolygon( ) +{ + m_PolyCorners.clear(); + m_PolyCorners.reserve(6); + + wxPoint start = m_Start; + wxPoint end = m_End; + // make calculations more easy if ensure start.x < end.x + // (only 2 quadrants to consider) + if( start.x > end.x ) + EXCHG( start, end ); + + // calculate values relative to start point: + wxPoint delta = end - start; + // calculate corners for the first quadrant only (delta.x and delta.y > 0 ) + // currently, delta.x already is > 0. + // make delta.y > 0 + bool change = delta.y < 0; + if( change ) + NEGATE( delta.y); + // Now create the full polygon. + // Due to previous chnages, the shape is always something like + // 3 4 + // 2 5 + // 1 6 + wxPoint corner; + corner.x -= m_Size.x/2; + corner.y -= m_Size.y/2; + m_PolyCorners.push_back( corner ); // Lower left corner, start point (1) + corner.y += m_Size.y; + m_PolyCorners.push_back( corner ); // upper left corner, start point (2) + if( delta.x || delta.y) + { + corner += delta; + m_PolyCorners.push_back( corner ); // upper left corner, end point (3) + } + corner.x += m_Size.x; + m_PolyCorners.push_back( corner ); // upper right corner, end point (4) + corner.y -= m_Size.y; + m_PolyCorners.push_back( corner ); // lower right corner, end point (5) + if( delta.x || delta.y ) + { + corner -= delta; + m_PolyCorners.push_back( corner ); // lower left corner, start point (6) + } + + // Create final polygon: + for( unsigned ii = 0; ii < m_PolyCorners.size(); ii++ ) + { + if( change ) + NEGATE( m_PolyCorners[ii].y); + m_PolyCorners[ii] += start; + } +} + /** function DrawGbrPoly - * a helper function used id ::Draw to draw the polygon stored ion m_PolyCorners + * a helper function used id ::Draw to draw the polygon stored in m_PolyCorners * Draw filled polygons */ void GERBER_DRAW_ITEM::DrawGbrPoly( EDA_Rect* aClipBox, diff --git a/gerbview/class_gerber_draw_item.h b/gerbview/class_gerber_draw_item.h index c59bc654d0..d9f172fd15 100644 --- a/gerbview/class_gerber_draw_item.h +++ b/gerbview/class_gerber_draw_item.h @@ -194,8 +194,15 @@ public: int aDrawMode, const wxPoint& aOffset = ZeroOffset ); + /** function ConvertSegmentToPolygon + * convert a line to an equivalent polygon. + * Useful when a line is plotted using a rectangular pen. + * In this case, the usual segment plot function cannot be used + */ + void ConvertSegmentToPolygon( ); + /** function DrawGbrPoly - * a helper function used id ::Draw to draw the polygon stored ion m_PolyCorners + * a helper function used id ::Draw to draw the polygon stored in m_PolyCorners */ void DrawGbrPoly( EDA_Rect* aClipBox, wxDC* aDC, int aColor, diff --git a/gerbview/gerber_test_files/test_line_with_rect_aperture.gbr b/gerbview/gerber_test_files/test_line_with_rect_aperture.gbr new file mode 100644 index 0000000000..b93e1c9fab --- /dev/null +++ b/gerbview/gerber_test_files/test_line_with_rect_aperture.gbr @@ -0,0 +1,16 @@ +* +%FSLAX23Y23*% +%MOIN*% +%ADD10R,0.025X0.025*% +%ADD11R,0.03X0.06*% +%IPPOS*% +%LNtest_rect.gbr*% +%LPD*% +G75* +G54D10* +X04000Y00100D02* +X04400Y00140D01* +G54D11* +X03000Y00100D02* +X02400Y-00340D01* +M02* diff --git a/gerbview/rs274d.cpp b/gerbview/rs274d.cpp index e9f9d4960a..2c0651436f 100644 --- a/gerbview/rs274d.cpp +++ b/gerbview/rs274d.cpp @@ -137,23 +137,23 @@ static void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem, * @param aGbrItem The GERBER_DRAW_ITEM to fill in. * @param Dcode_index The DCODE value, like D14 * @param aLayer The layer index to set into the GBRITEM - * @param aPos The center point of the flash - * @param aDiameter The diameter of the round flash + * @param aStart The starting point of the line + * @param aEnd The ending point of the line + * @param aPenSize The size of the flash. Note rectangular shapes are legal. * @param aLayerNegative = true if the current layer is negative - * @param aImageNegative = true if the current image is negative */ static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer, const wxPoint& aStart, const wxPoint& aEnd, - int aWidth, + wxSize aPenSize, bool aLayerNegative ) { aGbrItem->SetLayer( aLayer ); aGbrItem->m_Flashed = false; - aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth; + aGbrItem->m_Size = aPenSize; aGbrItem->m_Start = aStart; aGbrItem->m_End = aEnd; @@ -188,13 +188,12 @@ static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem, * must be calculated from the previously given constraint: arc only in the * same quadrant. * @param aDiameter The diameter of the round flash - * @param aWidth is the pen width. + * @param aPenSize The size of the flash. Note rectangular shapes are legal. * @param aLayerNegative = true if the current layer is negative - * @param aImageNegative = true if the current image is negative */ static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer, const wxPoint& aStart, const wxPoint& aEnd, - const wxPoint& aRelCenter, int aWidth, + const wxPoint& aRelCenter, wxSize aPenSize, bool aClockwise, bool aMultiquadrant, bool aLayerNegative ) { @@ -202,7 +201,7 @@ static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aL aGbrItem->m_Shape = GBR_ARC; aGbrItem->SetLayer( aLayer ); - aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth; + aGbrItem->m_Size = aPenSize; aGbrItem->m_Flashed = false; @@ -333,7 +332,7 @@ static void fillArcPOLY( BOARD* aPcb, GERBER_DRAW_ITEM* aGbrItem, aGbrItem->SetLayerPolarity( aLayerNegative ); fillArcGBRITEM( &dummyGbrItem, 0, 0, - aStart, aEnd, rel_center, 0, + aStart, aEnd, rel_center, wxSize(0, 0), clockwise, multiquadrant, aLayerNegative ); wxPoint center; @@ -688,7 +687,7 @@ bool GERBER_IMAGE::Execute_DCODE_Command( char*& text, int D_commande ) // m_PreviousPos.x, m_PreviousPos.y, // m_CurrentPos.x, m_CurrentPos.y ); ) fillLineGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos, - m_CurrentPos, size.x, GetLayerParams().m_LayerNegative ); + m_CurrentPos, size, GetLayerParams().m_LayerNegative ); StepAndRepeatItem( *gbritem ); break; @@ -708,7 +707,7 @@ bool GERBER_IMAGE::Execute_DCODE_Command( char*& text, int D_commande ) // m_CurrentPos.y, m_IJPos.x, // m_IJPos.y, m_Iterpolation, m_360Arc_enbl ); ) fillArcGBRITEM( gbritem, dcode, activeLayer, m_PreviousPos, - m_CurrentPos, m_IJPos, size.x, + m_CurrentPos, m_IJPos, size, ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true, m_360Arc_enbl, GetLayerParams().m_LayerNegative ); StepAndRepeatItem( *gbritem ); diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp index 6cf79668e7..d146be4aab 100644 --- a/pcbnew/class_drawsegment.cpp +++ b/pcbnew/class_drawsegment.cpp @@ -245,9 +245,11 @@ void DRAWSEGMENT::Draw( WinEDA_DrawPanel* panel, wxDC* DC, GRSetDrawMode( DC, draw_mode ); l_piste = m_Width >> 1; /* half trace width */ + // Line start point or Circle and Arc center ux0 = m_Start.x; uy0 = m_Start.y; + // Line end point or circle and arc start point dx = m_End.x; dy = m_End.y; diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 1a7f4c9504..92a4b1abd2 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -10,8 +10,8 @@ class DRAWSEGMENT : public BOARD_ITEM { public: int m_Width; // thickness of lines ... - wxPoint m_Start; // Line start point - wxPoint m_End; // Line end point + wxPoint m_Start; // Line start point or Circle and Arc center + wxPoint m_End; // Line end point or circle and arc start point int m_Shape; // Shape: line, Circle, Arc int m_Type; // Used in complex associations ( Dimensions.. ) diff --git a/pcbnew/class_edge_mod.cpp b/pcbnew/class_edge_mod.cpp index d2e58be86b..2cf70819e8 100644 --- a/pcbnew/class_edge_mod.cpp +++ b/pcbnew/class_edge_mod.cpp @@ -421,6 +421,7 @@ int EDGE_MODULE::ReadDescr( char* Line, FILE* File, &m_Start0.x, &m_Start0.y, &m_End0.x, &m_End0.y, &m_Angle, &m_Width, &m_Layer ); + NORMALIZE_ANGLE( m_Angle ); break; case S_SEGMENT: diff --git a/pcbnew/export_gencad.cpp b/pcbnew/export_gencad.cpp index 03012ee950..af03bddc53 100644 --- a/pcbnew/export_gencad.cpp +++ b/pcbnew/export_gencad.cpp @@ -818,9 +818,9 @@ void CreateTracksInfoData( FILE* file, BOARD* pcb ) */ void FootprintWriteShape( FILE* file, MODULE* module ) { - EDGE_MODULE* PtEdge; - EDA_BaseStruct* PtStruct; - int Yaxis_sign = -1; // Control Y axis change sign (as normal + EDGE_MODULE* edge; + EDA_BaseStruct* item; + int y_axis_sign = -1; // Control Y axis change sign (as normal // module / mirror axis and conventions) /* creates header: */ @@ -840,46 +840,53 @@ void FootprintWriteShape( FILE* file, MODULE* module ) } /* creates Drawing */ - PtStruct = module->m_Drawings; - for( ; PtStruct != NULL; PtStruct = PtStruct->Next() ) + item = module->m_Drawings; + for( ; item != NULL; item = item->Next() ) { - switch( PtStruct->Type() ) + switch( item->Type() ) { case TYPE_TEXTE_MODULE: break; case TYPE_EDGE_MODULE: - PtEdge = (EDGE_MODULE*) PtStruct; + edge = (EDGE_MODULE*) item; - switch( PtEdge->m_Shape ) + switch( edge->m_Shape ) { case S_SEGMENT: fprintf( file, "LINE %d %d %d %d\n", - PtEdge->m_Start0.x, Yaxis_sign * PtEdge->m_Start0.y, - PtEdge->m_End0.x, Yaxis_sign * PtEdge->m_End0.y ); + edge->m_Start0.x, y_axis_sign * edge->m_Start0.y, + edge->m_End0.x, y_axis_sign * edge->m_End0.y ); break; case S_CIRCLE: { int rayon = (int) hypot( - (double) ( PtEdge->m_End0.x - PtEdge->m_Start0.x ), - (double) ( PtEdge->m_End0.y - PtEdge->m_Start0.y ) ); + (double) ( edge->m_End0.x - edge->m_Start0.x ), + (double) ( edge->m_End0.y - edge->m_Start0.y ) ); fprintf( file, "CIRCLE %d %d %d\n", - PtEdge->m_Start0.x, Yaxis_sign * PtEdge->m_Start0.y, + edge->m_Start0.x, y_axis_sign * edge->m_Start0.y, rayon ); break; } case S_ARC: /* print ARC x,y start x,y end x,y center */ - { - int arcendx, arcendy; - arcendx = PtEdge->m_Start0.x; - arcendy = PtEdge->m_Start0.y; - RotatePoint( &arcendx, &arcendy, PtEdge->m_Angle ); + { // Arcs are defined counter clockwise (positive trigonometric) + // from the start point to the end point (0 to 360 degrees) + wxPoint arcStart, arcEnd; + // edge->m_Start0 is the arc center relative to the shape position + // edge->m_End0 is the arc start point relative to the shape position + arcStart = edge->m_End0; + // calculate arcEnd arc end point relative to the shape position, in pcbnew coordinates + arcEnd = arcStart; + RotatePoint( &arcEnd, edge->m_Start0, -edge->m_Angle ); + // due to difference between pcbnew and gencad, swap arc start and arc end + EXCHG(arcEnd, arcStart); + // print arc shape: fprintf( file, "ARC %d %d %d %d %d %d\n", - PtEdge->m_End0.x, Yaxis_sign * PtEdge->m_End0.y, - arcendx, Yaxis_sign * arcendy, - PtEdge->m_Start0.x, Yaxis_sign * PtEdge->m_Start0.y ); + arcStart.x, y_axis_sign * arcStart.y, // Start point + arcEnd.x, y_axis_sign * arcEnd.y, // End point + edge->m_Start0.x, y_axis_sign * edge->m_Start0.y ); break; }