Loading bitmap2component/bitmap2cmp_gui.cpp +17 −6 Original line number Original line Diff line number Diff line Loading @@ -45,6 +45,8 @@ #define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" ) #define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" ) #define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" ) #define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" ) #define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" ) #define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" ) #define KEYWORD_BINARY_THRESHOLD wxT( "Threshold" ) #define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" ) extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ); extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ); Loading Loading @@ -88,6 +90,7 @@ private: BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) { { int tmp; m_Config = new wxConfig(); m_Config = new wxConfig(); m_Config->Read( KEYWORD_FRAME_POSX, & m_FramePos.x, -1 ); m_Config->Read( KEYWORD_FRAME_POSX, & m_FramePos.x, -1 ); m_Config->Read( KEYWORD_FRAME_POSY, & m_FramePos.y, -1 ); m_Config->Read( KEYWORD_FRAME_POSY, & m_FramePos.y, -1 ); Loading @@ -95,6 +98,11 @@ BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) m_Config->Read( KEYWORD_FRAME_SIZEY, & m_FrameSize.y, -1 ); m_Config->Read( KEYWORD_FRAME_SIZEY, & m_FrameSize.y, -1 ); m_Config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName ); m_Config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName ); m_Config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName ); m_Config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName ); if( m_Config->Read( KEYWORD_BINARY_THRESHOLD, &tmp ) ) m_sliderThreshold->SetValue( tmp ); if( m_Config->Read( KEYWORD_BW_NEGATIVE, &tmp ) ) m_rbOptions->SetSelection( tmp ? 1 : 0 ); // Give an icon // Give an icon wxIcon icon; wxIcon icon; Loading Loading @@ -127,6 +135,8 @@ BM2CMP_FRAME::~BM2CMP_FRAME() m_Config->Write( KEYWORD_FRAME_SIZEY, (long) m_FrameSize.y ); m_Config->Write( KEYWORD_FRAME_SIZEY, (long) m_FrameSize.y ); m_Config->Write( KEYWORD_LAST_INPUT_FILE, m_BitmapFileName ); m_Config->Write( KEYWORD_LAST_INPUT_FILE, m_BitmapFileName ); m_Config->Write( KEYWORD_LAST_OUTPUT_FILE, m_ConvertedFileName ); m_Config->Write( KEYWORD_LAST_OUTPUT_FILE, m_ConvertedFileName ); m_Config->Write( KEYWORD_BINARY_THRESHOLD, m_sliderThreshold->GetValue() ); m_Config->Write( KEYWORD_BW_NEGATIVE, m_rbOptions->GetSelection() ); delete m_Config; delete m_Config; Loading Loading @@ -390,16 +400,12 @@ void BM2CMP_FRAME::ExportFile( FILE* aOutfile, int aFormat ) } } // BM_TO_CMP_APP // EDA_APP void EDA_APP::MacOpenFile(const wxString &fileName) { } IMPLEMENT_APP( EDA_APP ) IMPLEMENT_APP( EDA_APP ) ///----------------------------------------------------------------------------- ///----------------------------------------------------------------------------- // BM_TO_CMP_APP // EDA_APP // main program // main program //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- Loading @@ -415,3 +421,8 @@ bool EDA_APP::OnInit() return true; return true; } } void EDA_APP::MacOpenFile(const wxString &fileName) { } bitmap2component/bitmap2component.cpp +123 −188 Original line number Original line Diff line number Diff line Loading @@ -21,8 +21,10 @@ * or you may write to the Free Software Foundation, Inc., * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ */ #include <math.h> #include "kbool/booleng.h" // For some unknown reasons, polygon.hpp shoul be included first #include "boost/polygon/polygon.hpp" #include <stdio.h> #include <stdio.h> #include <string.h> #include <string.h> Loading @@ -34,6 +36,7 @@ #include "potracelib.h" #include "potracelib.h" #include "auxiliary.h" #include "auxiliary.h" #ifndef max #ifndef max #define max( a, b ) ( ( (a) > (b) ) ? (a) : (b) ) #define max( a, b ) ( ( (a) > (b) ) ? (a) : (b) ) #endif #endif Loading @@ -41,6 +44,16 @@ #define min( a, b ) ( ( (a) < (b) ) ? (a) : (b) ) #define min( a, b ) ( ( (a) < (b) ) ? (a) : (b) ) #endif #endif // Define some types used here from boost::polygon namespace bpl = boost::polygon; // bpl = boost polygon library using namespace bpl::operators; // +, -, =, ... typedef int coordinate_type; typedef bpl::polygon_data<coordinate_type> KPolygon; // define a basic polygon typedef std::vector<KPolygon> KPolygonSet; // define a set of polygons typedef bpl::point_data<coordinate_type> KPolyPoint; // define a corner of a polygon enum output_format { enum output_format { POSTSCRIPT_FMT = 1, POSTSCRIPT_FMT = 1, Loading @@ -48,8 +61,10 @@ enum output_format { EESCHEMA_FMT EESCHEMA_FMT }; }; /* free a potrace bitmap */ /* free a potrace bitmap */ static void bm_free(potrace_bitmap_t *bm) { static void bm_free( potrace_bitmap_t* bm ) if (bm != NULL) { { if( bm != NULL ) { free( bm->map ); free( bm->map ); } } free( bm ); free( bm ); Loading @@ -69,8 +84,7 @@ public: double m_ScaleY; // the conversion scale double m_ScaleY; // the conversion scale potrace_path_t* m_Paths; // the list of paths, from potrace (list of lines and bezier curves) potrace_path_t* m_Paths; // the list of paths, from potrace (list of lines and bezier curves) FILE* m_Outfile; FILE* m_Outfile; public: public: BITMAPCONV_INFO(); BITMAPCONV_INFO(); }; }; static void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer, static void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer, Loading @@ -96,101 +110,6 @@ BITMAPCONV_INFO::BITMAPCONV_INFO() } } /** * Function ArmBoolEng * Initialise parameters used in kbool * @param aBooleng = pointer to the Bool_Engine to initialise * @param aConvertHoles = mode for holes when a boolean operation is made * true: in resulting polygon, holes are linked into outer contours by double overlapping segments * false: in resulting polygons, holes are not linked: they are separate polygons */ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) { // set some global vals to arm the boolean engine // input points are scaled up with GetDGrid() * GetGrid() // DGRID is only meant to make fractional parts of input data which /* * The input data scaled up with DGrid is related to the accuracy the user has in his input data. * User data with a minimum accuracy of 0.001, means set the DGrid to 1000. * The input data may contain data with a minimum accuracy much smaller, but by setting the DGrid * everything smaller than 1/DGrid is rounded. * * DGRID is only meant to make fractional parts of input data which can be * doubles, part of the integers used in vertexes within the boolean algorithm. * And therefore DGRID bigger than 1 is not usefull, you would only loose accuracy. * Within the algorithm all input data is multiplied with DGRID, and the result * is rounded to an integer. */ double DGRID = 1000.0; // round coordinate X or Y value in calculations to this (initial value = 1000.0 in kbool example) // kbool uses DGRID to convert float user units to integer // kbool unit = (int)(user unit * DGRID) // Note: in kicad, coordinates are already integer so DGRID could be set to 1 // we can choose 1.0, // but choose DGRID = 1000.0 solves some filling problems // (perhaps because this allows a better precision in kbool internal calculations double MARGE = 1.0 / DGRID; // snap with in this range points to lines in the intersection routines // should always be >= 1/DGRID a MARGE >= 10/DGRID is ok // this is also used to remove small segments and to decide when // two segments are in line. ( initial value = 0.001 ) // For kicad we choose MARGE = 1/DGRID double CORRECTIONFACTOR = 0.0; // correct the polygons by this number: used in BOOL_CORRECTION operation // this operation shrinks a polygon if CORRECTIONFACTOR < 0 // or stretch it if CORRECTIONFACTOR > 0 // the size change is CORRECTIONFACTOR (holes are correctly handled) double CORRECTIONABER = 1.0; // the accuracy for the rounded shapes used in correction double ROUNDFACTOR = 1.5; // when will we round the correction shape to a circle double SMOOTHABER = 10.0; // accuracy when smoothing a polygon double MAXLINEMERGE = 1000.0; // leave as is, segments of this length in smoothen /* * Grid makes sure that the integer data used within the algorithm has room for extra intersections * smaller than the smallest number within the input data. * The input data scaled up with DGrid is related to the accuracy the user has in his input data. * Another scaling with Grid is applied on top of it to create space in the integer number for * even smaller numbers. */ int GRID = (int) ( 10000 / DGRID ); // initial value = 10000 in kbool example // But we use 10000/DGRID because the scalling is made // by DGRID on integer pcbnew units and // the global scalling ( GRID*DGRID) must be < 30000 to avoid // overflow in calculations (made in long long in kbool) if( GRID <= 1 ) // Cannot be null! GRID = 1; aBooleng->SetMarge( MARGE ); aBooleng->SetGrid( GRID ); aBooleng->SetDGrid( DGRID ); aBooleng->SetCorrectionFactor( CORRECTIONFACTOR ); aBooleng->SetCorrectionAber( CORRECTIONABER ); aBooleng->SetSmoothAber( SMOOTHABER ); aBooleng->SetMaxlinemerge( MAXLINEMERGE ); aBooleng->SetRoundfactor( ROUNDFACTOR ); aBooleng->SetWindingRule( true ); // This is the default kbool value if( aConvertHoles ) { #if 1 // Can be set to 1 for kbool version >= 2.1, must be set to 0 for previous versions // SetAllowNonTopHoleLinking() exists only in kbool >= 2.1 aBooleng->SetAllowNonTopHoleLinking( false ); // Default = , but i have problems (filling errors) when true #endif aBooleng->SetLinkHoles( true ); // holes will be connected by double overlapping segments aBooleng->SetOrientationEntryMode( false ); // all polygons are contours, not holes } else { aBooleng->SetLinkHoles( false ); // holes will not be connected by double overlapping segments aBooleng->SetOrientationEntryMode( true ); // holes are entered counter clockwise } } int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ) int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ) { { potrace_param_t* param; potrace_param_t* param; Loading Loading @@ -329,25 +248,32 @@ static void OuputEnd( BITMAPCONV_INFO& aInfo ) } } } } /** static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, * Function OuputOnePolygon std::vector <potrace_dpoint_t>& aPolygonBuffer ) * write one polygon to output file. * Polygon coordinates are expected scaled by the polugon extraction function */ static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, KPolygon & aPolygon ) { { unsigned ii; unsigned ii; KPolyPoint currpoint; int offsetX = (int)( aInfo.m_PixmapWidth / 2 * aInfo.m_ScaleX ); int offsetY = (int)( aInfo.m_PixmapHeight / 2 * aInfo.m_ScaleY ); double offsetX = aInfo.m_PixmapWidth / 2 * aInfo.m_ScaleX; KPolyPoint startpoint = *aPolygon.begin(); double offsetY = aInfo.m_PixmapHeight / 2 * aInfo.m_ScaleY; switch( aInfo.m_Format ) switch( aInfo.m_Format ) { { case POSTSCRIPT_FMT: case POSTSCRIPT_FMT: fprintf( aInfo.m_Outfile, "%f %f moveto\n", fprintf( aInfo.m_Outfile, "%d %d moveto\n", aPolygonBuffer[0].x * aInfo.m_ScaleX, startpoint.x(), startpoint.y() ); aPolygonBuffer[0].y * aInfo.m_ScaleY ); for( ii = 1; ii < aPolygon.size(); ii++ ) for( ii = 1; ii < aPolygonBuffer.size(); ii++ ) { fprintf( aInfo.m_Outfile, "%f %f lineto\n", currpoint = *(aPolygon.begin() + ii); aPolygonBuffer[ii].x * aInfo.m_ScaleX, fprintf( aInfo.m_Outfile, "%d %d lineto\n", aPolygonBuffer[ii].y * aInfo.m_ScaleY ); currpoint.x(), currpoint.y() ); } fprintf( aInfo.m_Outfile, "0 setgray fill\n" ); fprintf( aInfo.m_Outfile, "0 setgray fill\n" ); break; break; Loading @@ -359,30 +285,33 @@ static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, int width = 1; int width = 1; fprintf( aInfo.m_Outfile, "DP %d %d %d %d %d %d %d\n", fprintf( aInfo.m_Outfile, "DP %d %d %d %d %d %d %d\n", 0, 0, 0, 0, 0, 0, 0, 0, int(aPolygonBuffer.size()+1), aPolygon.size() + 1, width, layer ); width, layer ); for( ii = 0; ii < aPolygonBuffer.size(); ii++ ) for( ii = 0; ii < aPolygon.size(); ii++ ) { currpoint = *( aPolygon.begin() + ii ); fprintf( aInfo.m_Outfile, "Dl %d %d\n", fprintf( aInfo.m_Outfile, "Dl %d %d\n", (int) ( aPolygonBuffer[ii].x * aInfo.m_ScaleX - offsetX ), currpoint.x() - offsetX, currpoint.y() - offsetY ); (int) ( aPolygonBuffer[ii].y * aInfo.m_ScaleY - offsetY ) ); } // Close polygon // Close polygon fprintf( aInfo.m_Outfile, "Dl %d %d\n", fprintf( aInfo.m_Outfile, "Dl %d %d\n", (int) ( aPolygonBuffer[0].x * aInfo.m_ScaleX - offsetX ), startpoint.x() - offsetX, startpoint.y() - offsetY ); (int) ( aPolygonBuffer[0].y * aInfo.m_ScaleY - offsetY ) ); } } break; break; case EESCHEMA_FMT: case EESCHEMA_FMT: fprintf( aInfo.m_Outfile, "P %d 0 0 1", int(aPolygonBuffer.size()+1) ); fprintf( aInfo.m_Outfile, "P %d 0 0 1", aPolygon.size() + 1 ); for( ii = 0; ii < aPolygonBuffer.size(); ii++ ) for( ii = 0; ii < aPolygon.size(); ii++ ) { currpoint = *(aPolygon.begin() + ii); fprintf( aInfo.m_Outfile, " %d %d", fprintf( aInfo.m_Outfile, " %d %d", (int) ( aPolygonBuffer[ii].x * aInfo.m_ScaleX - offsetX ), currpoint.x() - offsetX, currpoint.y() - offsetY ); (int) ( aPolygonBuffer[ii].y * aInfo.m_ScaleY - offsetY ) ); } // Close polygon // Close polygon fprintf( aInfo.m_Outfile, " %d %d", fprintf( aInfo.m_Outfile, " %d %d", (int) ( aPolygonBuffer[0].x * aInfo.m_ScaleX - offsetX ), startpoint.x() - offsetX, startpoint.y() - offsetY ); (int) ( aPolygonBuffer[0].y * aInfo.m_ScaleY - offsetY ) ); fprintf( aInfo.m_Outfile, " F\n" ); fprintf( aInfo.m_Outfile, " F\n" ); break; break; Loading @@ -392,16 +321,21 @@ static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) { { unsigned int i, n; KPolyPoint currpoint; int* tag; std::vector <potrace_dpoint_t> cornersBuffer; std::vector <potrace_dpoint_t> cornersBuffer; // This KPolygonSet polyset_areas is a complex polygon to draw // and can be complex depending on holes inside this polygon KPolygonSet polyset_areas; // This KPolygonSet polyset_holes is the set of holes inside polyset_areas KPolygonSet polyset_holes; potrace_dpoint_t( *c )[3]; potrace_dpoint_t( *c )[3]; OuputHeader( aInfo ); OuputHeader( aInfo ); bool main_outline = true; bool main_outline = true; Bool_Engine* booleng = NULL; /* draw each as a polygon with no hole. /* draw each as a polygon with no hole. * Bezier curves are approximated by a polyline * Bezier curves are approximated by a polyline Loading @@ -409,17 +343,11 @@ static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) potrace_path_t* paths = aInfo.m_Paths; // the list of paths potrace_path_t* paths = aInfo.m_Paths; // the list of paths while( paths != NULL ) while( paths != NULL ) { { n = paths->curve.n; int cnt = paths->curve.n; tag = paths->curve.tag; int* tag = paths->curve.tag; c = paths->curve.c; c = paths->curve.c; potrace_dpoint_t startpoint = c[n - 1][2]; potrace_dpoint_t startpoint = c[cnt - 1][2]; cornersBuffer.push_back( startpoint ); for( int i = 0; i < cnt; i++ ) if( booleng == NULL ) { booleng = new Bool_Engine(); ArmBoolEng( booleng, true ); } for( i = 0; i < n; i++ ) { { switch( tag[i] ) switch( tag[i] ) { { Loading @@ -440,46 +368,53 @@ static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) if( main_outline ) if( main_outline ) { { main_outline = false; main_outline = false; booleng->StartPolygonAdd( GROUP_A ); for( i = 1; i < cornersBuffer.size(); i++ ) booleng->AddPoint( cornersBuffer[i].x, cornersBuffer[i].y ); booleng->EndPolygonAdd(); // build the current main polygon std::vector<KPolyPoint> cornerslist; // a simple boost polygon for( unsigned int i = 0; i < cornersBuffer.size(); i++ ) { currpoint.x( (coordinate_type) (cornersBuffer[i].x * aInfo.m_ScaleX) ); currpoint.y( (coordinate_type) (cornersBuffer[i].y * aInfo.m_ScaleY) ); cornerslist.push_back( currpoint ); } KPolygon poly; bpl::set_points( poly, cornerslist.begin(), cornerslist.end() ); polyset_areas.push_back( poly ); } } else else { { booleng->StartPolygonAdd( GROUP_B ); // Add current hole in polyset_holes for( i = 1; i < cornersBuffer.size(); i++ ) std::vector<KPolyPoint> cornerslist; // a simple boost polygon booleng->AddPoint( cornersBuffer[i].x, cornersBuffer[i].y ); for( unsigned int i = 0; i < cornersBuffer.size(); i++ ) { currpoint.x( (coordinate_type) (cornersBuffer[i].x * aInfo.m_ScaleX) ); currpoint.y( (coordinate_type) (cornersBuffer[i].y * aInfo.m_ScaleY) ); cornerslist.push_back( currpoint ); } booleng->EndPolygonAdd(); KPolygon poly; bpl::set_points( poly, cornerslist.begin(), cornerslist.end() ); polyset_holes.push_back( poly ); } } cornersBuffer.clear(); cornersBuffer.clear(); /* at the end of a group of a positive path and its negative /* at the end of a group of a positive path and its negative children, fill. * children, fill. */ */ if( paths->next == NULL || paths->next->sign == '+' ) if( paths->next == NULL || paths->next->sign == '+' ) { { booleng->Do_Operation( BOOL_A_SUB_B ); // Substract holes to main polygon: std::vector <potrace_dpoint_t> PolygonBuffer; polyset_areas -= polyset_holes; while( booleng->StartPolygonGet() ) { potrace_dpoint_t corner; PolygonBuffer.clear(); while( booleng->PolygonHasMorePoints() ) { corner.x = booleng->GetPolygonXPoint(); corner.y = booleng->GetPolygonYPoint(); PolygonBuffer.push_back( corner ); } booleng->EndPolygonGet(); // Output current resulting polygon(s) OuputOnePolygon( aInfo, PolygonBuffer ); for( unsigned ii = 0; ii < polyset_areas.size(); ii++ ) PolygonBuffer.clear(); { KPolygon& poly = polyset_areas[ii]; OuputOnePolygon( aInfo, poly ); } } delete booleng; polyset_areas.clear(); booleng = NULL; polyset_holes.clear(); main_outline = true; main_outline = true; } } paths = paths->next; paths = paths->next; Loading @@ -505,7 +440,7 @@ void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer, * between the true curve and its approximation does not exceed the * between the true curve and its approximation does not exceed the * desired accuracy delta. */ * desired accuracy delta. */ delta = 0.5; /* desired accuracy, in pixels */ delta = 0.25; /* desired accuracy, in pixels */ /* let dd = maximal value of 2nd derivative over curve - this must /* let dd = maximal value of 2nd derivative over curve - this must * occur at an endpoint. */ * occur at an endpoint. */ Loading potrace/potracelib.h +5 −4 Original line number Original line Diff line number Diff line Loading @@ -77,10 +77,11 @@ typedef struct potrace_dpoint_s potrace_dpoint_t; /* closed curve segment */ /* closed curve segment */ struct potrace_curve_s struct potrace_curve_s { { int n; /* number of segments */ int n; // number of segments int* tag; /* tag[n]: POTRACE_CURVETO or POTRACE_CORNER */ int* tag; // tag[n]: POTRACE_CURVETO or POTRACE_CORNER potrace_dpoint_t( * c )[3]; /* c[n][3]: control points. potrace_dpoint_t( * c )[3]; /* c[n][3]: control points. * c[n][0] is unused for tag[n]=POTRACE_CORNER */ * c[n][0] is unused for tag[n]=POTRACE_CORNER */ }; }; typedef struct potrace_curve_s potrace_curve_t; typedef struct potrace_curve_s potrace_curve_t; Loading Loading
bitmap2component/bitmap2cmp_gui.cpp +17 −6 Original line number Original line Diff line number Diff line Loading @@ -45,6 +45,8 @@ #define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" ) #define KEYWORD_FRAME_SIZEY wxT( "Bmconverter_Size_y" ) #define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" ) #define KEYWORD_LAST_INPUT_FILE wxT( "Last_input" ) #define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" ) #define KEYWORD_LAST_OUTPUT_FILE wxT( "Last_output" ) #define KEYWORD_BINARY_THRESHOLD wxT( "Threshold" ) #define KEYWORD_BW_NEGATIVE wxT( "Negative_choice" ) extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ); extern int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ); Loading Loading @@ -88,6 +90,7 @@ private: BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) { { int tmp; m_Config = new wxConfig(); m_Config = new wxConfig(); m_Config->Read( KEYWORD_FRAME_POSX, & m_FramePos.x, -1 ); m_Config->Read( KEYWORD_FRAME_POSX, & m_FramePos.x, -1 ); m_Config->Read( KEYWORD_FRAME_POSY, & m_FramePos.y, -1 ); m_Config->Read( KEYWORD_FRAME_POSY, & m_FramePos.y, -1 ); Loading @@ -95,6 +98,11 @@ BM2CMP_FRAME::BM2CMP_FRAME() : BM2CMP_FRAME_BASE( NULL ) m_Config->Read( KEYWORD_FRAME_SIZEY, & m_FrameSize.y, -1 ); m_Config->Read( KEYWORD_FRAME_SIZEY, & m_FrameSize.y, -1 ); m_Config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName ); m_Config->Read( KEYWORD_LAST_INPUT_FILE, &m_BitmapFileName ); m_Config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName ); m_Config->Read( KEYWORD_LAST_OUTPUT_FILE, &m_ConvertedFileName ); if( m_Config->Read( KEYWORD_BINARY_THRESHOLD, &tmp ) ) m_sliderThreshold->SetValue( tmp ); if( m_Config->Read( KEYWORD_BW_NEGATIVE, &tmp ) ) m_rbOptions->SetSelection( tmp ? 1 : 0 ); // Give an icon // Give an icon wxIcon icon; wxIcon icon; Loading Loading @@ -127,6 +135,8 @@ BM2CMP_FRAME::~BM2CMP_FRAME() m_Config->Write( KEYWORD_FRAME_SIZEY, (long) m_FrameSize.y ); m_Config->Write( KEYWORD_FRAME_SIZEY, (long) m_FrameSize.y ); m_Config->Write( KEYWORD_LAST_INPUT_FILE, m_BitmapFileName ); m_Config->Write( KEYWORD_LAST_INPUT_FILE, m_BitmapFileName ); m_Config->Write( KEYWORD_LAST_OUTPUT_FILE, m_ConvertedFileName ); m_Config->Write( KEYWORD_LAST_OUTPUT_FILE, m_ConvertedFileName ); m_Config->Write( KEYWORD_BINARY_THRESHOLD, m_sliderThreshold->GetValue() ); m_Config->Write( KEYWORD_BW_NEGATIVE, m_rbOptions->GetSelection() ); delete m_Config; delete m_Config; Loading Loading @@ -390,16 +400,12 @@ void BM2CMP_FRAME::ExportFile( FILE* aOutfile, int aFormat ) } } // BM_TO_CMP_APP // EDA_APP void EDA_APP::MacOpenFile(const wxString &fileName) { } IMPLEMENT_APP( EDA_APP ) IMPLEMENT_APP( EDA_APP ) ///----------------------------------------------------------------------------- ///----------------------------------------------------------------------------- // BM_TO_CMP_APP // EDA_APP // main program // main program //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- Loading @@ -415,3 +421,8 @@ bool EDA_APP::OnInit() return true; return true; } } void EDA_APP::MacOpenFile(const wxString &fileName) { }
bitmap2component/bitmap2component.cpp +123 −188 Original line number Original line Diff line number Diff line Loading @@ -21,8 +21,10 @@ * or you may write to the Free Software Foundation, Inc., * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ */ #include <math.h> #include "kbool/booleng.h" // For some unknown reasons, polygon.hpp shoul be included first #include "boost/polygon/polygon.hpp" #include <stdio.h> #include <stdio.h> #include <string.h> #include <string.h> Loading @@ -34,6 +36,7 @@ #include "potracelib.h" #include "potracelib.h" #include "auxiliary.h" #include "auxiliary.h" #ifndef max #ifndef max #define max( a, b ) ( ( (a) > (b) ) ? (a) : (b) ) #define max( a, b ) ( ( (a) > (b) ) ? (a) : (b) ) #endif #endif Loading @@ -41,6 +44,16 @@ #define min( a, b ) ( ( (a) < (b) ) ? (a) : (b) ) #define min( a, b ) ( ( (a) < (b) ) ? (a) : (b) ) #endif #endif // Define some types used here from boost::polygon namespace bpl = boost::polygon; // bpl = boost polygon library using namespace bpl::operators; // +, -, =, ... typedef int coordinate_type; typedef bpl::polygon_data<coordinate_type> KPolygon; // define a basic polygon typedef std::vector<KPolygon> KPolygonSet; // define a set of polygons typedef bpl::point_data<coordinate_type> KPolyPoint; // define a corner of a polygon enum output_format { enum output_format { POSTSCRIPT_FMT = 1, POSTSCRIPT_FMT = 1, Loading @@ -48,8 +61,10 @@ enum output_format { EESCHEMA_FMT EESCHEMA_FMT }; }; /* free a potrace bitmap */ /* free a potrace bitmap */ static void bm_free(potrace_bitmap_t *bm) { static void bm_free( potrace_bitmap_t* bm ) if (bm != NULL) { { if( bm != NULL ) { free( bm->map ); free( bm->map ); } } free( bm ); free( bm ); Loading @@ -69,8 +84,7 @@ public: double m_ScaleY; // the conversion scale double m_ScaleY; // the conversion scale potrace_path_t* m_Paths; // the list of paths, from potrace (list of lines and bezier curves) potrace_path_t* m_Paths; // the list of paths, from potrace (list of lines and bezier curves) FILE* m_Outfile; FILE* m_Outfile; public: public: BITMAPCONV_INFO(); BITMAPCONV_INFO(); }; }; static void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer, static void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer, Loading @@ -96,101 +110,6 @@ BITMAPCONV_INFO::BITMAPCONV_INFO() } } /** * Function ArmBoolEng * Initialise parameters used in kbool * @param aBooleng = pointer to the Bool_Engine to initialise * @param aConvertHoles = mode for holes when a boolean operation is made * true: in resulting polygon, holes are linked into outer contours by double overlapping segments * false: in resulting polygons, holes are not linked: they are separate polygons */ void ArmBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) { // set some global vals to arm the boolean engine // input points are scaled up with GetDGrid() * GetGrid() // DGRID is only meant to make fractional parts of input data which /* * The input data scaled up with DGrid is related to the accuracy the user has in his input data. * User data with a minimum accuracy of 0.001, means set the DGrid to 1000. * The input data may contain data with a minimum accuracy much smaller, but by setting the DGrid * everything smaller than 1/DGrid is rounded. * * DGRID is only meant to make fractional parts of input data which can be * doubles, part of the integers used in vertexes within the boolean algorithm. * And therefore DGRID bigger than 1 is not usefull, you would only loose accuracy. * Within the algorithm all input data is multiplied with DGRID, and the result * is rounded to an integer. */ double DGRID = 1000.0; // round coordinate X or Y value in calculations to this (initial value = 1000.0 in kbool example) // kbool uses DGRID to convert float user units to integer // kbool unit = (int)(user unit * DGRID) // Note: in kicad, coordinates are already integer so DGRID could be set to 1 // we can choose 1.0, // but choose DGRID = 1000.0 solves some filling problems // (perhaps because this allows a better precision in kbool internal calculations double MARGE = 1.0 / DGRID; // snap with in this range points to lines in the intersection routines // should always be >= 1/DGRID a MARGE >= 10/DGRID is ok // this is also used to remove small segments and to decide when // two segments are in line. ( initial value = 0.001 ) // For kicad we choose MARGE = 1/DGRID double CORRECTIONFACTOR = 0.0; // correct the polygons by this number: used in BOOL_CORRECTION operation // this operation shrinks a polygon if CORRECTIONFACTOR < 0 // or stretch it if CORRECTIONFACTOR > 0 // the size change is CORRECTIONFACTOR (holes are correctly handled) double CORRECTIONABER = 1.0; // the accuracy for the rounded shapes used in correction double ROUNDFACTOR = 1.5; // when will we round the correction shape to a circle double SMOOTHABER = 10.0; // accuracy when smoothing a polygon double MAXLINEMERGE = 1000.0; // leave as is, segments of this length in smoothen /* * Grid makes sure that the integer data used within the algorithm has room for extra intersections * smaller than the smallest number within the input data. * The input data scaled up with DGrid is related to the accuracy the user has in his input data. * Another scaling with Grid is applied on top of it to create space in the integer number for * even smaller numbers. */ int GRID = (int) ( 10000 / DGRID ); // initial value = 10000 in kbool example // But we use 10000/DGRID because the scalling is made // by DGRID on integer pcbnew units and // the global scalling ( GRID*DGRID) must be < 30000 to avoid // overflow in calculations (made in long long in kbool) if( GRID <= 1 ) // Cannot be null! GRID = 1; aBooleng->SetMarge( MARGE ); aBooleng->SetGrid( GRID ); aBooleng->SetDGrid( DGRID ); aBooleng->SetCorrectionFactor( CORRECTIONFACTOR ); aBooleng->SetCorrectionAber( CORRECTIONABER ); aBooleng->SetSmoothAber( SMOOTHABER ); aBooleng->SetMaxlinemerge( MAXLINEMERGE ); aBooleng->SetRoundfactor( ROUNDFACTOR ); aBooleng->SetWindingRule( true ); // This is the default kbool value if( aConvertHoles ) { #if 1 // Can be set to 1 for kbool version >= 2.1, must be set to 0 for previous versions // SetAllowNonTopHoleLinking() exists only in kbool >= 2.1 aBooleng->SetAllowNonTopHoleLinking( false ); // Default = , but i have problems (filling errors) when true #endif aBooleng->SetLinkHoles( true ); // holes will be connected by double overlapping segments aBooleng->SetOrientationEntryMode( false ); // all polygons are contours, not holes } else { aBooleng->SetLinkHoles( false ); // holes will not be connected by double overlapping segments aBooleng->SetOrientationEntryMode( true ); // holes are entered counter clockwise } } int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ) int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile, int aFormat ) { { potrace_param_t* param; potrace_param_t* param; Loading Loading @@ -329,25 +248,32 @@ static void OuputEnd( BITMAPCONV_INFO& aInfo ) } } } } /** static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, * Function OuputOnePolygon std::vector <potrace_dpoint_t>& aPolygonBuffer ) * write one polygon to output file. * Polygon coordinates are expected scaled by the polugon extraction function */ static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, KPolygon & aPolygon ) { { unsigned ii; unsigned ii; KPolyPoint currpoint; int offsetX = (int)( aInfo.m_PixmapWidth / 2 * aInfo.m_ScaleX ); int offsetY = (int)( aInfo.m_PixmapHeight / 2 * aInfo.m_ScaleY ); double offsetX = aInfo.m_PixmapWidth / 2 * aInfo.m_ScaleX; KPolyPoint startpoint = *aPolygon.begin(); double offsetY = aInfo.m_PixmapHeight / 2 * aInfo.m_ScaleY; switch( aInfo.m_Format ) switch( aInfo.m_Format ) { { case POSTSCRIPT_FMT: case POSTSCRIPT_FMT: fprintf( aInfo.m_Outfile, "%f %f moveto\n", fprintf( aInfo.m_Outfile, "%d %d moveto\n", aPolygonBuffer[0].x * aInfo.m_ScaleX, startpoint.x(), startpoint.y() ); aPolygonBuffer[0].y * aInfo.m_ScaleY ); for( ii = 1; ii < aPolygon.size(); ii++ ) for( ii = 1; ii < aPolygonBuffer.size(); ii++ ) { fprintf( aInfo.m_Outfile, "%f %f lineto\n", currpoint = *(aPolygon.begin() + ii); aPolygonBuffer[ii].x * aInfo.m_ScaleX, fprintf( aInfo.m_Outfile, "%d %d lineto\n", aPolygonBuffer[ii].y * aInfo.m_ScaleY ); currpoint.x(), currpoint.y() ); } fprintf( aInfo.m_Outfile, "0 setgray fill\n" ); fprintf( aInfo.m_Outfile, "0 setgray fill\n" ); break; break; Loading @@ -359,30 +285,33 @@ static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, int width = 1; int width = 1; fprintf( aInfo.m_Outfile, "DP %d %d %d %d %d %d %d\n", fprintf( aInfo.m_Outfile, "DP %d %d %d %d %d %d %d\n", 0, 0, 0, 0, 0, 0, 0, 0, int(aPolygonBuffer.size()+1), aPolygon.size() + 1, width, layer ); width, layer ); for( ii = 0; ii < aPolygonBuffer.size(); ii++ ) for( ii = 0; ii < aPolygon.size(); ii++ ) { currpoint = *( aPolygon.begin() + ii ); fprintf( aInfo.m_Outfile, "Dl %d %d\n", fprintf( aInfo.m_Outfile, "Dl %d %d\n", (int) ( aPolygonBuffer[ii].x * aInfo.m_ScaleX - offsetX ), currpoint.x() - offsetX, currpoint.y() - offsetY ); (int) ( aPolygonBuffer[ii].y * aInfo.m_ScaleY - offsetY ) ); } // Close polygon // Close polygon fprintf( aInfo.m_Outfile, "Dl %d %d\n", fprintf( aInfo.m_Outfile, "Dl %d %d\n", (int) ( aPolygonBuffer[0].x * aInfo.m_ScaleX - offsetX ), startpoint.x() - offsetX, startpoint.y() - offsetY ); (int) ( aPolygonBuffer[0].y * aInfo.m_ScaleY - offsetY ) ); } } break; break; case EESCHEMA_FMT: case EESCHEMA_FMT: fprintf( aInfo.m_Outfile, "P %d 0 0 1", int(aPolygonBuffer.size()+1) ); fprintf( aInfo.m_Outfile, "P %d 0 0 1", aPolygon.size() + 1 ); for( ii = 0; ii < aPolygonBuffer.size(); ii++ ) for( ii = 0; ii < aPolygon.size(); ii++ ) { currpoint = *(aPolygon.begin() + ii); fprintf( aInfo.m_Outfile, " %d %d", fprintf( aInfo.m_Outfile, " %d %d", (int) ( aPolygonBuffer[ii].x * aInfo.m_ScaleX - offsetX ), currpoint.x() - offsetX, currpoint.y() - offsetY ); (int) ( aPolygonBuffer[ii].y * aInfo.m_ScaleY - offsetY ) ); } // Close polygon // Close polygon fprintf( aInfo.m_Outfile, " %d %d", fprintf( aInfo.m_Outfile, " %d %d", (int) ( aPolygonBuffer[0].x * aInfo.m_ScaleX - offsetX ), startpoint.x() - offsetX, startpoint.y() - offsetY ); (int) ( aPolygonBuffer[0].y * aInfo.m_ScaleY - offsetY ) ); fprintf( aInfo.m_Outfile, " F\n" ); fprintf( aInfo.m_Outfile, " F\n" ); break; break; Loading @@ -392,16 +321,21 @@ static void OuputOnePolygon( BITMAPCONV_INFO& aInfo, static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) { { unsigned int i, n; KPolyPoint currpoint; int* tag; std::vector <potrace_dpoint_t> cornersBuffer; std::vector <potrace_dpoint_t> cornersBuffer; // This KPolygonSet polyset_areas is a complex polygon to draw // and can be complex depending on holes inside this polygon KPolygonSet polyset_areas; // This KPolygonSet polyset_holes is the set of holes inside polyset_areas KPolygonSet polyset_holes; potrace_dpoint_t( *c )[3]; potrace_dpoint_t( *c )[3]; OuputHeader( aInfo ); OuputHeader( aInfo ); bool main_outline = true; bool main_outline = true; Bool_Engine* booleng = NULL; /* draw each as a polygon with no hole. /* draw each as a polygon with no hole. * Bezier curves are approximated by a polyline * Bezier curves are approximated by a polyline Loading @@ -409,17 +343,11 @@ static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) potrace_path_t* paths = aInfo.m_Paths; // the list of paths potrace_path_t* paths = aInfo.m_Paths; // the list of paths while( paths != NULL ) while( paths != NULL ) { { n = paths->curve.n; int cnt = paths->curve.n; tag = paths->curve.tag; int* tag = paths->curve.tag; c = paths->curve.c; c = paths->curve.c; potrace_dpoint_t startpoint = c[n - 1][2]; potrace_dpoint_t startpoint = c[cnt - 1][2]; cornersBuffer.push_back( startpoint ); for( int i = 0; i < cnt; i++ ) if( booleng == NULL ) { booleng = new Bool_Engine(); ArmBoolEng( booleng, true ); } for( i = 0; i < n; i++ ) { { switch( tag[i] ) switch( tag[i] ) { { Loading @@ -440,46 +368,53 @@ static void CreateOutputFile( BITMAPCONV_INFO& aInfo ) if( main_outline ) if( main_outline ) { { main_outline = false; main_outline = false; booleng->StartPolygonAdd( GROUP_A ); for( i = 1; i < cornersBuffer.size(); i++ ) booleng->AddPoint( cornersBuffer[i].x, cornersBuffer[i].y ); booleng->EndPolygonAdd(); // build the current main polygon std::vector<KPolyPoint> cornerslist; // a simple boost polygon for( unsigned int i = 0; i < cornersBuffer.size(); i++ ) { currpoint.x( (coordinate_type) (cornersBuffer[i].x * aInfo.m_ScaleX) ); currpoint.y( (coordinate_type) (cornersBuffer[i].y * aInfo.m_ScaleY) ); cornerslist.push_back( currpoint ); } KPolygon poly; bpl::set_points( poly, cornerslist.begin(), cornerslist.end() ); polyset_areas.push_back( poly ); } } else else { { booleng->StartPolygonAdd( GROUP_B ); // Add current hole in polyset_holes for( i = 1; i < cornersBuffer.size(); i++ ) std::vector<KPolyPoint> cornerslist; // a simple boost polygon booleng->AddPoint( cornersBuffer[i].x, cornersBuffer[i].y ); for( unsigned int i = 0; i < cornersBuffer.size(); i++ ) { currpoint.x( (coordinate_type) (cornersBuffer[i].x * aInfo.m_ScaleX) ); currpoint.y( (coordinate_type) (cornersBuffer[i].y * aInfo.m_ScaleY) ); cornerslist.push_back( currpoint ); } booleng->EndPolygonAdd(); KPolygon poly; bpl::set_points( poly, cornerslist.begin(), cornerslist.end() ); polyset_holes.push_back( poly ); } } cornersBuffer.clear(); cornersBuffer.clear(); /* at the end of a group of a positive path and its negative /* at the end of a group of a positive path and its negative children, fill. * children, fill. */ */ if( paths->next == NULL || paths->next->sign == '+' ) if( paths->next == NULL || paths->next->sign == '+' ) { { booleng->Do_Operation( BOOL_A_SUB_B ); // Substract holes to main polygon: std::vector <potrace_dpoint_t> PolygonBuffer; polyset_areas -= polyset_holes; while( booleng->StartPolygonGet() ) { potrace_dpoint_t corner; PolygonBuffer.clear(); while( booleng->PolygonHasMorePoints() ) { corner.x = booleng->GetPolygonXPoint(); corner.y = booleng->GetPolygonYPoint(); PolygonBuffer.push_back( corner ); } booleng->EndPolygonGet(); // Output current resulting polygon(s) OuputOnePolygon( aInfo, PolygonBuffer ); for( unsigned ii = 0; ii < polyset_areas.size(); ii++ ) PolygonBuffer.clear(); { KPolygon& poly = polyset_areas[ii]; OuputOnePolygon( aInfo, poly ); } } delete booleng; polyset_areas.clear(); booleng = NULL; polyset_holes.clear(); main_outline = true; main_outline = true; } } paths = paths->next; paths = paths->next; Loading @@ -505,7 +440,7 @@ void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer, * between the true curve and its approximation does not exceed the * between the true curve and its approximation does not exceed the * desired accuracy delta. */ * desired accuracy delta. */ delta = 0.5; /* desired accuracy, in pixels */ delta = 0.25; /* desired accuracy, in pixels */ /* let dd = maximal value of 2nd derivative over curve - this must /* let dd = maximal value of 2nd derivative over curve - this must * occur at an endpoint. */ * occur at an endpoint. */ Loading
potrace/potracelib.h +5 −4 Original line number Original line Diff line number Diff line Loading @@ -77,10 +77,11 @@ typedef struct potrace_dpoint_s potrace_dpoint_t; /* closed curve segment */ /* closed curve segment */ struct potrace_curve_s struct potrace_curve_s { { int n; /* number of segments */ int n; // number of segments int* tag; /* tag[n]: POTRACE_CURVETO or POTRACE_CORNER */ int* tag; // tag[n]: POTRACE_CURVETO or POTRACE_CORNER potrace_dpoint_t( * c )[3]; /* c[n][3]: control points. potrace_dpoint_t( * c )[3]; /* c[n][3]: control points. * c[n][0] is unused for tag[n]=POTRACE_CORNER */ * c[n][0] is unused for tag[n]=POTRACE_CORNER */ }; }; typedef struct potrace_curve_s potrace_curve_t; typedef struct potrace_curve_s potrace_curve_t; Loading