 // 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  // 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 |
|
/**
* @file class_bitmap_base.cpp */
/*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 jean-pierre.charras * Copyright (C) 2011-2017 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 */
#include "fctsys.h"
#include "gr_basic.h"
#include "macros.h"
#include "trigo.h"
#include "common.h"
#include "richio.h"
#include "plotter.h"
#include "bitmap_base.h"
#include <wx/mstream.h>
/**********************//* class BITMAP_BASE *//**********************/
BITMAP_BASE::BITMAP_BASE( const wxPoint& pos ){ m_scale = 1.0; // 1.0 = original bitmap size
m_bitmap = NULL; m_image = NULL; m_ppi = 300; // the bitmap definition. the default is 300PPI
m_pixelScaleFactor = 1000.0 / m_ppi; // a value OK for bitmaps using 300 PPI
// for Eeschema which uses currently 1000PPI
}
BITMAP_BASE::BITMAP_BASE( const BITMAP_BASE& aSchBitmap ){ m_scale = aSchBitmap.m_scale; m_ppi = aSchBitmap.m_ppi; m_pixelScaleFactor = aSchBitmap.m_pixelScaleFactor;
m_image = nullptr; m_bitmap = nullptr;
if( aSchBitmap.m_image ) { m_image = new wxImage( *aSchBitmap.m_image ); m_bitmap = new wxBitmap( *m_image ); }}
/**
* Function ImportData * Copy aItem image to me and update m_bitmap */void BITMAP_BASE::ImportData( BITMAP_BASE* aItem ){ *m_image = *aItem->m_image; *m_bitmap = *aItem->m_bitmap; m_scale = aItem->m_scale; m_ppi = aItem->m_ppi; m_pixelScaleFactor = aItem->m_pixelScaleFactor;}
bool BITMAP_BASE::ReadImageFile( wxInputStream& aInStream ){ auto new_image = std::make_unique<wxImage>();
if( !new_image->LoadFile( aInStream ) ) { return false; }
delete m_image; m_image = new_image.release(); m_bitmap = new wxBitmap( *m_image );
return true;}
bool BITMAP_BASE::ReadImageFile( const wxString& aFullFilename ){ wxImage* new_image = new wxImage();
if( !new_image->LoadFile( aFullFilename ) ) { delete new_image; return false; }
delete m_image; m_image = new_image; m_bitmap = new wxBitmap( *m_image );
return true;}
bool BITMAP_BASE::SaveData( FILE* aFile ) const{ if( m_image ) { wxMemoryOutputStream stream; m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
// Write binary data in hexadecimal form (ASCII)
wxStreamBuffer* buffer = stream.GetOutputStreamBuffer(); char* begin = (char*) buffer->GetBufferStart();
for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ ) { if( ii >= 32 ) { ii = 0;
if( fprintf( aFile, "\n" ) == EOF ) return false; }
if( fprintf( aFile, "%2.2X ", *begin & 0xFF ) == EOF ) return false; } }
return true;}
void BITMAP_BASE::SaveData( wxArrayString& aPngStrings ) const{ if( m_image ) { wxMemoryOutputStream stream; m_image->SaveFile( stream, wxBITMAP_TYPE_PNG );
// Write binary data in hexadecimal form (ASCII)
wxStreamBuffer* buffer = stream.GetOutputStreamBuffer(); char* begin = (char*) buffer->GetBufferStart(); wxString line;
for( int ii = 0; begin < buffer->GetBufferEnd(); begin++, ii++ ) { if( ii >= 32 ) { ii = 0; aPngStrings.Add( line ); line.Empty(); }
line << wxString::Format( wxT( "%2.2X " ), *begin & 0xFF ); }
// Add last line:
if( !line.IsEmpty() ) aPngStrings.Add( line ); }}
bool BITMAP_BASE::LoadData( LINE_READER& aLine, wxString& aErrorMsg ){ wxMemoryOutputStream stream; char* line;
while( true ) { if( !aLine.ReadLine() ) { aErrorMsg = wxT("Unexpected end of data"); return false; }
line = aLine.Line();
if( strncasecmp( line, "EndData", 4 ) == 0 ) { // all the PNG date is read.
// We expect here m_image and m_bitmap are void
m_image = new wxImage(); wxMemoryInputStream istream( stream ); m_image->LoadFile( istream, wxBITMAP_TYPE_PNG ); m_bitmap = new wxBitmap( *m_image ); break; }
// Read PNG data, stored in hexadecimal,
// each byte = 2 hexadecimal digits and a space between 2 bytes
// and put it in memory stream buffer
int len = strlen( line );
for( ; len > 0; len -= 3, line += 3 ) { int value = 0;
if( sscanf( line, "%X", &value ) == 1 ) stream.PutC( (char) value ); else break; } }
return true;}
const EDA_RECT BITMAP_BASE::GetBoundingBox() const{ EDA_RECT rect;
wxSize size = GetSize();
rect.Inflate( size.x / 2, size.y / 2 );
return rect;}
void BITMAP_BASE::DrawBitmap( wxDC* aDC, const wxPoint& aPos ){ if( m_bitmap == NULL ) return;
wxPoint pos = aPos; wxSize size = GetSize();
// This fixes a bug in OSX that should be fixed in the 3.0.3 version or later.
if( ( size.x == 0 ) || ( size.y == 0 ) ) return;
// To draw the bitmap, pos is the upper left corner position
pos.x -= size.x / 2; pos.y -= size.y / 2;
double scale; int logicalOriginX, logicalOriginY; aDC->GetUserScale( &scale, &scale ); aDC->GetLogicalOrigin( &logicalOriginX, &logicalOriginY ); aDC->SetUserScale( scale * GetScalingFactor(), scale * GetScalingFactor() ); aDC->SetLogicalOrigin( logicalOriginX / GetScalingFactor(), logicalOriginY / GetScalingFactor() ); aDC->DrawBitmap( *m_bitmap, KiROUND( pos.x / GetScalingFactor() ), KiROUND( pos.y / GetScalingFactor() ), true ); aDC->SetUserScale( scale, scale ); aDC->SetLogicalOrigin( logicalOriginX, logicalOriginY );}
wxSize BITMAP_BASE::GetSize() const{ wxSize size;
if( m_bitmap ) { size.x = m_bitmap->GetWidth(); size.y = m_bitmap->GetHeight();
size.x = KiROUND( size.x * GetScalingFactor() ); size.y = KiROUND( size.y * GetScalingFactor() ); }
return size;}
void BITMAP_BASE::Mirror( bool aVertically ){ if( m_image ) { *m_image = m_image->Mirror( not aVertically ); RebuildBitmap(); }}
void BITMAP_BASE::Rotate( bool aRotateCCW ){ if( m_image ) { *m_image = m_image->Rotate90( aRotateCCW ); RebuildBitmap(); }}
void BITMAP_BASE::PlotImage( PLOTTER* aPlotter, const wxPoint& aPos, COLOR4D aDefaultColor, int aDefaultPensize ){ if( m_image == NULL ) return;
// These 2 lines are useful only for plotters that cannot plot a bitmap
// and plot a rectangle instead of.
aPlotter->SetColor( aDefaultColor ); aPlotter->SetCurrentLineWidth( aDefaultPensize ); aPlotter->PlotImage( *m_image, aPos, GetScalingFactor() );}
|