mirror of https://github.com/KLayout/klayout.git
Gerber X2: metadata and project initialization from the latter (at least in free mode)
This commit is contained in:
parent
55c7b66160
commit
ff4e99f2a2
|
|
@ -88,6 +88,14 @@ GerberDrillFileReader::init ()
|
|||
m_format_set = false;
|
||||
}
|
||||
|
||||
GerberMetaData
|
||||
GerberDrillFileReader::do_scan ()
|
||||
{
|
||||
GerberMetaData data;
|
||||
data.function = GerberMetaData::Hole;
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
GerberDrillFileReader::do_read ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public:
|
|||
|
||||
protected:
|
||||
virtual void do_read ();
|
||||
GerberMetaData do_scan ();
|
||||
|
||||
private:
|
||||
std::string m_buffer;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <QFileDialog>
|
||||
#include <QItemDelegate>
|
||||
#include <QHeaderView>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
|
@ -1340,10 +1341,134 @@ GerberImportDialog::layout_layer_double_clicked (QTreeWidgetItem *, int)
|
|||
}
|
||||
}
|
||||
|
||||
struct FilePositionCompare
|
||||
{
|
||||
bool operator() (const std::pair<ext::GerberMetaData, std::string> &a, const std::pair<ext::GerberMetaData, std::string> &b)
|
||||
{
|
||||
if ((a.first.cu_layer_number == 0) != (b.first.cu_layer_number == 0)) {
|
||||
return (a.first.cu_layer_number == 0) < (b.first.cu_layer_number == 0);
|
||||
}
|
||||
if (a.first.cu_layer_number != b.first.cu_layer_number) {
|
||||
return a.first.cu_layer_number < b.first.cu_layer_number;
|
||||
}
|
||||
if ((a.first.from_cu == 0) != (b.first.from_cu == 0)) {
|
||||
return (a.first.from_cu == 0) < (b.first.from_cu == 0);
|
||||
}
|
||||
if (a.first.from_cu != b.first.from_cu) {
|
||||
return a.first.from_cu < b.first.from_cu;
|
||||
}
|
||||
return a.second < b.second;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
GerberImportDialog::enter_page ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
int page = mp_ui->central_stack->currentIndex ();
|
||||
|
||||
if (page == 5) {
|
||||
|
||||
// --- Free Files page
|
||||
|
||||
if (mp_data->free_files.empty ()) {
|
||||
|
||||
// scan the files in the directory and populate the file list
|
||||
|
||||
QDir dir (tl::to_qstring (mp_data->base_dir));
|
||||
if (dir.exists ()) {
|
||||
|
||||
QStringList filters;
|
||||
filters << tl::to_qstring ("*.gbr");
|
||||
filters << tl::to_qstring ("*.GBR");
|
||||
|
||||
std::vector<std::pair<ext::GerberMetaData, std::string> > files;
|
||||
|
||||
QStringList entries = dir.entryList (filters);
|
||||
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
|
||||
ext::GerberMetaData data = ext::GerberImporter::scan (tl::to_string (dir.filePath (*e)));
|
||||
files.push_back (std::make_pair (data, tl::to_string (*e)));
|
||||
}
|
||||
|
||||
std::sort (files.begin (), files.end (), FilePositionCompare ());
|
||||
|
||||
if (files.empty ()) {
|
||||
return;
|
||||
}
|
||||
if (QMessageBox::question (this, tr ("Populate Project"), tr ("Some files have been found in the specified base directory.\nIf these files contain file attributes, the project can be initialized properly.\n\nPopulate project from these files?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
|
||||
mp_data->layout_layers.clear ();
|
||||
|
||||
int min_layer = 0, max_layer = 0;
|
||||
for (std::vector<std::pair<ext::GerberMetaData, std::string> >::const_iterator f = files.begin (); f != files.end (); ++f) {
|
||||
if (f->first.cu_layer_number > 0) {
|
||||
if (min_layer == 0 || min_layer > f->first.cu_layer_number) {
|
||||
min_layer = f->first.cu_layer_number;
|
||||
}
|
||||
if (max_layer == 0 || max_layer < f->first.cu_layer_number) {
|
||||
max_layer = f->first.cu_layer_number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<int, int> l2l;
|
||||
std::map<int, int> l2v;
|
||||
|
||||
if (min_layer > 0) {
|
||||
for (int l = min_layer; l <= max_layer; ++l) {
|
||||
l2l.insert (std::make_pair (l, int (mp_data->layout_layers.size ())));
|
||||
mp_data->layout_layers.push_back (db::LayerProperties (l * 2, 0, "Cu" + tl::to_string (l)));
|
||||
if (l < max_layer) {
|
||||
l2v.insert (std::make_pair (l, int (mp_data->layout_layers.size ())));
|
||||
mp_data->layout_layers.push_back (db::LayerProperties (l * 2 + 1, 0, "Via" + tl::to_string (l)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int next_layer = max_layer * 2;
|
||||
int hole_num = 0, profile_num = 0, legend_num = 0, solder_num = 0;
|
||||
|
||||
for (std::vector<std::pair<ext::GerberMetaData, std::string> >::const_iterator f = files.begin (); f != files.end (); ++f) {
|
||||
|
||||
mp_data->free_files.push_back (GerberFreeFileDescriptor ());
|
||||
mp_data->free_files.back ().filename = tl::to_string (f->second);
|
||||
|
||||
std::vector<int> layers;
|
||||
|
||||
if (f->first.function == ext::GerberMetaData::Copper) {
|
||||
if (l2l.find (f->first.cu_layer_number) != l2l.end ()) {
|
||||
layers.push_back (l2l [f->first.cu_layer_number]);
|
||||
}
|
||||
} else if (f->first.function == ext::GerberMetaData::PlatedHole) {
|
||||
for (int l = std::min (f->first.from_cu, f->first.to_cu); l < std::max (f->first.from_cu, f->first.to_cu); ++l) {
|
||||
if (l2v.find (l) != l2v.end ()) {
|
||||
layers.push_back (l2v [l]);
|
||||
}
|
||||
}
|
||||
} else if (f->first.function == ext::GerberMetaData::NonPlatedHole || f->first.function == ext::GerberMetaData::NonPlatedHole) {
|
||||
layers.push_back (int (mp_data->layout_layers.size ()));
|
||||
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "Hole" + tl::to_string (++hole_num)));
|
||||
} else if (f->first.function == ext::GerberMetaData::Profile) {
|
||||
layers.push_back (int (mp_data->layout_layers.size ()));
|
||||
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "Profile" + tl::to_string (++profile_num)));
|
||||
} else if (f->first.function == ext::GerberMetaData::Legend) {
|
||||
layers.push_back (int (mp_data->layout_layers.size ()));
|
||||
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "Legend" + tl::to_string (++legend_num)));
|
||||
} else if (f->first.function == ext::GerberMetaData::SolderMask) {
|
||||
layers.push_back (int (mp_data->layout_layers.size ()));
|
||||
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "SolderMask" + tl::to_string (++solder_num)));
|
||||
}
|
||||
|
||||
mp_data->free_files.back ().layout_layers = layers;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1499,19 +1624,27 @@ GerberImportDialog::commit_page ()
|
|||
*/
|
||||
|
||||
// add layers for all free files if no layer is defined yet. Add additional layers. Try to find some useful numbering scheme.
|
||||
if (mp_data->layout_layers.size () < mp_data->free_files.size ()) {
|
||||
|
||||
int max_layer = 0;
|
||||
for (std::vector <db::LayerProperties>::const_iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l) {
|
||||
max_layer = std::max (max_layer, l->layer);
|
||||
int max_layer = 0;
|
||||
for (std::vector <db::LayerProperties>::const_iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l) {
|
||||
max_layer = std::max (max_layer, l->layer);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mp_data->free_files.size (); ++i) {
|
||||
|
||||
std::vector<int> valid_layers;
|
||||
for (std::vector<int>::const_iterator l = mp_data->free_files[i].layout_layers.begin (); l != mp_data->free_files[i].layout_layers.end (); ++l) {
|
||||
if (*l >= 0 && *l < int (mp_data->layout_layers.size ())) {
|
||||
valid_layers.push_back (*l);
|
||||
}
|
||||
}
|
||||
|
||||
while (mp_data->layout_layers.size () < mp_data->free_files.size ()) {
|
||||
mp_data->free_files[i].layout_layers = valid_layers;
|
||||
|
||||
// Add a stupid 1:1 mapping if no layers are mapped for the next file.
|
||||
if (mp_data->free_files[mp_data->layout_layers.size ()].layout_layers.empty ()) {
|
||||
mp_data->free_files[mp_data->layout_layers.size ()].layout_layers.push_back (int (mp_data->layout_layers.size ()));
|
||||
}
|
||||
// Add a stupid 1:1 mapping if no layers are mapped for the next file.
|
||||
if (valid_layers.empty ()) {
|
||||
|
||||
mp_data->free_files[i].layout_layers.push_back (int (mp_data->layout_layers.size ()));
|
||||
|
||||
mp_data->layout_layers.push_back (db::LayerProperties ());
|
||||
mp_data->layout_layers.back ().layer = ++max_layer;
|
||||
|
|
@ -1927,6 +2060,7 @@ GerberImportDialog::update ()
|
|||
if (! l->filename.empty ()) {
|
||||
|
||||
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (l->filename)));
|
||||
item->setData (0, Qt::ToolTipRole, QVariant (tl::to_qstring (l->filename)));
|
||||
|
||||
QFileInfo file_info (tl::to_qstring (l->filename));
|
||||
if (! mp_data->base_dir.empty () && ! file_info.isAbsolute ()) {
|
||||
|
|
@ -1972,15 +2106,20 @@ GerberImportDialog::update ()
|
|||
for (std::vector <db::LayerProperties>::const_iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l, ++n) {
|
||||
|
||||
QString hdr_label;
|
||||
QString text = tl::to_qstring (l->to_string ());
|
||||
for (const QChar *c = text.constData (); !c->isNull (); ++c) {
|
||||
if (!hdr_label.isEmpty ()) {
|
||||
hdr_label += QString::fromUtf8 ("\n");
|
||||
}
|
||||
hdr_label += *c;
|
||||
|
||||
db::LayerProperties ll = *l;
|
||||
ll.name.clear ();
|
||||
hdr_label = tl::to_qstring (ll.to_string ());
|
||||
hdr_label += QString::fromUtf8 ("\n");
|
||||
|
||||
if (l->name.size () > 4) {
|
||||
hdr_label += tl::to_qstring (std::string (l->name, 0, 4) + "...");
|
||||
} else {
|
||||
hdr_label += tl::to_qstring (l->name);
|
||||
}
|
||||
|
||||
mp_ui->free_layer_mapping_tree->headerItem ()->setData (n + 1, Qt::DisplayRole, QVariant (hdr_label));
|
||||
mp_ui->free_layer_mapping_tree->headerItem ()->setData (n + 1, Qt::ToolTipRole, QVariant (tl::to_qstring (l->to_string ())));
|
||||
|
||||
if (mp_ui->free_layer_mapping_tree->itemDelegateForColumn (n + 1) == 0) {
|
||||
mp_ui->free_layer_mapping_tree->setItemDelegateForColumn (n + 1, new GerberImportDialogNoEditDelegate (mp_ui->free_layer_mapping_tree));
|
||||
|
|
|
|||
|
|
@ -130,7 +130,28 @@ GerberFileReader::accepts (tl::TextInputStream &stream)
|
|||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
GerberMetaData
|
||||
GerberFileReader::scan (tl::TextInputStream &stream)
|
||||
{
|
||||
mp_stream = &stream;
|
||||
mp_layout = 0;
|
||||
mp_top_cell = 0;
|
||||
m_target_layers.clear ();
|
||||
|
||||
GerberMetaData meta_data;
|
||||
|
||||
try {
|
||||
meta_data = do_scan();
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (QObject::tr (" in line ")) + tl::to_string (stream.line_number ()));
|
||||
}
|
||||
|
||||
mp_stream = 0;
|
||||
|
||||
return meta_data;
|
||||
}
|
||||
|
||||
void
|
||||
GerberFileReader::read (tl::TextInputStream &stream, db::Layout &layout, db::Cell &cell, const std::vector <unsigned int> &targets)
|
||||
{
|
||||
GraphicsState state;
|
||||
|
|
@ -495,6 +516,15 @@ GerberFile::layers_string () const
|
|||
// ---------------------------------------------------------------------------------------
|
||||
// Implementation of GerberImporter
|
||||
|
||||
// TODO: generalize this:
|
||||
std::vector <tl::shared_ptr<ext::GerberFileReader> > get_readers ()
|
||||
{
|
||||
std::vector <tl::shared_ptr<ext::GerberFileReader> > readers;
|
||||
readers.push_back (new ext::GerberDrillFileReader ());
|
||||
readers.push_back (new ext::RS274XReader ());
|
||||
return readers;
|
||||
}
|
||||
|
||||
GerberImporter::GerberImporter ()
|
||||
: m_cell_name ("PCB"), m_dbu (0.001), m_merge (false),
|
||||
m_invert_negative_layers (false), m_border (5000),
|
||||
|
|
@ -526,6 +556,37 @@ GerberImporter::load_project (tl::TextInputStream &stream)
|
|||
}
|
||||
}
|
||||
|
||||
GerberMetaData
|
||||
GerberImporter::scan (const std::string &fn)
|
||||
{
|
||||
tl::InputStream stream (fn);
|
||||
tl::TextInputStream text_stream (stream);
|
||||
|
||||
return scan (text_stream);
|
||||
}
|
||||
|
||||
GerberMetaData
|
||||
GerberImporter::scan (tl::TextInputStream &stream)
|
||||
{
|
||||
try {
|
||||
|
||||
std::vector <tl::shared_ptr<ext::GerberFileReader> > readers = get_readers ();
|
||||
|
||||
// determine the reader to use:
|
||||
for (std::vector <tl::shared_ptr<ext::GerberFileReader> >::iterator r = readers.begin (); r != readers.end (); ++r) {
|
||||
stream.reset ();
|
||||
if ((*r)->accepts (stream)) {
|
||||
return (*r)->scan (stream);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::warn << ex.msg ();
|
||||
}
|
||||
|
||||
return GerberMetaData ();
|
||||
}
|
||||
|
||||
static void read_ref_point_spec (tl::Extractor &l, std::vector<std::pair<db::DBox, db::DBox> > &ref_points, size_t n, bool pcb)
|
||||
{
|
||||
while (ref_points.size () < n + 1) {
|
||||
|
|
@ -926,20 +987,14 @@ GerberImporter::do_read (db::Layout &layout, db::cell_index_type cell_index)
|
|||
tl::InputStream input_file (tl::to_string (fi.absoluteFilePath ()));
|
||||
tl::TextInputStream stream (input_file);
|
||||
|
||||
// TODO: generalize this:
|
||||
ext::RS274XReader rs274x_reader;
|
||||
ext::GerberDrillFileReader drill_file_reader;
|
||||
|
||||
std::vector <ext::GerberFileReader *> readers;
|
||||
readers.push_back (&drill_file_reader);
|
||||
readers.push_back (&rs274x_reader);
|
||||
std::vector <tl::shared_ptr<ext::GerberFileReader> > readers = get_readers ();
|
||||
|
||||
// determine the reader to use:
|
||||
ext::GerberFileReader *reader = 0;
|
||||
for (std::vector <ext::GerberFileReader *>::const_iterator r = readers.begin (); r != readers.end (); ++r) {
|
||||
for (std::vector <tl::shared_ptr<ext::GerberFileReader> >::iterator r = readers.begin (); r != readers.end (); ++r) {
|
||||
stream.reset ();
|
||||
if ((*r)->accepts (stream)) {
|
||||
reader = *r;
|
||||
reader = r->operator-> ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,104 @@ namespace lay
|
|||
namespace ext
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A structure holding the meta data for a Gerber (X2) file
|
||||
*/
|
||||
struct GerberMetaData
|
||||
{
|
||||
/**
|
||||
* @brief Identfies the function of the layer
|
||||
*/
|
||||
enum Function
|
||||
{
|
||||
NoFunction = 0,
|
||||
Copper,
|
||||
Hole,
|
||||
PlatedHole,
|
||||
NonPlatedHole,
|
||||
Profile,
|
||||
SolderMask,
|
||||
Legend,
|
||||
Other
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Identfies the position of the layer
|
||||
*/
|
||||
enum Position
|
||||
{
|
||||
NoPosition = 0,
|
||||
Bottom,
|
||||
Inner,
|
||||
Top
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
GerberMetaData ()
|
||||
: function (NoFunction),
|
||||
cu_layer_number (0),
|
||||
from_cu (0),
|
||||
to_cu (0),
|
||||
position (NoPosition)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* @brief The project name or an empty string if none is given
|
||||
*/
|
||||
std::string project_id;
|
||||
|
||||
/**
|
||||
* @brief The creation date or an empty string if none is given
|
||||
*/
|
||||
std::string creation_date;
|
||||
|
||||
/**
|
||||
* @brief The generation software or an empty string if none is given
|
||||
*/
|
||||
std::string generation_software;
|
||||
|
||||
/**
|
||||
* @brief The function of the layer
|
||||
*/
|
||||
Function function;
|
||||
|
||||
/**
|
||||
* @brief The copper layer number
|
||||
*
|
||||
* This is a number identifying the layer in the copper stack.
|
||||
* The topmost layer is 1, the bottom layer 2 or larger.
|
||||
* This value is 0 if no layer is specified.
|
||||
*/
|
||||
int cu_layer_number;
|
||||
|
||||
/**
|
||||
* @brief The drill hole start copper layer
|
||||
*
|
||||
* This is number of the copper layer that the drill hole connects (upper layer).
|
||||
* This number is applicable only if the function is PlatedHole or NonPlatedHole.
|
||||
* It is a value > 0.
|
||||
*/
|
||||
int from_cu;
|
||||
|
||||
/**
|
||||
* @brief The drill hole end copper layer
|
||||
*
|
||||
* This is number of the copper layer that the drill hole connects (lower layer).
|
||||
* This number is applicable only if the function is PlatedHole or NonPlatedHole.
|
||||
* It is a value > 0.
|
||||
*/
|
||||
int to_cu;
|
||||
|
||||
/**
|
||||
* @brief This is the position of the layer in the stack
|
||||
*
|
||||
* This value is applicable for Copper, SolderMask and Legend.
|
||||
*/
|
||||
Position position;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class holding the graphics state of the reader
|
||||
*/
|
||||
|
|
@ -83,6 +181,7 @@ struct GraphicsState
|
|||
* @brief The base class for all readers
|
||||
*/
|
||||
class GerberFileReader
|
||||
: public tl::Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
|
@ -110,6 +209,11 @@ public:
|
|||
*/
|
||||
void read (tl::TextInputStream &stream, db::Layout &layout, db::Cell &cell, const std::vector <unsigned int> &targets);
|
||||
|
||||
/**
|
||||
* @brief Scans the stream and extracts the metadata
|
||||
*/
|
||||
GerberMetaData scan (tl::TextInputStream &stream);
|
||||
|
||||
/**
|
||||
* @brief Sets the number of points for a circle interpolation
|
||||
*
|
||||
|
|
@ -291,6 +395,11 @@ protected:
|
|||
*/
|
||||
virtual void do_read () = 0;
|
||||
|
||||
/**
|
||||
* @brief Scans the stream and returns the metadata
|
||||
*/
|
||||
virtual GerberMetaData do_scan () = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the reader accepts the stream
|
||||
*/
|
||||
|
|
@ -671,6 +780,16 @@ public:
|
|||
*/
|
||||
GerberImporter ();
|
||||
|
||||
/**
|
||||
* @brief Scans the given file and extracts the metadata from it
|
||||
*/
|
||||
static GerberMetaData scan (const std::string &fn);
|
||||
|
||||
/**
|
||||
* @brief Scans the given stream and extracts the metadata from it
|
||||
*/
|
||||
static GerberMetaData scan (tl::TextInputStream &stream);
|
||||
|
||||
/**
|
||||
* @brief Load the project file from the given stream
|
||||
*
|
||||
|
|
|
|||
|
|
@ -89,6 +89,129 @@ RS274XReader::init ()
|
|||
m_current_aperture = 0;
|
||||
}
|
||||
|
||||
static GerberMetaData::Position
|
||||
parse_position (tl::Extractor &ex)
|
||||
{
|
||||
if (ex.test ("Bot")) {
|
||||
return GerberMetaData::Bottom;
|
||||
} else if (ex.test ("Top")) {
|
||||
return GerberMetaData::Top;
|
||||
} else if (ex.test ("Inr")) {
|
||||
return GerberMetaData::Inner;
|
||||
} else {
|
||||
return GerberMetaData::NoPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GerberMetaData
|
||||
RS274XReader::do_scan ()
|
||||
{
|
||||
GerberMetaData data;
|
||||
|
||||
char c;
|
||||
|
||||
// Actually read:
|
||||
while ((c = stream ().skip ()) != 0 && !stream ().at_end ()) {
|
||||
|
||||
if (c == '%') {
|
||||
|
||||
stream ().get_char ();
|
||||
|
||||
while (! stream ().at_end () && (c = stream ().skip ()) != '%') {
|
||||
|
||||
std::string param;
|
||||
param += stream ().get_char ();
|
||||
if (! stream ().at_end ()) {
|
||||
param += stream ().get_char ();
|
||||
}
|
||||
|
||||
std::string bl = get_block ();
|
||||
|
||||
if (param == "TF") {
|
||||
|
||||
// Extract information
|
||||
tl::Extractor ex (bl);
|
||||
|
||||
if (ex.test (".ProjectId")) {
|
||||
|
||||
ex.test (",");
|
||||
data.project_id = ex.get ();
|
||||
|
||||
} else if (ex.test (".CreationDate")) {
|
||||
|
||||
ex.test (",");
|
||||
data.creation_date = ex.get ();
|
||||
|
||||
} else if (ex.test (".GenerationSoftware")) {
|
||||
|
||||
ex.test (",");
|
||||
data.generation_software = ex.get ();
|
||||
|
||||
} else if (ex.test (".FileFunction")) {
|
||||
|
||||
ex.test (",");
|
||||
bool plated = false;
|
||||
|
||||
if (ex.test ("Copper")) {
|
||||
|
||||
data.function = GerberMetaData::Copper;
|
||||
|
||||
ex.test (",");
|
||||
ex.test ("L");
|
||||
ex.read (data.cu_layer_number);
|
||||
ex.test (",");
|
||||
data.position = parse_position (ex);
|
||||
|
||||
} else if (ex.test ("Profile")) {
|
||||
|
||||
data.function = GerberMetaData::Profile;
|
||||
|
||||
} else if (ex.test ("Soldermask")) {
|
||||
|
||||
data.function = GerberMetaData::SolderMask;
|
||||
ex.test (",");
|
||||
data.position = parse_position (ex);
|
||||
|
||||
} else if (ex.test ("Legend")) {
|
||||
|
||||
data.function = GerberMetaData::Legend;
|
||||
ex.test (",");
|
||||
data.position = parse_position (ex);
|
||||
|
||||
} else if ((plated = ex.test ("Plated")) || ex.test ("NonPlated")) {
|
||||
|
||||
data.function = plated ? GerberMetaData::PlatedHole : GerberMetaData::NonPlatedHole;
|
||||
|
||||
ex.test (",");
|
||||
ex.read (data.from_cu);
|
||||
ex.test (",");
|
||||
ex.read (data.to_cu);
|
||||
|
||||
} else {
|
||||
data.function = GerberMetaData::NoFunction;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eat trailing '%'
|
||||
if (! stream ().at_end ()) {
|
||||
stream ().get_char ();
|
||||
}
|
||||
|
||||
} else {
|
||||
get_block ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
RS274XReader::do_read ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public:
|
|||
|
||||
protected:
|
||||
virtual void do_read ();
|
||||
GerberMetaData do_scan ();
|
||||
|
||||
private:
|
||||
bool m_clear;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbLoadLayoutOptions.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "extGerberImporter.h"
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
|
|
@ -51,6 +52,109 @@ static void run_test (tl::TestBase *_this, const char *dir)
|
|||
db::compare_layouts (_this, layout, tl::testsrc_private () + "/testdata/pcb/" + dir + "/au.oas.gz", db::WriteOAS, 1);
|
||||
}
|
||||
|
||||
TEST(0_Metadata)
|
||||
{
|
||||
ext::GerberMetaData data;
|
||||
|
||||
std::string fn;
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/1.gbr";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "2017-09-07T21:37;00+01:00");
|
||||
EXPECT_EQ (data.generation_software, "KLayout,0.25");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::Copper);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::Top);
|
||||
EXPECT_EQ (data.from_cu, 0);
|
||||
EXPECT_EQ (data.to_cu, 0);
|
||||
EXPECT_EQ (data.cu_layer_number, 1);
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/2.gbr";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "2017-09-07T21:37;00+01:00");
|
||||
EXPECT_EQ (data.generation_software, "KLayout,0.25");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::Copper);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::Bottom);
|
||||
EXPECT_EQ (data.from_cu, 0);
|
||||
EXPECT_EQ (data.to_cu, 0);
|
||||
EXPECT_EQ (data.cu_layer_number, 4);
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/3.gbr";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "2017-09-07T21:37;00+01:00");
|
||||
EXPECT_EQ (data.generation_software, "KLayout,0.25");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::Copper);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::Inner);
|
||||
EXPECT_EQ (data.from_cu, 0);
|
||||
EXPECT_EQ (data.to_cu, 0);
|
||||
EXPECT_EQ (data.cu_layer_number, 2);
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/10.gbr";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "2017-09-07T21:37;00+01:00");
|
||||
EXPECT_EQ (data.generation_software, "KLayout,0.25");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::Legend);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::Top);
|
||||
EXPECT_EQ (data.from_cu, 0);
|
||||
EXPECT_EQ (data.to_cu, 0);
|
||||
EXPECT_EQ (data.cu_layer_number, 0);
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/11.gbr";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "2017-09-07T21:37;00+01:00");
|
||||
EXPECT_EQ (data.generation_software, "KLayout,0.25");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::SolderMask);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::Top);
|
||||
EXPECT_EQ (data.from_cu, 0);
|
||||
EXPECT_EQ (data.to_cu, 0);
|
||||
EXPECT_EQ (data.cu_layer_number, 0);
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/12.gbr";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "2017-09-07T21:37;00+01:00");
|
||||
EXPECT_EQ (data.generation_software, "KLayout,0.25");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::PlatedHole);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::NoPosition);
|
||||
EXPECT_EQ (data.from_cu, 1);
|
||||
EXPECT_EQ (data.to_cu, 4);
|
||||
EXPECT_EQ (data.cu_layer_number, 0);
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/13.gbr";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "2017-09-07T21:37;00+01:00");
|
||||
EXPECT_EQ (data.generation_software, "KLayout,0.25");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::NonPlatedHole);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::NoPosition);
|
||||
EXPECT_EQ (data.from_cu, 1);
|
||||
EXPECT_EQ (data.to_cu, 4);
|
||||
EXPECT_EQ (data.cu_layer_number, 0);
|
||||
|
||||
fn = tl::testsrc_private ();
|
||||
fn += "/testdata/pcb/metadata/20.drl";
|
||||
data = ext::GerberImporter::scan (fn);
|
||||
|
||||
EXPECT_EQ (data.creation_date, "");
|
||||
EXPECT_EQ (data.generation_software, "");
|
||||
EXPECT_EQ (data.function, ext::GerberMetaData::Hole);
|
||||
EXPECT_EQ (data.position, ext::GerberMetaData::NoPosition);
|
||||
EXPECT_EQ (data.from_cu, 0);
|
||||
EXPECT_EQ (data.to_cu, 0);
|
||||
EXPECT_EQ (data.cu_layer_number, 0);
|
||||
}
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
|
|
|||
Loading…
Reference in New Issue