Loading CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -542,6 +542,7 @@ add_subdirectory( potrace ) add_subdirectory( bitmap2component ) add_subdirectory( pcb_calculator ) add_subdirectory( tools ) add_subdirectory( utils ) add_subdirectory( qa ) #add_subdirectory( new ) Loading pcbnew/CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ set( PCBNEW_EXPORTERS exporters/export_gencad.cpp exporters/export_idf.cpp exporters/export_vrml.cpp exporters/idf_common.cpp exporters/idf.cpp exporters/gen_drill_report_files.cpp exporters/gen_modules_placefile.cpp Loading pcbnew/exporters/idf.cpp +0 −411 Original line number Diff line number Diff line Loading @@ -47,8 +47,6 @@ #include <idf.h> #include <build_version.h> // differences in angle smaller than MIN_ANG are considered equal #define MIN_ANG (0.01) // minimum drill diameter (nanometers) - 10000 is a 0.01mm drill #define IDF_MIN_DIA ( 10000.0 ) Loading @@ -70,280 +68,6 @@ static bool GetIDFString( const std::string& aLine, std::string& aIDFString, // END: IDF_LIB helper routines bool IDF_POINT::Matches( const IDF_POINT& aPoint, double aRadius ) { double dx = x - aPoint.x; double dy = y - aPoint.y; double d2 = dx * dx + dy * dy; if( d2 <= aRadius * aRadius ) return true; return false; } double IDF_POINT::CalcDistance( const IDF_POINT& aPoint ) const { double dx = aPoint.x - x; double dy = aPoint.y - y; double dist = sqrt( dx * dx + dy * dy ); return dist; } double IDF3::CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ) { return atan2( aEndPoint.y - aStartPoint.y, aEndPoint.x - aStartPoint.x ); } double IDF3::CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ) { double ang = CalcAngleRad( aStartPoint, aEndPoint ); // round to thousandths of a degree int iang = int (ang / M_PI * 1800000.0); ang = iang / 10000.0; return ang; } IDF_SEGMENT::IDF_SEGMENT() { angle = 0.0; offsetAngle = 0.0; radius = 0.0; } IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ) { angle = 0.0; offsetAngle = 0.0; radius = 0.0; startPoint = aStartPoint; endPoint = aEndPoint; } IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint, double aAngle, bool aFromKicad ) { double diff = abs( aAngle ) - 360.0; if( ( diff < MIN_ANG && diff > -MIN_ANG ) || ( aAngle < MIN_ANG && aAngle > -MIN_ANG ) || (!aFromKicad) ) { angle = 0.0; startPoint = aStartPoint; endPoint = aEndPoint; if( diff < MIN_ANG && diff > -MIN_ANG ) { angle = 360.0; center = aStartPoint; offsetAngle = 0.0; radius = aStartPoint.CalcDistance( aEndPoint ); } else if( aAngle < MIN_ANG && aAngle > -MIN_ANG ) { CalcCenterAndRadius(); } return; } // we need to convert from the KiCad arc convention angle = aAngle; center = aStartPoint; offsetAngle = IDF3::CalcAngleDeg( aStartPoint, aEndPoint ); radius = aStartPoint.CalcDistance( aEndPoint ); startPoint = aEndPoint; double ang = offsetAngle + aAngle; ang = (ang / 180.0) * M_PI; endPoint.x = ( radius * cos( ang ) ) + center.x; endPoint.y = ( radius * sin( ang ) ) + center.y; } bool IDF_SEGMENT::MatchesStart( const IDF_POINT& aPoint, double aRadius ) { return startPoint.Matches( aPoint, aRadius ); } bool IDF_SEGMENT::MatchesEnd( const IDF_POINT& aPoint, double aRadius ) { return endPoint.Matches( aPoint, aRadius ); } void IDF_SEGMENT::CalcCenterAndRadius( void ) { // NOTE: this routine does not check if the points are the same // or too close to be sensible in a production setting. double offAng = IDF3::CalcAngleRad( startPoint, endPoint ); double d = startPoint.CalcDistance( endPoint ) / 2.0; double xm = ( startPoint.x + endPoint.x ) * 0.5; double ym = ( startPoint.y + endPoint.y ) * 0.5; radius = d / sin( angle * M_PI / 180.0 ); if( radius < 0.0 ) { radius = -radius; } // calculate the height of the triangle with base d and hypotenuse r double dh2 = radius * radius - d * d; if( dh2 < 0 ) { // this should only ever happen due to rounding errors when r == d dh2 = 0; } double h = sqrt( dh2 ); if( angle > 0.0 ) offAng += M_PI2; else offAng -= M_PI2; if( ( angle > M_PI ) || ( angle < -M_PI ) ) offAng += M_PI; center.x = h * cos( offAng ) + xm; center.y = h * sin( offAng ) + ym; offsetAngle = IDF3::CalcAngleDeg( center, startPoint ); } bool IDF_SEGMENT::IsCircle( void ) { double diff = abs( angle ) - 360.0; if( ( diff < MIN_ANG ) && ( diff > -MIN_ANG ) ) return true; return false; } double IDF_SEGMENT::GetMinX( void ) { if( angle == 0.0 ) return std::min( startPoint.x, endPoint.x ); // Calculate the leftmost point of the circle or arc if( IsCircle() ) { // if only everything were this easy return center.x - radius; } // cases: // 1. CCW arc: if offset + included angle >= 180 deg then // MinX = center.x - radius, otherwise MinX is the // same as for the case of a line. // 2. CW arc: if offset + included angle <= -180 deg then // MinX = center.x - radius, otherwise MinX is the // same as for the case of a line. if( angle > 0 ) { // CCW case if( ( offsetAngle + angle ) >= 180.0 ) { return center.x - radius; } else { return std::min( startPoint.x, endPoint.x ); } } // CW case if( ( offsetAngle + angle ) <= -180.0 ) { return center.x - radius; } return std::min( startPoint.x, endPoint.x ); } void IDF_SEGMENT::SwapEnds( void ) { if( IsCircle() ) { // reverse the direction angle = -angle; return; } IDF_POINT tmp = startPoint; startPoint = endPoint; endPoint = tmp; if( ( angle < MIN_ANG ) && ( angle > -MIN_ANG ) ) return; // nothing more to do // change the direction of the arc angle = -angle; // calculate the new offset angle offsetAngle = IDF3::CalcAngleDeg( center, startPoint ); } void IDF_OUTLINE::push( IDF_SEGMENT* item ) { if( !outline.empty() ) { if( item->IsCircle() ) { // not allowed wxString msg = wxT( "INVALID GEOMETRY: a circle is being added to a non-empty outline" ); THROW_IO_ERROR( msg ); } else { if( outline.back()->IsCircle() ) { // we can't add lines to a circle wxString msg = wxT( "INVALID GEOMETRY: a line is being added to a circular outline" ); THROW_IO_ERROR( msg ); } else if( !item->MatchesStart( outline.back()->endPoint ) ) { // startPoint[N] != endPoint[N -1] wxString msg = wxT( "INVALID GEOMETRY: disjoint segments" ); THROW_IO_ERROR( msg ); } } } outline.push_back( item ); dir += ( outline.back()->endPoint.x - outline.back()->startPoint.x ) * ( outline.back()->endPoint.y + outline.back()->startPoint.y ); } IDF_DRILL_DATA::IDF_DRILL_DATA( double aDrillDia, double aPosX, double aPosY, IDF3::KEY_PLATING aPlating, Loading Loading @@ -881,141 +605,6 @@ void IDF_BOARD::GetOffset( double& x, double& y ) } void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines, IDF_OUTLINE& aOutline ) { aOutline.Clear(); // NOTE: To tell if the point order is CCW or CW, // sum all: (endPoint.X[n] - startPoint.X[n])*(endPoint[n] + startPoint.Y[n]) // If the result is >0, the direction is CW, otherwise // it is CCW. Note that the result cannot be 0 unless // we have a bounded area of 0. // First we find the segment with the leftmost point std::list<IDF_SEGMENT*>::iterator bl = aLines.begin(); std::list<IDF_SEGMENT*>::iterator el = aLines.end(); std::list<IDF_SEGMENT*>::iterator idx = bl++; // iterator for the object with minX double minx = (*idx)->GetMinX(); double curx; while( bl != el ) { curx = (*bl)->GetMinX(); if( curx < minx ) { minx = curx; idx = bl; } ++bl; } aOutline.push( *idx ); aLines.erase( idx ); // If the item is a circle then we're done if( aOutline.front()->IsCircle() ) return; // Assemble the loop bool complete = false; // set if loop is complete bool matched; // set if a segment's end point was matched while( !complete ) { matched = false; bl = aLines.begin(); el = aLines.end(); while( bl != el && !matched ) { if( (*bl)->MatchesStart( aOutline.back()->endPoint ) ) { if( (*bl)->IsCircle() ) { // a circle on the perimeter is pathological but we just ignore it ++bl; } else { matched = true; aOutline.push( *bl ); aLines.erase( bl ); } continue; } ++bl; } if( !matched ) { // attempt to match the end points bl = aLines.begin(); el = aLines.end(); while( bl != el && !matched ) { if( (*bl)->MatchesEnd( aOutline.back()->endPoint ) ) { if( (*bl)->IsCircle() ) { // a circle on the perimeter is pathological but we just ignore it ++bl; } else { matched = true; (*bl)->SwapEnds(); aOutline.push( *bl ); aLines.erase( bl ); } continue; } ++bl; } } if( !matched ) { // still no match - attempt to close the loop if( (aOutline.size() > 1) || ( aOutline.front()->angle < -MIN_ANG ) || ( aOutline.front()->angle > MIN_ANG ) ) { // close the loop IDF_SEGMENT* seg = new IDF_SEGMENT( aOutline.back()->endPoint, aOutline.front()->startPoint ); if( seg ) { complete = true; aOutline.push( seg ); break; } } // the outline is bad; drop the segments aOutline.Clear(); return; } // check if the loop is complete if( aOutline.front()->MatchesStart( aOutline.back()->endPoint ) ) { complete = true; break; } } } IDF_LIB::~IDF_LIB() { while( !components.empty() ) Loading pcbnew/exporters/idf.h +1 −263 Original line number Diff line number Diff line Loading @@ -31,269 +31,7 @@ #include <wx/string.h> #include <set> #include <string> #ifndef M_PI #define M_PI 3.1415926535897932384626433832795028841 #endif #ifndef M_PI2 #define M_PI2 ( M_PI / 2.0 ) #endif #ifndef M_PI4 #define M_PI4 ( M_PI / 4.0 ) #endif class IDF_POINT; class IDF_SEGMENT; class IDF_DRILL_DATA; class IDF_OUTLINE; class IDF_LIB; namespace IDF3 { enum KEY_OWNER { UNOWNED = 0, // < either MCAD or ECAD may modify a feature MCAD, // < only MCAD may modify a feature ECAD // < only ECAD may modify a feature }; enum KEY_HOLETYPE { PIN = 0, // < drill hole is for a pin VIA, // < drill hole is for a via MTG, // < drill hole is for mounting TOOL, // < drill hole is for tooling OTHER // < user has specified a custom type }; enum KEY_PLATING { PTH = 0, // < Plate-Through Hole NPTH // < Non-Plate-Through Hole }; enum KEY_REFDES { BOARD = 0, // < feature is associated with the board NOREFDES, // < feature is associated with a component with no RefDes PANEL, // < feature is associated with an IDF panel REFDES // < reference designator as assigned by the CAD software }; // calculate the angle between the horizon and the segment aStartPoint to aEndPoint double CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ); double CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ); // take contiguous elements from 'lines' and stuff them into 'outline' void GetOutline( std::list<IDF_SEGMENT*>& aLines, IDF_OUTLINE& aOutline ); } /** * @Struct IDF_POINT * represents a vector of three doubles; this may be represent * a point in space, or scaling, translation or rotation along * three axes. */ struct IDF_VECTOR { double x; double y; double z; }; /** * @Class IDF_POINT * represents a point */ class IDF_POINT { public: double x; // < X coordinate double y; // < Y coordinate IDF_POINT() { x = 0.0; y = 0.0; } /** * Function Matches() * returns true if the given coordinate point is within the given radius * of the point. * @param aPoint : coordinates of the point being compared * @param aRadius : radius within which the points are considered the same */ bool Matches( const IDF_POINT& aPoint, double aRadius = 1e-5 ); double CalcDistance( const IDF_POINT& aPoint ) const; }; /** * @Class IDF_SEGMENT * represents a geometry segment as used in IDFv3 outlines */ class IDF_SEGMENT { private: /** * Function CalcCenterAndRadius() * Calculates the center, radius, and angle between center and start point given the * IDF compliant points and included angle. * @var startPoint, @var endPoint, and @var angle must be set prior as per IDFv3 */ void CalcCenterAndRadius( void ); public: IDF_POINT startPoint; // starting point in IDF coordinates IDF_POINT endPoint; // end point in IDF coordinates IDF_POINT center; // center of an arc or circle; used primarily for calculating min X double angle; // included angle (degrees) according to IDFv3 specification double offsetAngle; // angle between center and start of arc; used to speed up some calcs. double radius; // radius of the arc or circle; used to speed up some calcs. /** * Function IDF_SEGMENT() * initializes the internal variables */ IDF_SEGMENT(); /** * Function IDF_SEGMENT( start, end ) * creates a straight segment */ IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ); /** * Function IDF_SEGMENT( start, end ) * creates a straight segment, arc, or circle depending on the angle * @param aStartPoint : start point (center if using KiCad convention, otherwise IDF convention) * @param aEndPoint : end point (start of arc if using KiCad convention, otherwise IDF convention) * @param aAngle : included angle; the KiCad convention is equivalent to the IDF convention * @param fromKicad : set true if we need to convert from KiCad to IDF convention */ IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint, double aAngle, bool aFromKicad ); /** * Function MatchesStart() * returns true if the given coordinate is within a radius 'rad' * of the start point. * @param aPoint : coordinates of the point being compared * @param aRadius : radius within which the points are considered the same */ bool MatchesStart( const IDF_POINT& aPoint, double aRadius = 1e-3 ); /** * Function MatchesEnd() * returns true if the given coordinate is within a radius 'rad' * of the end point. * @param aPoint : coordinates of the point being compared * @param aRadius : radius within which the points are considered the same */ bool MatchesEnd( const IDF_POINT& aPoint, double aRadius = 1e-3 ); /** * Function IsCircle() * returns true if this segment is a circle */ bool IsCircle( void ); /** * Function GetMinX() * returns the minimum X coordinate of this segment */ double GetMinX( void ); /** * Function SwapEnds() * Swaps the start and end points and alters internal * variables as necessary for arcs */ void SwapEnds( void ); }; /** * @Class IDF_OUTLINE * contains segment and winding information for an IDF outline */ class IDF_OUTLINE { private: double dir; std::list<IDF_SEGMENT*> outline; public: IDF_OUTLINE() { dir = 0.0; } ~IDF_OUTLINE() { Clear(); } // returns true if the current list of points represents a counterclockwise winding bool IsCCW( void ) { if( dir > 0.0 ) return false; return true; } // clears the internal list of outline segments void Clear( void ) { dir = 0.0; while( !outline.empty() ) { delete outline.front(); outline.pop_front(); } } // returns the size of the internal segment list size_t size( void ) { return outline.size(); } // returns true if the internal segment list is empty bool empty( void ) { return outline.empty(); } // return the front() of the internal segment list IDF_SEGMENT*& front( void ) { return outline.front(); } // return the back() of the internal segment list IDF_SEGMENT*& back( void ) { return outline.back(); } // return the begin() iterator of the internal segment list std::list<IDF_SEGMENT*>::iterator begin( void ) { return outline.begin(); } // return the end() iterator of the internal segment list std::list<IDF_SEGMENT*>::iterator end( void ) { return outline.end(); } // push a segment onto the internal list void push( IDF_SEGMENT* item ); }; #include <idf_common.h> /** Loading Loading
CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -542,6 +542,7 @@ add_subdirectory( potrace ) add_subdirectory( bitmap2component ) add_subdirectory( pcb_calculator ) add_subdirectory( tools ) add_subdirectory( utils ) add_subdirectory( qa ) #add_subdirectory( new ) Loading
pcbnew/CMakeLists.txt +1 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ set( PCBNEW_EXPORTERS exporters/export_gencad.cpp exporters/export_idf.cpp exporters/export_vrml.cpp exporters/idf_common.cpp exporters/idf.cpp exporters/gen_drill_report_files.cpp exporters/gen_modules_placefile.cpp Loading
pcbnew/exporters/idf.cpp +0 −411 Original line number Diff line number Diff line Loading @@ -47,8 +47,6 @@ #include <idf.h> #include <build_version.h> // differences in angle smaller than MIN_ANG are considered equal #define MIN_ANG (0.01) // minimum drill diameter (nanometers) - 10000 is a 0.01mm drill #define IDF_MIN_DIA ( 10000.0 ) Loading @@ -70,280 +68,6 @@ static bool GetIDFString( const std::string& aLine, std::string& aIDFString, // END: IDF_LIB helper routines bool IDF_POINT::Matches( const IDF_POINT& aPoint, double aRadius ) { double dx = x - aPoint.x; double dy = y - aPoint.y; double d2 = dx * dx + dy * dy; if( d2 <= aRadius * aRadius ) return true; return false; } double IDF_POINT::CalcDistance( const IDF_POINT& aPoint ) const { double dx = aPoint.x - x; double dy = aPoint.y - y; double dist = sqrt( dx * dx + dy * dy ); return dist; } double IDF3::CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ) { return atan2( aEndPoint.y - aStartPoint.y, aEndPoint.x - aStartPoint.x ); } double IDF3::CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ) { double ang = CalcAngleRad( aStartPoint, aEndPoint ); // round to thousandths of a degree int iang = int (ang / M_PI * 1800000.0); ang = iang / 10000.0; return ang; } IDF_SEGMENT::IDF_SEGMENT() { angle = 0.0; offsetAngle = 0.0; radius = 0.0; } IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ) { angle = 0.0; offsetAngle = 0.0; radius = 0.0; startPoint = aStartPoint; endPoint = aEndPoint; } IDF_SEGMENT::IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint, double aAngle, bool aFromKicad ) { double diff = abs( aAngle ) - 360.0; if( ( diff < MIN_ANG && diff > -MIN_ANG ) || ( aAngle < MIN_ANG && aAngle > -MIN_ANG ) || (!aFromKicad) ) { angle = 0.0; startPoint = aStartPoint; endPoint = aEndPoint; if( diff < MIN_ANG && diff > -MIN_ANG ) { angle = 360.0; center = aStartPoint; offsetAngle = 0.0; radius = aStartPoint.CalcDistance( aEndPoint ); } else if( aAngle < MIN_ANG && aAngle > -MIN_ANG ) { CalcCenterAndRadius(); } return; } // we need to convert from the KiCad arc convention angle = aAngle; center = aStartPoint; offsetAngle = IDF3::CalcAngleDeg( aStartPoint, aEndPoint ); radius = aStartPoint.CalcDistance( aEndPoint ); startPoint = aEndPoint; double ang = offsetAngle + aAngle; ang = (ang / 180.0) * M_PI; endPoint.x = ( radius * cos( ang ) ) + center.x; endPoint.y = ( radius * sin( ang ) ) + center.y; } bool IDF_SEGMENT::MatchesStart( const IDF_POINT& aPoint, double aRadius ) { return startPoint.Matches( aPoint, aRadius ); } bool IDF_SEGMENT::MatchesEnd( const IDF_POINT& aPoint, double aRadius ) { return endPoint.Matches( aPoint, aRadius ); } void IDF_SEGMENT::CalcCenterAndRadius( void ) { // NOTE: this routine does not check if the points are the same // or too close to be sensible in a production setting. double offAng = IDF3::CalcAngleRad( startPoint, endPoint ); double d = startPoint.CalcDistance( endPoint ) / 2.0; double xm = ( startPoint.x + endPoint.x ) * 0.5; double ym = ( startPoint.y + endPoint.y ) * 0.5; radius = d / sin( angle * M_PI / 180.0 ); if( radius < 0.0 ) { radius = -radius; } // calculate the height of the triangle with base d and hypotenuse r double dh2 = radius * radius - d * d; if( dh2 < 0 ) { // this should only ever happen due to rounding errors when r == d dh2 = 0; } double h = sqrt( dh2 ); if( angle > 0.0 ) offAng += M_PI2; else offAng -= M_PI2; if( ( angle > M_PI ) || ( angle < -M_PI ) ) offAng += M_PI; center.x = h * cos( offAng ) + xm; center.y = h * sin( offAng ) + ym; offsetAngle = IDF3::CalcAngleDeg( center, startPoint ); } bool IDF_SEGMENT::IsCircle( void ) { double diff = abs( angle ) - 360.0; if( ( diff < MIN_ANG ) && ( diff > -MIN_ANG ) ) return true; return false; } double IDF_SEGMENT::GetMinX( void ) { if( angle == 0.0 ) return std::min( startPoint.x, endPoint.x ); // Calculate the leftmost point of the circle or arc if( IsCircle() ) { // if only everything were this easy return center.x - radius; } // cases: // 1. CCW arc: if offset + included angle >= 180 deg then // MinX = center.x - radius, otherwise MinX is the // same as for the case of a line. // 2. CW arc: if offset + included angle <= -180 deg then // MinX = center.x - radius, otherwise MinX is the // same as for the case of a line. if( angle > 0 ) { // CCW case if( ( offsetAngle + angle ) >= 180.0 ) { return center.x - radius; } else { return std::min( startPoint.x, endPoint.x ); } } // CW case if( ( offsetAngle + angle ) <= -180.0 ) { return center.x - radius; } return std::min( startPoint.x, endPoint.x ); } void IDF_SEGMENT::SwapEnds( void ) { if( IsCircle() ) { // reverse the direction angle = -angle; return; } IDF_POINT tmp = startPoint; startPoint = endPoint; endPoint = tmp; if( ( angle < MIN_ANG ) && ( angle > -MIN_ANG ) ) return; // nothing more to do // change the direction of the arc angle = -angle; // calculate the new offset angle offsetAngle = IDF3::CalcAngleDeg( center, startPoint ); } void IDF_OUTLINE::push( IDF_SEGMENT* item ) { if( !outline.empty() ) { if( item->IsCircle() ) { // not allowed wxString msg = wxT( "INVALID GEOMETRY: a circle is being added to a non-empty outline" ); THROW_IO_ERROR( msg ); } else { if( outline.back()->IsCircle() ) { // we can't add lines to a circle wxString msg = wxT( "INVALID GEOMETRY: a line is being added to a circular outline" ); THROW_IO_ERROR( msg ); } else if( !item->MatchesStart( outline.back()->endPoint ) ) { // startPoint[N] != endPoint[N -1] wxString msg = wxT( "INVALID GEOMETRY: disjoint segments" ); THROW_IO_ERROR( msg ); } } } outline.push_back( item ); dir += ( outline.back()->endPoint.x - outline.back()->startPoint.x ) * ( outline.back()->endPoint.y + outline.back()->startPoint.y ); } IDF_DRILL_DATA::IDF_DRILL_DATA( double aDrillDia, double aPosX, double aPosY, IDF3::KEY_PLATING aPlating, Loading Loading @@ -881,141 +605,6 @@ void IDF_BOARD::GetOffset( double& x, double& y ) } void IDF3::GetOutline( std::list<IDF_SEGMENT*>& aLines, IDF_OUTLINE& aOutline ) { aOutline.Clear(); // NOTE: To tell if the point order is CCW or CW, // sum all: (endPoint.X[n] - startPoint.X[n])*(endPoint[n] + startPoint.Y[n]) // If the result is >0, the direction is CW, otherwise // it is CCW. Note that the result cannot be 0 unless // we have a bounded area of 0. // First we find the segment with the leftmost point std::list<IDF_SEGMENT*>::iterator bl = aLines.begin(); std::list<IDF_SEGMENT*>::iterator el = aLines.end(); std::list<IDF_SEGMENT*>::iterator idx = bl++; // iterator for the object with minX double minx = (*idx)->GetMinX(); double curx; while( bl != el ) { curx = (*bl)->GetMinX(); if( curx < minx ) { minx = curx; idx = bl; } ++bl; } aOutline.push( *idx ); aLines.erase( idx ); // If the item is a circle then we're done if( aOutline.front()->IsCircle() ) return; // Assemble the loop bool complete = false; // set if loop is complete bool matched; // set if a segment's end point was matched while( !complete ) { matched = false; bl = aLines.begin(); el = aLines.end(); while( bl != el && !matched ) { if( (*bl)->MatchesStart( aOutline.back()->endPoint ) ) { if( (*bl)->IsCircle() ) { // a circle on the perimeter is pathological but we just ignore it ++bl; } else { matched = true; aOutline.push( *bl ); aLines.erase( bl ); } continue; } ++bl; } if( !matched ) { // attempt to match the end points bl = aLines.begin(); el = aLines.end(); while( bl != el && !matched ) { if( (*bl)->MatchesEnd( aOutline.back()->endPoint ) ) { if( (*bl)->IsCircle() ) { // a circle on the perimeter is pathological but we just ignore it ++bl; } else { matched = true; (*bl)->SwapEnds(); aOutline.push( *bl ); aLines.erase( bl ); } continue; } ++bl; } } if( !matched ) { // still no match - attempt to close the loop if( (aOutline.size() > 1) || ( aOutline.front()->angle < -MIN_ANG ) || ( aOutline.front()->angle > MIN_ANG ) ) { // close the loop IDF_SEGMENT* seg = new IDF_SEGMENT( aOutline.back()->endPoint, aOutline.front()->startPoint ); if( seg ) { complete = true; aOutline.push( seg ); break; } } // the outline is bad; drop the segments aOutline.Clear(); return; } // check if the loop is complete if( aOutline.front()->MatchesStart( aOutline.back()->endPoint ) ) { complete = true; break; } } } IDF_LIB::~IDF_LIB() { while( !components.empty() ) Loading
pcbnew/exporters/idf.h +1 −263 Original line number Diff line number Diff line Loading @@ -31,269 +31,7 @@ #include <wx/string.h> #include <set> #include <string> #ifndef M_PI #define M_PI 3.1415926535897932384626433832795028841 #endif #ifndef M_PI2 #define M_PI2 ( M_PI / 2.0 ) #endif #ifndef M_PI4 #define M_PI4 ( M_PI / 4.0 ) #endif class IDF_POINT; class IDF_SEGMENT; class IDF_DRILL_DATA; class IDF_OUTLINE; class IDF_LIB; namespace IDF3 { enum KEY_OWNER { UNOWNED = 0, // < either MCAD or ECAD may modify a feature MCAD, // < only MCAD may modify a feature ECAD // < only ECAD may modify a feature }; enum KEY_HOLETYPE { PIN = 0, // < drill hole is for a pin VIA, // < drill hole is for a via MTG, // < drill hole is for mounting TOOL, // < drill hole is for tooling OTHER // < user has specified a custom type }; enum KEY_PLATING { PTH = 0, // < Plate-Through Hole NPTH // < Non-Plate-Through Hole }; enum KEY_REFDES { BOARD = 0, // < feature is associated with the board NOREFDES, // < feature is associated with a component with no RefDes PANEL, // < feature is associated with an IDF panel REFDES // < reference designator as assigned by the CAD software }; // calculate the angle between the horizon and the segment aStartPoint to aEndPoint double CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ); double CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ); // take contiguous elements from 'lines' and stuff them into 'outline' void GetOutline( std::list<IDF_SEGMENT*>& aLines, IDF_OUTLINE& aOutline ); } /** * @Struct IDF_POINT * represents a vector of three doubles; this may be represent * a point in space, or scaling, translation or rotation along * three axes. */ struct IDF_VECTOR { double x; double y; double z; }; /** * @Class IDF_POINT * represents a point */ class IDF_POINT { public: double x; // < X coordinate double y; // < Y coordinate IDF_POINT() { x = 0.0; y = 0.0; } /** * Function Matches() * returns true if the given coordinate point is within the given radius * of the point. * @param aPoint : coordinates of the point being compared * @param aRadius : radius within which the points are considered the same */ bool Matches( const IDF_POINT& aPoint, double aRadius = 1e-5 ); double CalcDistance( const IDF_POINT& aPoint ) const; }; /** * @Class IDF_SEGMENT * represents a geometry segment as used in IDFv3 outlines */ class IDF_SEGMENT { private: /** * Function CalcCenterAndRadius() * Calculates the center, radius, and angle between center and start point given the * IDF compliant points and included angle. * @var startPoint, @var endPoint, and @var angle must be set prior as per IDFv3 */ void CalcCenterAndRadius( void ); public: IDF_POINT startPoint; // starting point in IDF coordinates IDF_POINT endPoint; // end point in IDF coordinates IDF_POINT center; // center of an arc or circle; used primarily for calculating min X double angle; // included angle (degrees) according to IDFv3 specification double offsetAngle; // angle between center and start of arc; used to speed up some calcs. double radius; // radius of the arc or circle; used to speed up some calcs. /** * Function IDF_SEGMENT() * initializes the internal variables */ IDF_SEGMENT(); /** * Function IDF_SEGMENT( start, end ) * creates a straight segment */ IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint ); /** * Function IDF_SEGMENT( start, end ) * creates a straight segment, arc, or circle depending on the angle * @param aStartPoint : start point (center if using KiCad convention, otherwise IDF convention) * @param aEndPoint : end point (start of arc if using KiCad convention, otherwise IDF convention) * @param aAngle : included angle; the KiCad convention is equivalent to the IDF convention * @param fromKicad : set true if we need to convert from KiCad to IDF convention */ IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint, double aAngle, bool aFromKicad ); /** * Function MatchesStart() * returns true if the given coordinate is within a radius 'rad' * of the start point. * @param aPoint : coordinates of the point being compared * @param aRadius : radius within which the points are considered the same */ bool MatchesStart( const IDF_POINT& aPoint, double aRadius = 1e-3 ); /** * Function MatchesEnd() * returns true if the given coordinate is within a radius 'rad' * of the end point. * @param aPoint : coordinates of the point being compared * @param aRadius : radius within which the points are considered the same */ bool MatchesEnd( const IDF_POINT& aPoint, double aRadius = 1e-3 ); /** * Function IsCircle() * returns true if this segment is a circle */ bool IsCircle( void ); /** * Function GetMinX() * returns the minimum X coordinate of this segment */ double GetMinX( void ); /** * Function SwapEnds() * Swaps the start and end points and alters internal * variables as necessary for arcs */ void SwapEnds( void ); }; /** * @Class IDF_OUTLINE * contains segment and winding information for an IDF outline */ class IDF_OUTLINE { private: double dir; std::list<IDF_SEGMENT*> outline; public: IDF_OUTLINE() { dir = 0.0; } ~IDF_OUTLINE() { Clear(); } // returns true if the current list of points represents a counterclockwise winding bool IsCCW( void ) { if( dir > 0.0 ) return false; return true; } // clears the internal list of outline segments void Clear( void ) { dir = 0.0; while( !outline.empty() ) { delete outline.front(); outline.pop_front(); } } // returns the size of the internal segment list size_t size( void ) { return outline.size(); } // returns true if the internal segment list is empty bool empty( void ) { return outline.empty(); } // return the front() of the internal segment list IDF_SEGMENT*& front( void ) { return outline.front(); } // return the back() of the internal segment list IDF_SEGMENT*& back( void ) { return outline.back(); } // return the begin() iterator of the internal segment list std::list<IDF_SEGMENT*>::iterator begin( void ) { return outline.begin(); } // return the end() iterator of the internal segment list std::list<IDF_SEGMENT*>::iterator end( void ) { return outline.end(); } // push a segment onto the internal list void push( IDF_SEGMENT* item ); }; #include <idf_common.h> /** Loading