 // Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
14 years ago |
|
/*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2009 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net> * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.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 */
/**
* @file dcode.cpp * @brief D_CODE class implementation */
#include <fctsys.h>
#include <common.h>
#include <class_drawpanel.h>
#include <trigo.h>
#include <gerbview_frame.h>
#include <class_gerber_file_image.h>
#include <convert_to_biu.h>
#define DCODE_DEFAULT_SIZE Millimeter2iu( 0.1 )
/* Format Gerber: NOTES:
* Tools and D_CODES * tool number (identification of shapes) * 1 to 999 * * D_CODES: * D01 ... D9 = command codes: * D01 = activating light (pen down) while moving * D02 = light extinction (pen up) while moving * D03 = Flash * D04 to D09 = non used * D10 ... D999 = Identification Tool (Shape id) * * For tools defining a shape): * DCode min = D10 * DCode max = 999 */
/***************/ /* Class DCODE */ /***************/
D_CODE::D_CODE( int num_dcode ) { m_Num_Dcode = num_dcode; Clear_D_CODE_Data(); }
D_CODE::~D_CODE() { }
void D_CODE::Clear_D_CODE_Data() { m_Size.x = DCODE_DEFAULT_SIZE; m_Size.y = DCODE_DEFAULT_SIZE; m_Shape = APT_CIRCLE; m_Drill.x = m_Drill.y = 0; m_DrillShape = APT_DEF_NO_HOLE; m_InUse = false; m_Defined = false; m_Macro = NULL; m_Rotation = 0.0; m_EdgesCount = 0; m_PolyCorners.clear(); }
const wxChar* D_CODE::ShowApertureType( APERTURE_T aType ) { const wxChar* ret;
switch( aType ) { case APT_CIRCLE: ret = wxT( "Round" ); break;
case APT_RECT: ret = wxT( "Rect" ); break;
case APT_OVAL: ret = wxT( "Oval" ); break;
case APT_POLYGON: ret = wxT( "Poly" ); break;
case APT_MACRO: ret = wxT( "Macro" ); break;
default: ret = wxT( "???" ); break; }
return ret; }
int D_CODE::GetShapeDim( GERBER_DRAW_ITEM* aParent ) { int dim = -1; switch( m_Shape ) { case APT_CIRCLE: dim = m_Size.x; break;
case APT_RECT: case APT_OVAL: dim = std::min( m_Size.x, m_Size.y ); break;
case APT_POLYGON: dim = std::min( m_Size.x, m_Size.y ); break;
case APT_MACRO: if( m_Macro ) dim = m_Macro->GetShapeDim( aParent ); break;
default: break; }
return dim; }
void D_CODE::DrawFlashedShape( GERBER_DRAW_ITEM* aParent, EDA_RECT* aClipBox, wxDC* aDC, EDA_COLOR_T aColor, EDA_COLOR_T aAltColor, wxPoint aShapePos, bool aFilledShape ) { int radius;
switch( m_Shape ) { case APT_MACRO: GetMacro()->DrawApertureMacroShape( aParent, aClipBox, aDC, aColor, aAltColor, aShapePos, aFilledShape); break;
case APT_CIRCLE: radius = m_Size.x >> 1; if( !aFilledShape ) GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius, 0, aColor ); else if( m_DrillShape == APT_DEF_NO_HOLE ) { GRFilledCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius, aColor ); } else if( APT_DEF_ROUND_HOLE == 1 ) // round hole in shape
{ int width = (m_Size.x - m_Drill.x ) / 2; GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius - (width / 2), width, aColor ); } else // rectangular hole
{ if( m_PolyCorners.size() == 0 ) ConvertShapeToPolygon();
DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos ); } break;
case APT_RECT: { wxPoint start; start.x = aShapePos.x - m_Size.x / 2; start.y = aShapePos.y - m_Size.y / 2; wxPoint end = start + m_Size; start = aParent->GetABPosition( start ); end = aParent->GetABPosition( end );
if( !aFilledShape ) { GRRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor ); } else if( m_DrillShape == APT_DEF_NO_HOLE ) { GRFilledRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor, aColor ); } else { if( m_PolyCorners.size() == 0 ) ConvertShapeToPolygon();
DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos ); } } break;
case APT_OVAL: { wxPoint start = aShapePos; wxPoint end = aShapePos;
if( m_Size.x > m_Size.y ) // horizontal oval
{ int delta = (m_Size.x - m_Size.y) / 2; start.x -= delta; end.x += delta; radius = m_Size.y; } else // horizontal oval
{ int delta = (m_Size.y - m_Size.x) / 2; start.y -= delta; end.y += delta; radius = m_Size.x; }
start = aParent->GetABPosition( start ); end = aParent->GetABPosition( end );
if( !aFilledShape ) { GRCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor ); } else if( m_DrillShape == APT_DEF_NO_HOLE ) { GRFillCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor ); } else { if( m_PolyCorners.size() == 0 ) ConvertShapeToPolygon();
DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos ); } } break;
case APT_POLYGON: if( m_PolyCorners.size() == 0 ) ConvertShapeToPolygon();
DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos ); break; } }
void D_CODE::DrawFlashedPolygon( GERBER_DRAW_ITEM* aParent, EDA_RECT* aClipBox, wxDC* aDC, EDA_COLOR_T aColor, bool aFilled, const wxPoint& aPosition ) { if( m_PolyCorners.size() == 0 ) return;
std::vector<wxPoint> points; points = m_PolyCorners;
for( unsigned ii = 0; ii < points.size(); ii++ ) { points[ii] += aPosition; points[ii] = aParent->GetABPosition( points[ii] ); }
GRClosedPoly( aClipBox, aDC, points.size(), &points[0], aFilled, aColor, aColor ); }
#define SEGS_CNT 32 // number of segments to approximate a circle
// A helper function for D_CODE::ConvertShapeToPolygon(). Add a hole to a polygon
static void addHoleToPolygon( std::vector<wxPoint>& aBuffer, APERTURE_DEF_HOLETYPE aHoleShape, wxSize aSize, wxPoint aAnchorPos );
void D_CODE::ConvertShapeToPolygon() { wxPoint initialpos; wxPoint currpos;
m_PolyCorners.clear();
switch( m_Shape ) { case APT_CIRCLE: // creates only a circle with rectangular hole
currpos.x = m_Size.x >> 1; initialpos = currpos;
for( unsigned ii = 0; ii <= SEGS_CNT; ii++ ) { currpos = initialpos; RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT ); m_PolyCorners.push_back( currpos ); }
addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos ); break;
case APT_RECT: currpos.x = m_Size.x / 2; currpos.y = m_Size.y / 2; initialpos = currpos; m_PolyCorners.push_back( currpos ); currpos.x -= m_Size.x; m_PolyCorners.push_back( currpos ); currpos.y -= m_Size.y; m_PolyCorners.push_back( currpos ); currpos.x += m_Size.x; m_PolyCorners.push_back( currpos ); currpos.y += m_Size.y; m_PolyCorners.push_back( currpos ); // close polygon
addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos ); break;
case APT_OVAL: { int delta, radius;
// we create an horizontal oval shape. then rotate if needed
if( m_Size.x > m_Size.y ) // horizontal oval
{ delta = (m_Size.x - m_Size.y) / 2; radius = m_Size.y / 2; } else // vertical oval
{ delta = (m_Size.y - m_Size.x) / 2; radius = m_Size.x / 2; }
currpos.y = radius; initialpos = currpos; m_PolyCorners.push_back( currpos );
// build the right arc of the shape
unsigned ii = 0;
for( ; ii <= SEGS_CNT / 2; ii++ ) { currpos = initialpos; RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT ); currpos.x += delta; m_PolyCorners.push_back( currpos ); }
// build the left arc of the shape
for( ii = SEGS_CNT / 2; ii <= SEGS_CNT; ii++ ) { currpos = initialpos; RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT ); currpos.x -= delta; m_PolyCorners.push_back( currpos ); }
m_PolyCorners.push_back( initialpos ); // close outline
if( m_Size.y > m_Size.x ) // vertical oval, rotate polygon.
{ for( unsigned jj = 0; jj < m_PolyCorners.size(); jj++ ) RotatePoint( &m_PolyCorners[jj], 900 ); }
addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos ); } break;
case APT_POLYGON: currpos.x = m_Size.x >> 1; // first point is on X axis
initialpos = currpos;
// rs274x said: m_EdgesCount = 3 ... 12
if( m_EdgesCount < 3 ) m_EdgesCount = 3;
if( m_EdgesCount > 12 ) m_EdgesCount = 12;
for( int ii = 0; ii <= m_EdgesCount; ii++ ) { currpos = initialpos; RotatePoint( &currpos, ii * 3600.0 / m_EdgesCount ); m_PolyCorners.push_back( currpos ); }
addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos );
if( m_Rotation ) // vertical oval, rotate polygon.
{ int angle = KiROUND( m_Rotation * 10 );
for( unsigned jj = 0; jj < m_PolyCorners.size(); jj++ ) { RotatePoint( &m_PolyCorners[jj], -angle ); } }
break;
case APT_MACRO:
// TODO
break; } }
// The helper function for D_CODE::ConvertShapeToPolygon().
// Add a hole to a polygon
static void addHoleToPolygon( std::vector<wxPoint>& aBuffer, APERTURE_DEF_HOLETYPE aHoleShape, wxSize aSize, wxPoint aAnchorPos ) { wxPoint currpos;
if( aHoleShape == APT_DEF_ROUND_HOLE ) // build a round hole
{ for( int ii = 0; ii <= SEGS_CNT; ii++ ) { currpos.x = 0; currpos.y = aSize.x / 2; // aSize.x / 2 is the radius of the hole
RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT ); aBuffer.push_back( currpos ); }
aBuffer.push_back( aAnchorPos ); // link to outline
}
if( aHoleShape == APT_DEF_RECT_HOLE ) // Create rectangular hole
{ currpos.x = aSize.x / 2; currpos.y = aSize.y / 2; aBuffer.push_back( currpos ); // link to hole and begin hole
currpos.x -= aSize.x; aBuffer.push_back( currpos ); currpos.y -= aSize.y; aBuffer.push_back( currpos ); currpos.x += aSize.x; aBuffer.push_back( currpos ); currpos.y += aSize.y; aBuffer.push_back( currpos ); // close hole
aBuffer.push_back( aAnchorPos ); // link to outline
} }
|