From e06176663b0ac8b7a4e781ef1b49c0f1f9a9f51f Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Fri, 1 Oct 2010 21:23:36 +0200 Subject: [PATCH] added forgotten files --- gerbview/class_aperture_macro.cpp | 408 ++++++++++++++++++++++++++++++ gerbview/class_aperture_macro.h | 159 ++++++++++++ 2 files changed, 567 insertions(+) create mode 100644 gerbview/class_aperture_macro.cpp create mode 100644 gerbview/class_aperture_macro.h diff --git a/gerbview/class_aperture_macro.cpp b/gerbview/class_aperture_macro.cpp new file mode 100644 index 0000000000..83a1498cde --- /dev/null +++ b/gerbview/class_aperture_macro.cpp @@ -0,0 +1,408 @@ +/****************************/ +/* class_aperture_macro.cpp */ +/****************************/ + + +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 1992-2010 Jean-Pierre Charras + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2010 Kicad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "fctsys.h" +#include "common.h" +#include "macros.h" +#include "trigo.h" +#include "gerbview.h" + +/** helper Function mapPt + * translates a point from the aperture macro coordinate system to our + * deci-mils coordinate system. + * @return wxPoint - The gerbview coordinate system vector. + */ +extern wxPoint mapPt( double x, double y, bool isMetric ); // defined it rs274d.cpp +/** + * Function scale + * converts a distance given in floating point to our deci-mils + */ +extern int scale( double aCoord, bool isMetric ); // defined it rs274d.cpp + + +/** function DrawBasicShape + * Draw the primitive shape for flashed items. + */ +void AM_PRIMITIVE::DrawBasicShape( GERBER_DRAW_ITEM* aParent, + EDA_Rect* aClipBox, + wxDC* aDC, + int aColor, + wxPoint aShapePos, + bool aFilledShape ) +{ + static std::vector polybuffer; // create a static buffer to avoid a lot of memory reallocation + polybuffer.clear(); + + wxPoint curPos = aShapePos; + D_CODE* tool = aParent->GetDcodeDescr(); + bool gerberMetric = aParent->m_UnitsMetric; + switch( primitive_id ) + { + case AMP_CIRCLE: // Circle, given diameter and position + { + /* Generated by an aperture macro declaration like: + * "1,1,0.3,0.5, 1.0*" + * type (1), exposure, diameter, pos.x, pos.y + * type is not stored in parameters list, so the first parameter is pos.x + */ + int exposure = params[0].GetValue( tool ); + curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), gerberMetric ); + int radius = scale( params[1].GetValue( tool ), gerberMetric ) / 2; + if( !aFilledShape ) + GRCircle( aClipBox, aDC, curPos.x, curPos.y, radius, aColor ); + else + GRFilledCircle( aClipBox, aDC, curPos, radius, aColor ); + } + break; + + case AMP_LINE2: + case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation) + { + /* Generated by an aperture macro declaration like: + * "2,1,0.3,0,0, 0.5, 1.0,-135*" + * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation + * type is not stored in parameters list, so the first parameter is pos.x + */ + int exposure = params[0].GetValue( tool ); + ConvertShapeToPolygon(aParent, polybuffer, gerberMetric); + // shape rotation: + int rotation = wxRound(params[6].GetValue( tool ) * 10.0); + if (rotation) + { + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + RotatePoint(&polybuffer[ii], rotation); + } + // Move to current position: + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + polybuffer[ii] += curPos; + + GRClosedPoly( aClipBox, aDC, polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); + } + break; + + case AMP_LINE_CENTER: + { + /* Generated by an aperture macro declaration like: + * "21,1,0.3,0.03,0,0,-135*" + * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation + * type is not stored in parameters list, so the first parameter is pos.x + */ + int exposure = params[0].GetValue( tool ); + ConvertShapeToPolygon(aParent, polybuffer, gerberMetric); + // shape rotation: + int rotation = wxRound(params[5].GetValue( tool ) * 10.0); + if (rotation) + { + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + RotatePoint(&polybuffer[ii], rotation); + } + // Move to current position: + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + polybuffer[ii] += curPos; + GRClosedPoly( aClipBox, aDC, polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); + } + break; + + case AMP_LINE_LOWER_LEFT: + { + /* Generated by an aperture macro declaration like: + * "22,1,0.3,0.03,0,0,-135*" + * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation + * type is not stored in parameters list, so the first parameter is pos.x + */ + int exposure = params[0].GetValue( tool ); + ConvertShapeToPolygon(aParent, polybuffer, gerberMetric); + // shape rotation: + int rotation = wxRound(params[5].GetValue( tool ) * 10.0); + if (rotation) + { + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + RotatePoint(&polybuffer[ii], rotation); + } + // Move to current position: + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + polybuffer[ii] += curPos; + GRClosedPoly( aClipBox, aDC, polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); + } + break; + + case AMP_THERMAL: + { + /* Generated by an aperture macro declaration like: + * "7,0,0,1.0,0.3,0.01,-13*" + * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation + * type is not stored in parameters list, so the first parameter is pos.x + */ + ConvertShapeToPolygon(aParent, polybuffer, gerberMetric); + // shape rotation: + int rotation = wxRound(params[6].GetValue( tool ) * 10.0); + if (rotation) + { + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + RotatePoint(&polybuffer[ii], rotation); + } + // Move to current position: + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + polybuffer[ii] += curPos; + GRClosedPoly( aClipBox, aDC, polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); +printf(" AMP_THERMAL %d\n",polybuffer.size()); + } + break; + + case AMP_MOIRE: // A cross hair with n concentric circles + { + curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), + gerberMetric ); + + /* Generated by an aperture macro declaration like: + * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0" + * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness, crosshaire len, rotation + * type is not stored in parameters list, so the first parameter is pos.x + */ + int outerDiam = scale( params[2].GetValue( tool ), gerberMetric ); + int penThickness = scale( params[3].GetValue( tool ), gerberMetric ); + int gap = scale( params[4].GetValue( tool ), gerberMetric ); + int numCircles = wxRound(params[5].GetValue( tool )); + + // adjust outerDiam by this on each nested circle + int diamAdjust = (gap + penThickness);//*2; //Should we use * 2 ? + for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust ) + { + if( outerDiam <= 0 ) + break; + if( !aFilledShape ) + { + // draw the border of the pen's path using two circles, each as narrow as possible + GRCircle( aClipBox, aDC, curPos.x, curPos.y, outerDiam/2, 0, aColor ); + GRCircle( aClipBox, aDC, curPos.x, curPos.y, outerDiam/2 - penThickness, 0, aColor ); + } + else // Filled mode + { + GRCircle( aClipBox, aDC, curPos.x, curPos.y, (outerDiam-penThickness)/2, penThickness, aColor ); + } + } + // Draw the cross: + ConvertShapeToPolygon(aParent, polybuffer, gerberMetric); + // shape rotation: + int rotation = wxRound(params[8].GetValue( tool ) * 10.0); + if (rotation) + { + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + RotatePoint(&polybuffer[ii], rotation); + } + // Move to current position: + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + polybuffer[ii] += curPos; + GRClosedPoly( aClipBox, aDC, polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); + } + break; + + case AMP_OUTLINE: +#if defined(DEBUG) + { + int exposure = params[0].GetValue( tool ); + int numPoints = (int) this->params[1].GetValue( tool ); + int rotation = wxRound(params[numPoints * 2 + 4].GetValue( tool ) * 10.0); + + printf( "AMP_OUTLINE:\n" ); + printf( " exposure: %g\n", exposure ); + printf( " # points: %d\n", numPoints ); + + // numPoints does not include the starting point, so add 1. + for( int i = 0; iparams[i * 2 + 2 + 0].GetValue( tool ), + this->params[i * 2 + 2 + 1].GetValue( tool ) + ); + } + + printf( " rotation: %g\n", (float)rotation/10 ); + } +#endif + break; + + case AMP_UNKNOWN: + case AMP_POLYGON: + case AMP_EOF: + default: + + // not yet supported, waiting for you. + break; + } +} + + +/** function ConvertShapeToPolygon (virtual) + * convert a shape to an equivalent polygon. + * Arcs and circles are approximated by segments + * Useful when a shape is not a graphic primitive (shape with hole, + * rotated shape ... ) and cannot be easily drawn. + * note for some schapes conbining circles and solid lines (rectangles), only rectangles are converted + * because circles are very easy to draw (no rotation problem) so convert them in polygons, + * and draw them as polygons is not a good idea. + */ +void AM_PRIMITIVE::ConvertShapeToPolygon( GERBER_DRAW_ITEM* aParent, std::vector& aBuffer, bool aUnitsMetric) +{ + D_CODE* tool = aParent->GetDcodeDescr(); + switch( primitive_id ) + { + case AMP_CIRCLE: // Circle, currently convertion not needed + break; + + case AMP_LINE2: + case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation) + { + int width = scale( this->params[1].GetValue( tool ), aUnitsMetric ); + wxPoint start = mapPt( this->params[2].GetValue( tool ), + this->params[3].GetValue( tool ), aUnitsMetric ); + wxPoint end = mapPt( this->params[4].GetValue( tool ), + this->params[5].GetValue( tool ), aUnitsMetric ); + wxPoint delta = end - start; + int len = wxRound(hypot(delta.x, delta.y)); + // To build the polygon, we must create a horizonta polygon starting to "start" + // and rotate it to have it end point to "end" + wxPoint currpt; + currpt.y += width/2; // Upper left + aBuffer.push_back(currpt); + currpt.x = len; // Upper right + aBuffer.push_back(currpt); + currpt.y -= width; // lower right + aBuffer.push_back(currpt); + currpt.x = 0; // Upper left + aBuffer.push_back(currpt); + // Rotate rectangle and move it to the actual start point + int angle = wxRound( atan2(delta.y, delta.x) * 1800.0 / M_PI ); + for( unsigned ii = 0; ii < 4; ii++ ) + { + RotatePoint(&aBuffer[ii], -angle); + aBuffer[ii] += start; + NEGATE(aBuffer[ii].y); + } + } + break; + + case AMP_LINE_CENTER: + { + wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), aUnitsMetric ); + wxPoint pos = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ), aUnitsMetric ); + // Build poly: + pos.x -= size.x/2; + pos.y -= size.y/2; // Lower left + aBuffer.push_back(pos); + pos.y += size.y; // Upper left + aBuffer.push_back(pos); + pos.x += size.x; // Upper right + aBuffer.push_back(pos); + pos.y -= size.y; // lower right + aBuffer.push_back(pos); + } + break; + + case AMP_LINE_LOWER_LEFT: + { + wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), aUnitsMetric ); + wxPoint lowerLeft = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ), aUnitsMetric ); + // Build poly: + NEGATE(lowerLeft.y); + aBuffer.push_back(lowerLeft); + lowerLeft.y += size.y; // Upper left + aBuffer.push_back(lowerLeft); + lowerLeft.x += size.x; // Upper right + aBuffer.push_back(lowerLeft); + lowerLeft.y -= size.y; // lower right + aBuffer.push_back(lowerLeft); + // Negate y coordinates: + for( unsigned ii = 0; ii < aBuffer.size(); ii++ ) + NEGATE(aBuffer[ii].y); + } + break; + + case AMP_THERMAL: + { + int outerDiam = scale( this->params[2].GetValue( tool ), aUnitsMetric ); + int innerDiam = scale( this->params[3].GetValue( tool ), aUnitsMetric ); + } + break; + + case AMP_MOIRE: // A cross hair with n concentric circles. Only the cros is build as polygon + // because circles can be drawn easily + { + int crossHairThickness = scale( this->params[6].GetValue( tool ), aUnitsMetric ); + int crossHairLength = scale( this->params[7].GetValue( tool ), aUnitsMetric ); + // Create cross. First create 1/4 of the shape. + // Others point are the same, totated by 90, 180 and 270 deg + wxPoint pos(crossHairThickness/2, crossHairLength/2); + aBuffer.push_back(pos); + pos.y = crossHairThickness/2; + aBuffer.push_back(pos); + pos.x = -crossHairLength/2; + aBuffer.push_back(pos); + pos.y = -crossHairThickness/2; + aBuffer.push_back(pos); + // Copy these 4 points, rotated by 90, 180 and 270 deg + for( int jj = 900; jj <= 2700; jj += 900 ) + { + for( int ii = 0; ii < 4; ii++ ) + { + pos = aBuffer[ii]; + RotatePoint(&pos,jj); + aBuffer.push_back(pos); + } + } + } + break; + + case AMP_UNKNOWN: + case AMP_OUTLINE: + case AMP_POLYGON: + case AMP_EOF: + break; + } +} + + +/** function DrawApertureMacroShape + * Draw the primitive shape for flashed items. + * When an item is flashed, this is the shape of the item + */ +void APERTURE_MACRO::DrawApertureMacroShape( GERBER_DRAW_ITEM* aParent, + EDA_Rect* aClipBox, + wxDC* aDC, + int aColor, + wxPoint aShapePos, + bool aFilledShape ) +{ + for( AM_PRIMITIVES::iterator prim_macro = primitives.begin(); + prim_macro != primitives.end(); ++prim_macro ) + { + prim_macro->DrawBasicShape( aParent, aClipBox, aDC, aColor, aShapePos, aFilledShape ); + } +} diff --git a/gerbview/class_aperture_macro.h b/gerbview/class_aperture_macro.h new file mode 100644 index 0000000000..8df8b8e6cf --- /dev/null +++ b/gerbview/class_aperture_macro.h @@ -0,0 +1,159 @@ +/**************************/ +/* class_aperture_macro.h */ +/**************************/ + +#ifndef _APERTURE_MACRO_H_ +#define _APERTURE_MACRO_H_ + +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 1992-2010 Jean-Pierre Charras + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 1992-2010 Kicad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#include "base_struct.h" + + +/** + * Enum AM_PRIMITIVE_ID + * is the set of all "aperture macro primitives" (primitive numbers). See + * Table 3 in http://gerbv.sourceforge.net/docs/rs274xrevd_e.pdf + * aperture macro primitives are basic shapes which can be combined to create a complex shape + * This complex shape is flashed. + */ +enum AM_PRIMITIVE_ID { + AMP_UNKNOWN = 0, // A value for uninitialized AM_PRIMITIVE. + AMP_CIRCLE = 1, // Circle. (diameter and position) + AMP_LINE2 = 2, // Line with rectangle ends. (Width, start and end pos + rotation) + AMP_LINE20 = 20, // Same as AMP_LINE2 + AMP_LINE_CENTER = 21, // Rectangle. (height, width and center pos + rotation) + AMP_LINE_LOWER_LEFT = 22, // Rectangle. (height, width and left bottom corner pos + rotation) + AMP_EOF = 3, // End Of File marquer: not really a shape + AMP_OUTLINE = 4, // Free polyline (n corners + rotation) + AMP_POLYGON = 5, // Closed regular polygon(diameter, number of vertices (3 to 10), rotation) + AMP_MOIRE = 6, // A cross hair with n concentric circles + rotation + AMP_THERMAL = 7, // Thermal shape (pos, outer and inner diameter, cross hair thickness + rotation) +}; + + +/** + * Struct AM_PRIMITIVE + * holds an aperture macro primitive as given in Table 3 of + * http://gerbv.sourceforge.net/docs/rs274xrevd_e.pdf + */ +class AM_PRIMITIVE +{ +public: + AM_PRIMITIVE_ID primitive_id; ///< The primitive type + DCODE_PARAMS params; ///< A sequence of parameters used by + // the primitive + +public: + AM_PRIMITIVE( AM_PRIMITIVE_ID aId = AMP_UNKNOWN ) + { + primitive_id = aId; + } + + + ~AM_PRIMITIVE() {} + + /** + * Function GetExposure + * returns the first parameter in integer form. Some but not all primitives + * use the first parameter as an exposure control. + */ + int GetExposure() const + { + // No D_CODE* for GetValue() + wxASSERT( params.size() && params[0].IsImmediate() ); + return (int) params[0].GetValue( NULL ); + } + + + /* Draw functions: */ + + /** function DrawBasicShape + * Draw the primitive shape for flashed items. + */ + void DrawBasicShape( GERBER_DRAW_ITEM* aParent, EDA_Rect* aClipBox, wxDC* aDC, + int aColor, wxPoint aShapePos, bool aFilledShape ); + +private: + + /** function ConvertShapeToPolygon + * convert a shape to an equivalent polygon. + * Arcs and circles are approximated by segments + * Useful when a shape is not a graphic primitive (shape with hole, + * rotated shape ... ) and cannot be easily drawn. + */ + void ConvertShapeToPolygon( GERBER_DRAW_ITEM* aParent, std::vector& aBuffer, bool aUnitsMetric); +}; + + +typedef std::vector AM_PRIMITIVES; + +/** + * Struct APERTURE_MACRO + * helps support the "aperture macro" defined within standard RS274X. + */ +struct APERTURE_MACRO +{ + wxString name; ///< The name of the aperture macro + AM_PRIMITIVES primitives; ///< A sequence of AM_PRIMITIVEs + + /** function DrawApertureMacroShape + * Draw the primitive shape for flashed items. + * When an item is flashed, this is the shape of the item + */ + void DrawApertureMacroShape( GERBER_DRAW_ITEM* aParent, EDA_Rect* aClipBox, wxDC* aDC, + int aColor, wxPoint aShapePos, bool aFilledShape ); +}; + + +/** + * Struct APERTURE_MACRO_less_than + * is used by std:set instantiation which uses + * APERTURE_MACRO.name as its key. + */ +struct APERTURE_MACRO_less_than +{ + // a "less than" test on two APERTURE_MACROs (.name wxStrings) + bool operator()( const APERTURE_MACRO& am1, const APERTURE_MACRO& am2 ) const + { + return am1.name.Cmp( am2.name ) < 0; // case specific wxString compare + } +}; + + +/** + * Type APERTURE_MACRO_SET + * is a sorted collection of APERTURE_MACROS whose key is the name field in + * the APERTURE_MACRO. + */ +typedef std::set APERTURE_MACRO_SET; +typedef std::pair APERTURE_MACRO_SET_PAIR; + + +#endif // ifndef _APERTURE_MACRO_H_