diff options
Diffstat (limited to 'gerbview/class_aperture_macro.cpp')
-rw-r--r-- | gerbview/class_aperture_macro.cpp | 811 |
1 files changed, 811 insertions, 0 deletions
diff --git a/gerbview/class_aperture_macro.cpp b/gerbview/class_aperture_macro.cpp new file mode 100644 index 0000000..0c48a5b --- /dev/null +++ b/gerbview/class_aperture_macro.cpp @@ -0,0 +1,811 @@ +/** + * @file 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 <jean-pierre.charras@gipsa-lab.inpg.fr> + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> + * 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 <gr_basic.h> + +#include <gerbview.h> +#include <class_GERBER.h> + + + +/** + * Function scaletoIU + * converts a distance given in floating point to our internal units + */ +extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordiantes.cpp + +/** + * Function mapPt + * translates a point from the aperture macro coordinate system to our + * deci-mils coordinate system. + * @return wxPoint - The GerbView coordinate system vector. + */ +static wxPoint mapPt( double x, double y, bool isMetric ) +{ + wxPoint ret( scaletoIU( x, isMetric ), scaletoIU( y, isMetric ) ); + + return ret; +} + +/** + * Function mapExposure + * translates the first parameter from an aperture macro into a current + * exposure setting. + * @param aParent = a GERBER_DRAW_ITEM that handle: + * ** m_Exposure A dynamic setting which can change throughout the + * reading of the gerber file, and it indicates whether the current tool + * is lit or not. + * ** m_ImageNegative A dynamic setting which can change throughout the reading + * of the gerber file, and it indicates whether the current D codes are to + * be interpreted as erasures or not. + * @return true to draw with current color, false to draw with alt color (erase) + */ +bool AM_PRIMITIVE::mapExposure( GERBER_DRAW_ITEM* aParent ) +{ + bool exposure; + switch( primitive_id ) + { + case AMP_CIRCLE: + case AMP_LINE2: + case AMP_LINE20: + case AMP_LINE_CENTER: + case AMP_LINE_LOWER_LEFT: + case AMP_OUTLINE: + case AMP_THERMAL: + case AMP_POLYGON: + // All have an exposure parameter and can return true or false + switch( GetExposure(aParent) ) + { + case 0: // exposure always OFF + exposure = false; + break; + + default: + case 1: // exposure always OON + exposure = true; + break; + + case 2: // reverse exposure + exposure = !aParent->GetLayerPolarity(); + } + break; + + case AMP_MOIRE: + case AMP_EOF: + case AMP_UNKNOWN: + default: + return true; // All have no exposure parameter and must return true (no change for exposure) + break; + } + + return exposure ^ aParent->m_imageParams->m_ImageNegative; +} + + +/** + * Function GetExposure + * returns the first parameter in integer form. Some but not all primitives + * use the first parameter as an exposure control. + */ +int AM_PRIMITIVE::GetExposure(GERBER_DRAW_ITEM* aParent) const +{ + // No D_CODE* for GetValue() + wxASSERT( params.size() && params[0].IsImmediate() ); + return (int) params[0].GetValue( aParent->GetDcodeDescr() ); +} + +/** + * Function DrawBasicShape + * Draw the primitive shape for flashed items. + */ +void AM_PRIMITIVE::DrawBasicShape( GERBER_DRAW_ITEM* aParent, + EDA_RECT* aClipBox, + wxDC* aDC, + EDA_COLOR_T aColor, EDA_COLOR_T aAltColor, + wxPoint aShapePos, + bool aFilledShape ) +{ + static std::vector<wxPoint> polybuffer; // create a static buffer to avoid a lot of memory reallocation + polybuffer.clear(); + + wxPoint curPos = aShapePos; + D_CODE* tool = aParent->GetDcodeDescr(); + double rotation; + if( mapExposure( aParent ) == false ) + { + std::swap( aColor, aAltColor ); + } + + 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 exposure + */ + curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric ); + curPos = aParent->GetABPosition( curPos ); + int radius = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ) / 2; + if( !aFilledShape ) + GRCircle( aClipBox, aDC, curPos, radius, 0, 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 exposure + */ + ConvertShapeToPolygon( aParent, polybuffer ); + + // shape rotation: + rotation = params[6].GetValue( tool ) * 10.0; + if( rotation != 0) + { + 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; + polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] ); + } + + 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 exposure + */ + ConvertShapeToPolygon( aParent, polybuffer ); + + // shape rotation: + rotation = params[5].GetValue( tool ) * 10.0; + if( rotation != 0 ) + { + 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; + polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] ); + } + + 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 exposure + */ + ConvertShapeToPolygon( aParent, polybuffer ); + + // shape rotation: + rotation = params[5].GetValue( tool ) * 10.0; + if( rotation != 0) + { + 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; + polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] ); + } + + 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 center.x + */ + curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric ); + ConvertShapeToPolygon( aParent, polybuffer ); + + // shape rotation: + rotation = params[5].GetValue( tool ) * 10.0; + + // Because a thermal shape has 4 identical sub-shapes, only one is created in polybuffer. + // We must draw 4 sub-shapes rotated by 90 deg + std::vector<wxPoint> subshape_poly; + for( int ii = 0; ii < 4; ii++ ) + { + subshape_poly = polybuffer; + double sub_rotation = rotation + 900 * ii; + for( unsigned jj = 0; jj < subshape_poly.size(); jj++ ) + RotatePoint( &subshape_poly[jj], -sub_rotation ); + + // Move to current position: + for( unsigned jj = 0; jj < subshape_poly.size(); jj++ ) + { + subshape_poly[jj] += curPos; + subshape_poly[jj] = aParent->GetABPosition( subshape_poly[jj] ); + } + + GRClosedPoly( aClipBox, aDC, + subshape_poly.size(), &subshape_poly[0], true, aAltColor, + aAltColor ); + } + } + break; + + case AMP_MOIRE: // A cross hair with n concentric circles + { + curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), + m_GerbMetric ); + + /* 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 = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ); + int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric ); + int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ); + int numCircles = KiROUND( params[5].GetValue( tool ) ); + + // Draw circles: + wxPoint center = aParent->GetABPosition( curPos ); + // 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, center, outerDiam / 2, 0, aColor ); + GRCircle( aClipBox, aDC, center, outerDiam / 2 - penThickness, 0, aColor ); + } + else // Filled mode + { + GRCircle( aClipBox, aDC, center, + (outerDiam - penThickness) / 2, penThickness, aColor ); + } + } + + // Draw the cross: + ConvertShapeToPolygon( aParent, polybuffer ); + + rotation = params[8].GetValue( tool ) * 10.0; + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + { + // shape rotation: + RotatePoint( &polybuffer[ii], -rotation ); + // Move to current position: + polybuffer[ii] += curPos; + polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] ); + } + + GRClosedPoly( aClipBox, aDC, + polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); + } + break; + + case AMP_OUTLINE: + { + /* Generated by an aperture macro declaration like: + * "4,1,3,0.0,0.0,0.0,0.5,0.5,0.5,0.5,0.0,-25" + * type(4), exposure, corners count, corner1.x, corner.1y, ..., rotation + * type is not stored in parameters list, so the first parameter is exposure + */ + int numPoints = (int) params[1].GetValue( tool ); + rotation = params[numPoints * 2 + 4].GetValue( tool ) * 10.0; + wxPoint pos; + // Read points. numPoints does not include the starting point, so add 1. + for( int i = 0; i<numPoints + 1; ++i ) + { + int jj = i * 2 + 2; + pos.x = scaletoIU( params[jj].GetValue( tool ), m_GerbMetric ); + pos.y = scaletoIU( params[jj + 1].GetValue( tool ), m_GerbMetric ); + polybuffer.push_back(pos); + } + // rotate polygon and move it to the actual position + // shape 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; + polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] ); + } + + GRClosedPoly( aClipBox, aDC, + polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); + } + break; + + case AMP_POLYGON: // Is a regular polygon + /* Generated by an aperture macro declaration like: + * "5,1,0.6,0,0,0.5,25" + * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation + * type is not stored in parameters list, so the first parameter is exposure + */ + curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric ); + // Creates the shape: + ConvertShapeToPolygon( aParent, polybuffer ); + + // rotate polygon and move it to the actual position + rotation = params[5].GetValue( tool ) * 10.0; + for( unsigned ii = 0; ii < polybuffer.size(); ii++ ) + { + RotatePoint( &polybuffer[ii], -rotation ); + polybuffer[ii] += curPos; + polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] ); + } + GRClosedPoly( aClipBox, aDC, + polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor ); + break; + + case AMP_EOF: + // not yet supported, waiting for you. + break; + + case AMP_UNKNOWN: + default: + DBG( printf( "AM_PRIMITIVE::DrawBasicShape() err: unknown prim id %d\n",primitive_id) ); + 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<wxPoint>& aBuffer ) +{ + 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 = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); + wxPoint start = mapPt( params[2].GetValue( tool ), + params[3].GetValue( tool ), m_GerbMetric ); + wxPoint end = mapPt( params[4].GetValue( tool ), + params[5].GetValue( tool ), m_GerbMetric ); + wxPoint delta = end - start; + int len = KiROUND( EuclideanNorm( delta ) ); + + // 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 + double angle = ArcTangente( delta.y, delta.x ); + + for( unsigned ii = 0; ii < 4; ii++ ) + { + RotatePoint( &aBuffer[ii], -angle ); + aBuffer[ii] += start; + } + } + break; + + case AMP_LINE_CENTER: + { + wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric ); + wxPoint pos = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ), m_GerbMetric ); + + // 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 ), m_GerbMetric ); + wxPoint lowerLeft = mapPt( params[3].GetValue( tool ), params[4].GetValue( + tool ), m_GerbMetric ); + + // Build poly: + 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 ); + } + break; + + case AMP_THERMAL: + { + // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first + // rotated by 90, 180 and 270 deg. + // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness + int outerRadius = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2; + int innerRadius = scaletoIU( params[3].GetValue( tool ), m_GerbMetric ) / 2; + int halfthickness = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2; + double angle_start = RAD2DECIDEG( asin( (double) halfthickness / innerRadius ) ); + + // Draw shape in the first cadrant (X and Y > 0) + wxPoint pos, startpos; + + // Inner arc + startpos.x = innerRadius; + double angle_end = 900 - angle_start; + for( double angle = angle_start; angle < angle_end; angle += 100 ) + { + pos = startpos; + RotatePoint( &pos, angle ); + aBuffer.push_back( pos ); + } + + // Last point + pos = startpos; + RotatePoint( &pos, angle_end ); + aBuffer.push_back( pos ); + + // outer arc + startpos.x = outerRadius; + startpos.y = 0; + angle_start = RAD2DECIDEG( asin( (double) halfthickness / outerRadius ) ); + angle_end = 900 - angle_start; + + // First point, near Y axis, outer arc + for( double angle = angle_end; angle > angle_start; angle -= 100 ) + { + pos = startpos; + RotatePoint( &pos, angle ); + aBuffer.push_back( pos ); + } + + // last point + pos = startpos; + RotatePoint( &pos, angle_start ); + aBuffer.push_back( pos ); + + aBuffer.push_back( aBuffer[0] ); // Close poly + } + 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 = scaletoIU( params[6].GetValue( tool ), m_GerbMetric ); + int crossHairLength = scaletoIU( params[7].GetValue( tool ), m_GerbMetric ); + + // 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 the 4 shape, rotated by 90, 180 and 270 deg + for( int jj = 1; jj <= 3; jj ++ ) + { + for( int ii = 0; ii < 4; ii++ ) + { + pos = aBuffer[ii]; + RotatePoint( &pos, jj*900 ); + aBuffer.push_back( pos ); + } + } + } + break; + + case AMP_OUTLINE: + // already is a polygon. Do nothing + break; + + case AMP_POLYGON: // Creates a regular polygon + { + int vertexcount = KiROUND( params[1].GetValue( tool ) ); + int radius = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2; + // rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis + if( vertexcount < 3 ) + vertexcount = 3; + if( vertexcount > 10 ) + vertexcount = 10; + for( int ii = 0; ii <= vertexcount; ii++ ) + { + wxPoint pos( radius, 0); + RotatePoint( &pos, ii * 3600 / vertexcount ); + aBuffer.push_back( pos ); + } + } + break; + + case AMP_COMMENT: + case AMP_UNKNOWN: + case AMP_EOF: + break; + } +} + +/** GetShapeDim + * Calculate a value that can be used to evaluate the size of text + * when displaying the D-Code of an item + * due to the complexity of the shape of some primitives + * one cannot calculate the "size" of a shape (only abounding box) + * but here, the "dimension" of the shape is the diameter of the primitive + * or for lines the width of the line + * @param aParent = the parent GERBER_DRAW_ITEM which is actually drawn + * @return a dimension, or -1 if no dim to calculate + */ +int AM_PRIMITIVE::GetShapeDim( GERBER_DRAW_ITEM* aParent ) +{ + int dim = -1; + D_CODE* tool = aParent->GetDcodeDescr(); + + switch( primitive_id ) + { + case AMP_CIRCLE: + // params = exposure, diameter, pos.x, pos.y + dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // Diameter + break; + + case AMP_LINE2: + case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation) + dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // linne width + break; + + case AMP_LINE_CENTER: + { + wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric ); + dim = std::min(size.x, size.y); + } + break; + + case AMP_LINE_LOWER_LEFT: + { + wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric ); + dim = std::min(size.x, size.y); + } + break; + + case AMP_THERMAL: + { + // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first + // rotated by 90, 180 and 270 deg. + // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness + dim = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2; // Outer diam + } + break; + + case AMP_MOIRE: // A cross hair with n concentric circles. + dim = scaletoIU( params[7].GetValue( tool ), m_GerbMetric ); // = cross hair len + break; + + case AMP_OUTLINE: // a free polygon : + // dim = min side of the bounding box (this is a poor criteria, but what is a good criteria b?) + { + // exposure, corners count, corner1.x, corner.1y, ..., rotation + int numPoints = (int) params[1].GetValue( tool ); + // Read points. numPoints does not include the starting point, so add 1. + // and calculate the bounding box; + wxSize pos_min, pos_max, pos; + for( int i = 0; i<numPoints + 1; ++i ) + { + int jj = i * 2 + 2; + pos.x = scaletoIU( params[jj].GetValue( tool ), m_GerbMetric ); + pos.y = scaletoIU( params[jj + 1].GetValue( tool ), m_GerbMetric ); + if( i == 0 ) + pos_min = pos_max = pos; + else + { + // upper right corner: + if( pos_min.x > pos.x ) + pos_min.x = pos.x; + if( pos_min.y > pos.y ) + pos_min.y = pos.y; + // lower left corner: + if( pos_max.x < pos.x ) + pos_max.x = pos.x; + if( pos_max.y < pos.y ) + pos_max.y = pos.y; + } + } + // calculate dim + wxSize size; + size.x = pos_max.x - pos_min.x; + size.y = pos_max.y - pos_min.y; + dim = std::min( size.x, size.y ); + } + break; + + case AMP_POLYGON: // Regular polygon + dim = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2; // Radius + break; + + case AMP_COMMENT: + case AMP_UNKNOWN: + case AMP_EOF: + break; + } + return dim; +} + + +/** + * 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, + EDA_COLOR_T aColor, EDA_COLOR_T aAltColor, + 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, aAltColor, + aShapePos, + aFilledShape ); + } +} + +/* Function HasNegativeItems + * return true if this macro has at least one aperture primitives + * that must be drawn in background color + * used to optimize screen refresh + */ +bool APERTURE_MACRO::HasNegativeItems( GERBER_DRAW_ITEM* aParent ) +{ + for( AM_PRIMITIVES::iterator prim_macro = primitives.begin(); + prim_macro != primitives.end(); ++prim_macro ) + { + if( prim_macro->mapExposure( aParent ) == false ) // = is negative + return true; + } + + return false; +} + + +/** GetShapeDim + * Calculate a value that can be used to evaluate the size of text + * when displaying the D-Code of an item + * due to the complexity of a shape using many primitives + * one cannot calculate the "size" of a shape (only abounding box) + * but most of aperture macro are using one or few primitives + * and the "dimension" of the shape is the diameter of the primitive + * (or the max diameter of primitives) + * @return a dimension, or -1 if no dim to calculate + */ +int APERTURE_MACRO::GetShapeDim( GERBER_DRAW_ITEM* aParent ) +{ + int dim = -1; + for( AM_PRIMITIVES::iterator prim_macro = primitives.begin(); + prim_macro != primitives.end(); ++prim_macro ) + { + int pdim = prim_macro->GetShapeDim( aParent ); + if( dim < pdim ) + dim = pdim; + } + + return dim; +} + + +/** + * function GetLocalParam + * Usually, parameters are defined inside the aperture primitive + * using immediate mode or defered mode. + * in defered mode the value is defined in a DCODE that want to use the aperture macro. + * But some parameters are defined outside the aperture primitive + * and are local to the aperture macro + * @return the value of a defered parameter defined inside the aperture macro + * @param aParamId = the param id (defined by $3 or $5 ..) to evaluate + */ +double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const +{ + // find parameter descr. + const AM_PARAM * param = NULL; + for( unsigned ii = 0; ii < m_localparamStack.size(); ii ++ ) + { + if( m_localparamStack[ii].GetIndex() == aParamId ) + { + param = &m_localparamStack[ii]; + break; + } + } + if ( param == NULL ) // not found + return 0.0; + // Evaluate parameter + double value = param->GetValue( aDcode ); + return value; +} |