/****************************/ /* 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 ); } }