mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
Recommendation is to avoid using the year nomenclature as this information is already encoded in the git repo. Avoids needing to repeatly update. Also updates AUTHORS.txt from current repo with contributor names
649 lines
18 KiB
C++
649 lines
18 KiB
C++
/**
|
|
* @file idf_common.h
|
|
*/
|
|
|
|
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2013-2017 Cirilo Bernardo
|
|
* Copyright The 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
|
|
*/
|
|
|
|
#ifndef IDF_COMMON_H
|
|
#define IDF_COMMON_H
|
|
|
|
#include <list>
|
|
#include <fstream>
|
|
#include <exception>
|
|
#include <string>
|
|
#include <cmath>
|
|
|
|
// differences in angle smaller than MIN_ANG are considered equal
|
|
#define MIN_ANG (0.01)
|
|
|
|
class IDF_POINT;
|
|
class IDF_SEGMENT;
|
|
class IDF_DRILL_DATA;
|
|
class IDF_OUTLINE;
|
|
class IDF_LIB;
|
|
|
|
|
|
struct IDF_ERROR : std::exception
|
|
{
|
|
std::string message;
|
|
|
|
IDF_ERROR( const char* aSourceFile, const char* aSourceMethod, int aSourceLine,
|
|
const std::string& aMessage ) noexcept;
|
|
|
|
virtual ~IDF_ERROR() noexcept;
|
|
|
|
virtual const char* what() const noexcept override;
|
|
};
|
|
|
|
|
|
namespace IDF3 {
|
|
|
|
/**
|
|
* State values for the IDF parser's input.
|
|
*/
|
|
enum FILE_STATE
|
|
{
|
|
FILE_START = 0, // no data has been read; expecting .HEADER
|
|
FILE_HEADER, // header has been read; expecting .BOARD_OUTLINE
|
|
FILE_OUTLINE, // board outline has been read; most sections can be accepted
|
|
FILE_PLACEMENT, // placement has been read; no further sections can be accepted
|
|
FILE_INVALID, // file is invalid
|
|
FILE_ERROR // other errors while processing the file
|
|
};
|
|
|
|
/**
|
|
* The supported IDF versions (3.0 and 2.0 ONLY).
|
|
*/
|
|
enum IDF_VERSION
|
|
{
|
|
IDF_V2 = 0, // version 2 has read support only; files written as IDFv3
|
|
IDF_V3 // version 3 has full read/write support
|
|
};
|
|
|
|
/**
|
|
* The type of CAD which has ownership an object.
|
|
*/
|
|
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
|
|
};
|
|
|
|
/**
|
|
* The purpose of an IDF hole.
|
|
*/
|
|
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
|
|
};
|
|
|
|
/**
|
|
* The plating condition of a hole.
|
|
*/
|
|
enum KEY_PLATING
|
|
{
|
|
PTH = 0, //< Plate-Through Hole
|
|
NPTH //< Non-Plate-Through Hole
|
|
};
|
|
|
|
/**
|
|
* A component's Reference Designator.
|
|
*/
|
|
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
|
|
};
|
|
|
|
/**
|
|
* The class of CAD program which is opening or modifying a file.
|
|
*/
|
|
enum CAD_TYPE
|
|
{
|
|
CAD_ELEC = 0, //< An Electrical CAD is opening/modifying the file
|
|
CAD_MECH, //< A Mechanical CAD is opening/modifying the file
|
|
CAD_INVALID
|
|
};
|
|
|
|
/**
|
|
* The various IDF layer classes and groupings.
|
|
*/
|
|
enum IDF_LAYER
|
|
{
|
|
LYR_TOP = 0,
|
|
LYR_BOTTOM,
|
|
LYR_BOTH,
|
|
LYR_INNER,
|
|
LYR_ALL,
|
|
LYR_INVALID
|
|
};
|
|
|
|
/**
|
|
* The class of outline.
|
|
*/
|
|
enum OUTLINE_TYPE
|
|
{
|
|
OTLN_BOARD = 0,
|
|
OTLN_OTHER,
|
|
OTLN_PLACE,
|
|
OTLN_ROUTE,
|
|
OTLN_PLACE_KEEPOUT,
|
|
OTLN_ROUTE_KEEPOUT,
|
|
OTLN_VIA_KEEPOUT,
|
|
OTLN_GROUP_PLACE,
|
|
OTLN_COMPONENT,
|
|
OTLN_INVALID
|
|
};
|
|
|
|
/**
|
|
* Whether a component is a mechanical or electrical part.
|
|
*/
|
|
enum COMP_TYPE
|
|
{
|
|
COMP_ELEC = 0, //< Component library object is an electrical part
|
|
COMP_MECH, //< Component library object is a mechanical part
|
|
COMP_INVALID
|
|
};
|
|
|
|
/**
|
|
* The native unit of the board and of component outlines.
|
|
*/
|
|
enum IDF_UNIT
|
|
{
|
|
UNIT_MM = 0, //< Units in the file are in millimeters
|
|
UNIT_THOU, //< Units in the file are in mils (aka thou)
|
|
UNIT_TNM, //< Deprecated Ten Nanometer Units from IDFv2
|
|
UNIT_INVALID
|
|
};
|
|
|
|
/**
|
|
* The placement status of a component.
|
|
*/
|
|
enum IDF_PLACEMENT
|
|
{
|
|
PS_UNPLACED = 0, //< component location on the board has not been specified
|
|
PS_PLACED, //< component location has been specified and may be modified by ECAD or MCAD
|
|
PS_MCAD, //< component location has been specified and may only be modified by MCAD
|
|
PS_ECAD, //< component location has been specified and may only be modified by ECAD
|
|
PS_INVALID
|
|
};
|
|
|
|
/**
|
|
* Calculate the angle (radians) between the horizon and the segment aStartPoint to aEndPoint.
|
|
*
|
|
* @param aStartPoint is the start point of a line segment.
|
|
* @param aEndPoint is the end point of a line segment.
|
|
* @return the angle in radians.
|
|
*/
|
|
double CalcAngleRad( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
|
|
|
|
/**
|
|
* Calculate the angle (degrees) between the horizon and the segment aStartPoint to aEndPoint.
|
|
*
|
|
* @param aStartPoint is the start point of a line segment.
|
|
* @param aEndPoint is the end point of a line segment.
|
|
* @return the angle in degrees.
|
|
*/
|
|
double CalcAngleDeg( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
|
|
|
|
/**
|
|
* Take contiguous elements from 'aLines' and stuffs them into 'aOutline'; elements put
|
|
* into the outline are deleted from aLines.
|
|
*
|
|
* This function is useful for sorting the jumbled mess of line segments and arcs which represent
|
|
* a board outline and cutouts in KiCad. The function will determine which segment element within
|
|
* aLines contains the leftmost point and retrieve the outline of which that segment is part.
|
|
*
|
|
* @param aLines (input/output) is a list of IDF segments which comprise an outline and cutouts.
|
|
* @param aOutline (output) is the ordered set of segments/
|
|
*/
|
|
void GetOutline( std::list<IDF_SEGMENT*>& aLines, IDF_OUTLINE& aOutline );
|
|
|
|
#ifdef DEBUG_IDF
|
|
// prints out segment information for debug purposes
|
|
void PrintSeg( IDF_SEGMENT* aSegment );
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* An entry in the NOTE section of an IDF file.
|
|
*/
|
|
class IDF_NOTE
|
|
{
|
|
public:
|
|
IDF_NOTE();
|
|
|
|
/**
|
|
* Set the text to be stored as a NOTE entry.
|
|
*/
|
|
void SetText( const std::string& aText );
|
|
|
|
/**
|
|
* Set the position (mm) of the NOTE entry.
|
|
*/
|
|
void SetPosition( double aXpos, double aYpos );
|
|
|
|
/**
|
|
* Set the height and length (mm) of the NOTE entry.
|
|
*/
|
|
void SetSize( double aHeight, double aLength );
|
|
|
|
/**
|
|
* @return the string stored in the note entry.
|
|
*/
|
|
const std::string& GetText();
|
|
|
|
/**
|
|
* @return the position (mm) of the note entry.
|
|
*/
|
|
void GetPosition( double& aXpos, double& aYpos );
|
|
|
|
/**
|
|
* @return the height and length (mm) of the note entry.
|
|
*/
|
|
void GetSize( double& aHeight, double& aLength );
|
|
|
|
private:
|
|
friend class IDF3_BOARD;
|
|
|
|
/**
|
|
* Read a note entry from an IDFv3 file.
|
|
*
|
|
* @param aBoardFile is an open BOARD file; the file position must be set to the start of
|
|
* a NOTE entry.
|
|
* @param aBoardState is the parser's current state value.
|
|
* @param aBoardUnit is the BOARD file's native units (MM or THOU).
|
|
* @return true if a note item was read, false otherwise.
|
|
* @throw In case of unrecoverable errors.
|
|
*/
|
|
bool readNote( std::istream& aBoardFile, IDF3::FILE_STATE& aBoardState,
|
|
IDF3::IDF_UNIT aBoardUnit );
|
|
|
|
/**
|
|
* Write a note entry to an IDFv3 file.
|
|
*
|
|
* @param aBoardFile is an open BOARD file; the file position must be within a NOTE section.
|
|
* @param aBoardUnit is the BOARD file's native units (MM or THOU).
|
|
* @return true if the item was successfully written, false otherwise.
|
|
* @throw In case of unrecoverable error.
|
|
*/
|
|
bool writeNote( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit );
|
|
|
|
std::string text; // note text as per IDFv3
|
|
double xpos; // text X position as per IDFv3
|
|
double ypos; // text Y position as per IDFv3
|
|
double height; // text height as per IDFv3
|
|
double length; // text length as per IDFv3
|
|
};
|
|
|
|
|
|
/**
|
|
* A drilled hole.
|
|
*
|
|
* Responsible for writing this information to a file in compliance with the IDFv3 specification.
|
|
*/
|
|
class IDF_DRILL_DATA
|
|
{
|
|
public:
|
|
/**
|
|
* Create an empty drill entry which can be populated by the read() function.
|
|
*/
|
|
IDF_DRILL_DATA();
|
|
|
|
/**
|
|
* Create a drill entry with information compliant with the IDFv3 specifications.
|
|
*
|
|
* @param aDrillDia is the drill diameter.
|
|
* @param aPosX is the X coordinate of the drill center.
|
|
* @param aPosY is the Y coordinate of the drill center.
|
|
* @param aPlating is a plating flag, PTH or NPTH.
|
|
* @param aRefDes is the component Reference Designator.
|
|
* @param aHoleType is the type of hole.
|
|
* @param aOwner is one of MCAD, ECAD, UNOWNED.
|
|
*/
|
|
IDF_DRILL_DATA( double aDrillDia, double aPosX, double aPosY,
|
|
IDF3::KEY_PLATING aPlating,
|
|
const std::string& aRefDes,
|
|
const std::string& aHoleType,
|
|
IDF3::KEY_OWNER aOwner );
|
|
|
|
/**
|
|
* Return true if the given drill diameter and location matches the diameter and location
|
|
* of this IDF_DRILL_DATA object.
|
|
*
|
|
* @param aDrillDia is the drill diameter (mm).
|
|
* @param aPosX is the X position (mm) of the drilled hole.
|
|
* @param aPosY is the Y position (mm) of the drilled hole.
|
|
* @return true if the diameter and position match this object.
|
|
*/
|
|
bool Matches( double aDrillDia, double aPosX, double aPosY ) const;
|
|
|
|
/**
|
|
* @return the drill diameter in mm.
|
|
*/
|
|
double GetDrillDia() const;
|
|
|
|
/**
|
|
* @return the drill's X position in mm.
|
|
*/
|
|
double GetDrillXPos() const;
|
|
|
|
/**
|
|
* @return the drill's Y position in mm.
|
|
*/
|
|
double GetDrillYPos() const;
|
|
|
|
/**
|
|
* @return the plating value (PTH, NPTH).
|
|
*/
|
|
IDF3::KEY_PLATING GetDrillPlating();
|
|
|
|
/**
|
|
* @return the reference designator of the hole; this may be a component reference designator,
|
|
* BOARD, or NOREFDES as per IDFv3.
|
|
*/
|
|
const std::string& GetDrillRefDes();
|
|
|
|
/**
|
|
* @return the classification of the hole; this may be one of PIN, VIA, MTG, TOOL, or a
|
|
* user-specified string.
|
|
*/
|
|
const std::string& GetDrillHoleType();
|
|
|
|
IDF3::KEY_OWNER GetDrillOwner() const
|
|
{
|
|
return owner;
|
|
}
|
|
|
|
private:
|
|
friend class IDF3_BOARD;
|
|
friend class IDF3_COMPONENT;
|
|
|
|
/**
|
|
* Read a drill entry from an IDFv3 file
|
|
*
|
|
* @param aBoardFile is an open IDFv3 file; the file position must be within the DRILLED_HOLES
|
|
* section.
|
|
* @param aBoardUnit is the board file's native unit (MM or THOU).
|
|
* @param aBoardState is the state value of the parser.
|
|
* @return true if data was successfully read, otherwise false.
|
|
* @throw in case of an unrecoverable error.
|
|
*/
|
|
bool read( std::istream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, IDF3::FILE_STATE aBoardState,
|
|
IDF3::IDF_VERSION aIdfVersion );
|
|
|
|
/**
|
|
* Write a single line representing a hole within a .DRILLED_HOLES section.
|
|
*
|
|
* @param aBoardFile is an open BOARD file
|
|
* @param aBoardUnit is the native unit of the output file
|
|
* @throw in case of an unrecoverable error.
|
|
*/
|
|
void write( std::ostream& aBoardFile, IDF3::IDF_UNIT aBoardUnit );
|
|
|
|
double dia;
|
|
double x;
|
|
double y;
|
|
IDF3::KEY_PLATING plating;
|
|
IDF3::KEY_REFDES kref;
|
|
IDF3::KEY_HOLETYPE khole;
|
|
std::string refdes;
|
|
std::string holetype;
|
|
IDF3::KEY_OWNER owner;
|
|
};
|
|
|
|
|
|
/**
|
|
* A point as used by the various IDF related classes.
|
|
*/
|
|
class IDF_POINT
|
|
{
|
|
public:
|
|
IDF_POINT()
|
|
{
|
|
x = 0.0;
|
|
y = 0.0;
|
|
}
|
|
|
|
IDF_POINT( double aX, double aY )
|
|
{
|
|
x = aX;
|
|
y = aY;
|
|
}
|
|
|
|
/**
|
|
* Return true if the given coordinate point is within the given radius of the point.
|
|
*
|
|
* @param aPoint is the coordinates of the point being compared.
|
|
* @param aRadius is the radius (mm) within which the points are considered the same.
|
|
* @return true if this point matches the given point.
|
|
*/
|
|
bool Matches( const IDF_POINT& aPoint, double aRadius = 1e-5 ) const;
|
|
|
|
/**
|
|
* Return the Euclidean distance between this point and the given point.
|
|
*
|
|
* @param aPoint is the coordinates of the point whose distance is to be determined.
|
|
* @return double is the distance between this point and aPoint.
|
|
*/
|
|
double CalcDistance( const IDF_POINT& aPoint ) const;
|
|
|
|
double x; // < X coordinate
|
|
double y; // < Y coordinate
|
|
};
|
|
|
|
|
|
/**
|
|
* A segment as used in IDFv3 outlines.
|
|
*
|
|
* It may be any of an arc, line segment, or circle
|
|
*/
|
|
class IDF_SEGMENT
|
|
{
|
|
public:
|
|
/**
|
|
* Initialize the internal variables.
|
|
*/
|
|
IDF_SEGMENT();
|
|
|
|
/**
|
|
* Create a straight segment.
|
|
*/
|
|
IDF_SEGMENT( const IDF_POINT& aStartPoint, const IDF_POINT& aEndPoint );
|
|
|
|
/**
|
|
* Create a straight segment, arc, or circle depending on the angle.
|
|
*
|
|
* @param aStartPoint is the start point (center if using KiCad convention, otherwise IDF
|
|
* convention)
|
|
* @param aEndPoint is the end point (start of arc if using KiCad convention, otherwise IDF
|
|
* convention)
|
|
* @param aAngle is the included angle; the KiCad convention is equivalent to the IDF convention
|
|
* @param fromKicad set to 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 );
|
|
|
|
/**
|
|
* Return true if the given coordinate is within a radius 'rad' of the start point.
|
|
*
|
|
* @param aPoint are the coordinates of the point (mm) being compared.
|
|
* @param aRadius is the radius (mm) within which the points are considered the same.
|
|
* @return true if the given point matches the start point of this segment.
|
|
*/
|
|
bool MatchesStart( const IDF_POINT& aPoint, double aRadius = 1e-3 );
|
|
|
|
/**
|
|
* Return true if the given coordinate is within a radius 'rad' of the end point.
|
|
*
|
|
* @param aPoint are the coordinates (mm) of the point being compared.
|
|
* @param aRadius is the radius (mm) within which the points are considered the same.
|
|
* @return true if the given point matches the end point of this segment.
|
|
*/
|
|
bool MatchesEnd( const IDF_POINT& aPoint, double aRadius = 1e-3 );
|
|
|
|
/**
|
|
* @return true if this segment is a circle.
|
|
*/
|
|
bool IsCircle();
|
|
|
|
/**
|
|
* @return the minimum X coordinate of this segment.
|
|
*/
|
|
double GetMinX();
|
|
|
|
/**
|
|
* Swap the start and end points and alters internal variables as necessary for arcs.
|
|
*/
|
|
void SwapEnds();
|
|
|
|
private:
|
|
/**
|
|
* Calculate 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();
|
|
|
|
public:
|
|
IDF_POINT startPoint; ///< starting point coordinates in mm
|
|
IDF_POINT endPoint; ///< end point coordinates in mm
|
|
|
|
///< center of an arc or circle; internally calculated and not to be set by the user.
|
|
IDF_POINT center;
|
|
double angle; ///< included angle (degrees) according to IDFv3 specification
|
|
double offsetAngle; ///< angle between center and start of arc; internally calculated
|
|
double radius; ///< radius of the arc or circle; internally calculated
|
|
};
|
|
|
|
|
|
/**
|
|
* A segment and winding information for an IDF outline.
|
|
*/
|
|
class IDF_OUTLINE
|
|
{
|
|
public:
|
|
IDF_OUTLINE() { dir = 0.0; }
|
|
~IDF_OUTLINE() { Clear(); }
|
|
|
|
/**
|
|
* @return true if the current list of points represents a counterclockwise winding.
|
|
*/
|
|
bool IsCCW();
|
|
|
|
/**
|
|
* @returns true if this outline is a circle.
|
|
*/
|
|
bool IsCircle();
|
|
|
|
/**
|
|
* Clear the internal list of outline segments.
|
|
*/
|
|
void Clear()
|
|
{
|
|
dir = 0.0;
|
|
|
|
while( !outline.empty() )
|
|
{
|
|
delete outline.front();
|
|
outline.pop_front();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the size of the internal segment list.
|
|
*/
|
|
size_t size()
|
|
{
|
|
return outline.size();
|
|
}
|
|
|
|
/**
|
|
* @return true if the internal segment list is empty.
|
|
*/
|
|
bool empty()
|
|
{
|
|
return outline.empty();
|
|
}
|
|
|
|
/**
|
|
* @return the front() iterator of the internal segment list.
|
|
*/
|
|
IDF_SEGMENT*& front()
|
|
{
|
|
return outline.front();
|
|
}
|
|
|
|
/**
|
|
* @return the back() iterator of the internal segment list.
|
|
*/
|
|
IDF_SEGMENT*& back()
|
|
{
|
|
return outline.back();
|
|
}
|
|
|
|
/**
|
|
* @return the begin() iterator of the internal segment list.
|
|
*/
|
|
std::list<IDF_SEGMENT*>::iterator begin()
|
|
{
|
|
return outline.begin();
|
|
}
|
|
|
|
/**
|
|
* @return the end() iterator of the internal segment list.
|
|
*/
|
|
std::list<IDF_SEGMENT*>::iterator end()
|
|
{
|
|
return outline.end();
|
|
}
|
|
|
|
/**
|
|
* Add a segment to the internal segment list.
|
|
*
|
|
* Segments must be added in order so that startPoint[N] == endPoint[N - 1].
|
|
*
|
|
* @param item is a pointer to the segment to add to the outline.
|
|
* @return true if the segment was added, otherwise false (outline restrictions have been
|
|
* violated).
|
|
*/
|
|
bool push( IDF_SEGMENT* item );
|
|
|
|
private:
|
|
double dir; // accumulator to help determine winding direction
|
|
std::list<IDF_SEGMENT*> outline; // sequential segments comprising an outline
|
|
};
|
|
|
|
#endif // IDF_COMMON_H
|