mirror of https://github.com/KLayout/klayout.git
WIP: Fixed PCB import for non-Qt builds, added missing file.
This commit is contained in:
parent
221d5a4a38
commit
260243a6d9
|
|
@ -119,6 +119,7 @@ SOURCES = \
|
|||
gsiDeclDbVector.cc \
|
||||
gsiDeclDbLayoutDiff.cc \
|
||||
gsiDeclDbGlyphs.cc \
|
||||
dbConverters.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -206,7 +207,8 @@ HEADERS = \
|
|||
dbNamedLayerReader.h \
|
||||
dbForceLink.h \
|
||||
dbPlugin.h \
|
||||
dbInit.h
|
||||
dbInit.h \
|
||||
dbConverters.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbConverters.h"
|
||||
#include "tlInternational.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// .. nothing yet ..
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_dbConverters
|
||||
#define HDR_dbConverters
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbLayerProperties.h"
|
||||
#include "dbTrans.h"
|
||||
#include "dbPoint.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A converter for transformations
|
||||
*
|
||||
* T is supposed a transformation type such as "db::DCplxTrans".
|
||||
*/
|
||||
template <class T>
|
||||
struct DB_PUBLIC TransformationConverter
|
||||
{
|
||||
std::string to_string (const T &t) const
|
||||
{
|
||||
return t.to_string ();
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, T &t) const
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
ex.read (t);
|
||||
ex.expect_end ();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A converter for layout layers
|
||||
*/
|
||||
struct DB_PUBLIC LayoutLayerConverter
|
||||
{
|
||||
std::string to_string (const db::LayerProperties &p) const
|
||||
{
|
||||
return p.to_string ();
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, db::LayerProperties &p) const
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
p.read (ex);
|
||||
ex.expect_end ();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A converter for points
|
||||
*
|
||||
* P is supposed to be a point type (i.e. db::DPoint).
|
||||
*/
|
||||
template <class P>
|
||||
struct DB_PUBLIC PointConverter
|
||||
{
|
||||
std::string to_string (const P &p) const
|
||||
{
|
||||
return tl::to_string (p.x ()) + "," + tl::to_string (p.y ());
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, P &p) const
|
||||
{
|
||||
typename P::coord_type x, y;
|
||||
tl::Extractor ex (s.c_str ());
|
||||
ex.read (x);
|
||||
ex.expect (",");
|
||||
ex.read (y);
|
||||
p = P (x, y);
|
||||
ex.expect_end ();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -28,8 +28,6 @@
|
|||
|
||||
#include <QColor>
|
||||
|
||||
#include "dbLayerProperties.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
|
|
@ -42,70 +40,6 @@ struct LAYBASIC_PUBLIC ColorConverter
|
|||
void from_string (const std::string &s, QColor &c) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A converter for transformations
|
||||
*
|
||||
* T is supposed a transformation type such as "db::DCplxTrans".
|
||||
*/
|
||||
template <class T>
|
||||
struct LAYBASIC_PUBLIC TransformationConverter
|
||||
{
|
||||
std::string to_string (const T &t) const
|
||||
{
|
||||
return t.to_string ();
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, T &t) const
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
ex.read (t);
|
||||
ex.expect_end ();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A converter for layout layers
|
||||
*/
|
||||
struct LAYBASIC_PUBLIC LayoutLayerConverter
|
||||
{
|
||||
std::string to_string (const db::LayerProperties &p) const
|
||||
{
|
||||
return p.to_string ();
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, db::LayerProperties &p) const
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
p.read (ex);
|
||||
ex.expect_end ();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A converter for points
|
||||
*
|
||||
* P is supposed to be a point type (i.e. db::DPoint).
|
||||
*/
|
||||
template <class P>
|
||||
struct LAYBASIC_PUBLIC PointConverter
|
||||
{
|
||||
std::string to_string (const P &p) const
|
||||
{
|
||||
return tl::to_string (p.x ()) + "," + tl::to_string (p.y ());
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, P &p) const
|
||||
{
|
||||
typename P::coord_type x, y;
|
||||
tl::Extractor ex (s.c_str ());
|
||||
ex.read (x);
|
||||
ex.expect (",");
|
||||
ex.read (y);
|
||||
p = P (x, y);
|
||||
ex.expect_end ();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,517 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbGerberImportData.h"
|
||||
#include "dbGerberImporter.h"
|
||||
#include "dbPoint.h"
|
||||
#include "dbConverters.h"
|
||||
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlXMLParser.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// GerberImportData implementation
|
||||
|
||||
GerberImportData::GerberImportData ()
|
||||
: invert_negative_layers (false), border (5000),
|
||||
free_layer_mapping (false), mode (ModeSamePanel), mounting (MountingTop),
|
||||
num_metal_layers (0), num_via_types (0), num_circle_points (-1),
|
||||
merge_flag (false), dbu (0.001), topcell_name ("PCB")
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::reset ()
|
||||
{
|
||||
double dbu_saved = dbu;
|
||||
std::string base_dir_saved = base_dir;
|
||||
bool free_layer_mapping_saved = free_layer_mapping;
|
||||
mode_type mode_saved = mode;
|
||||
|
||||
*this = GerberImportData ();
|
||||
|
||||
dbu = dbu_saved;
|
||||
base_dir = base_dir_saved;
|
||||
free_layer_mapping = free_layer_mapping_saved;
|
||||
mode = mode_saved;
|
||||
}
|
||||
|
||||
std::string
|
||||
GerberImportData::get_layer_properties_file () const
|
||||
{
|
||||
std::string lyp_file = layer_properties_file;
|
||||
if (! lyp_file.empty ()) {
|
||||
if (! base_dir.empty () && ! tl::is_absolute (lyp_file)) {
|
||||
lyp_file = tl::absolute_file_path (tl::combine_path (base_dir, lyp_file));
|
||||
}
|
||||
}
|
||||
|
||||
return lyp_file;
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::setup_importer (db::GerberImporter *importer)
|
||||
{
|
||||
if (num_circle_points >= 4) {
|
||||
importer->set_circle_points (num_circle_points);
|
||||
}
|
||||
|
||||
importer->set_dbu (dbu);
|
||||
importer->set_cell_name (topcell_name);
|
||||
importer->set_dir (base_dir);
|
||||
importer->set_global_trans (explicit_trans);
|
||||
importer->set_reference_points (reference_points);
|
||||
importer->set_merge (merge_flag);
|
||||
importer->set_invert_negative_layers (invert_negative_layers);
|
||||
importer->set_border (border);
|
||||
|
||||
if (free_layer_mapping) {
|
||||
|
||||
for (std::vector<GerberFreeFileDescriptor>::iterator file = free_files.begin (); file != free_files.end (); ++file) {
|
||||
|
||||
if (! file->filename.empty ()) {
|
||||
|
||||
db::GerberFile file_spec;
|
||||
file_spec.set_filename (file->filename);
|
||||
|
||||
for (std::vector <int>::const_iterator i = file->layout_layers.begin (); i != file->layout_layers.end (); ++i) {
|
||||
if (*i >= 0 && *i < int (layout_layers.size ())) {
|
||||
file_spec.add_layer_spec (layout_layers [*i]);
|
||||
}
|
||||
}
|
||||
|
||||
importer->add_file (file_spec);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (std::vector<GerberArtworkFileDescriptor>::iterator file = artwork_files.begin (); file != artwork_files.end (); ++file) {
|
||||
|
||||
if (! file->filename.empty ()) {
|
||||
|
||||
size_t n;
|
||||
if (mounting == MountingTop) {
|
||||
n = std::distance (artwork_files.begin (), file);
|
||||
} else {
|
||||
n = std::distance (file, artwork_files.end ()) - 1;
|
||||
}
|
||||
|
||||
if (n * 2 < layout_layers.size ()) {
|
||||
db::GerberFile file_spec;
|
||||
file_spec.set_filename (file->filename);
|
||||
file_spec.add_layer_spec (layout_layers [n * 2]);
|
||||
importer->add_file (file_spec);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<GerberDrillFileDescriptor>::iterator file = drill_files.begin (); file != drill_files.end (); ++file) {
|
||||
|
||||
if (! file->filename.empty ()) {
|
||||
|
||||
size_t nstart, nstop;
|
||||
if (mounting == MountingTop) {
|
||||
nstart = std::distance (artwork_files.begin (), artwork_files.begin () + file->start);
|
||||
nstop = std::distance (artwork_files.begin (), artwork_files.begin () + file->stop);
|
||||
} else {
|
||||
nstop = std::distance (artwork_files.begin () + file->start, artwork_files.end ()) - 1;
|
||||
nstart = std::distance (artwork_files.begin () + file->stop, artwork_files.end ()) - 1;
|
||||
}
|
||||
|
||||
db::GerberFile file_spec;
|
||||
file_spec.set_filename (file->filename);
|
||||
|
||||
for (size_t n = nstart; n < nstop; ++n) {
|
||||
if (n * 2 + 1 < layout_layers.size ()) {
|
||||
file_spec.add_layer_spec (layout_layers [n * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
importer->add_file (file_spec);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct MountingConverter
|
||||
{
|
||||
std::string to_string (GerberImportData::mounting_type m) const
|
||||
{
|
||||
return m == GerberImportData::MountingTop ? "top" : "bottom";
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, GerberImportData::mounting_type &m) const
|
||||
{
|
||||
if (s == "top") {
|
||||
m = GerberImportData::MountingTop;
|
||||
} else if (s == "bottom") {
|
||||
m = GerberImportData::MountingBottom;
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid mounting specification: %s")), s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// declaration of the layer properties file XML structure
|
||||
static const tl::XMLStruct <GerberImportData>
|
||||
pcb_project_structure ("pcb-project",
|
||||
tl::make_member (&GerberImportData::invert_negative_layers, "invert-negative-layers") +
|
||||
tl::make_member (&GerberImportData::border, "border") +
|
||||
tl::make_member (&GerberImportData::free_layer_mapping, "free-layer-mapping") +
|
||||
tl::make_element (&GerberImportData::layout_layers, "layout-layers",
|
||||
tl::make_member<db::LayerProperties, std::vector<db::LayerProperties>::const_iterator, std::vector<db::LayerProperties> > (&std::vector<db::LayerProperties>::begin, &std::vector<db::LayerProperties>::end, &std::vector<db::LayerProperties>::push_back, "layout-layer", db::LayoutLayerConverter ())
|
||||
) +
|
||||
tl::make_member (&GerberImportData::mounting, "mounting", MountingConverter ()) +
|
||||
tl::make_member (&GerberImportData::num_metal_layers, "num-metal-layers") +
|
||||
tl::make_member (&GerberImportData::num_via_types, "num-via-types") +
|
||||
tl::make_element (&GerberImportData::artwork_files, "artwork-files",
|
||||
tl::make_element<GerberArtworkFileDescriptor, std::vector<GerberArtworkFileDescriptor>::const_iterator, std::vector<GerberArtworkFileDescriptor> > (&std::vector<GerberArtworkFileDescriptor>::begin, &std::vector<GerberArtworkFileDescriptor>::end, &std::vector<GerberArtworkFileDescriptor>::push_back, "artwork-file",
|
||||
tl::make_member (&GerberArtworkFileDescriptor::filename, "filename")
|
||||
)
|
||||
) +
|
||||
tl::make_element (&GerberImportData::drill_files, "drill-files",
|
||||
tl::make_element<GerberDrillFileDescriptor, std::vector<GerberDrillFileDescriptor>::const_iterator, std::vector<GerberDrillFileDescriptor> > (&std::vector<GerberDrillFileDescriptor>::begin, &std::vector<GerberDrillFileDescriptor>::end, &std::vector<GerberDrillFileDescriptor>::push_back, "drill-file",
|
||||
tl::make_member (&GerberDrillFileDescriptor::start, "start") +
|
||||
tl::make_member (&GerberDrillFileDescriptor::stop, "stop") +
|
||||
tl::make_member (&GerberDrillFileDescriptor::filename, "filename")
|
||||
)
|
||||
) +
|
||||
tl::make_element (&GerberImportData::free_files, "free-files",
|
||||
tl::make_element<GerberFreeFileDescriptor, std::vector<GerberFreeFileDescriptor>::const_iterator, std::vector<GerberFreeFileDescriptor> > (&std::vector<GerberFreeFileDescriptor>::begin, &std::vector<GerberFreeFileDescriptor>::end, &std::vector<GerberFreeFileDescriptor>::push_back, "free-file",
|
||||
tl::make_member (&GerberFreeFileDescriptor::filename, "filename") +
|
||||
tl::make_element (&GerberFreeFileDescriptor::layout_layers, "layout-layers",
|
||||
tl::make_member<int, std::vector<int>::const_iterator, std::vector<int> > (&std::vector<int>::begin, &std::vector<int>::end, &std::vector<int>::push_back, "index")
|
||||
)
|
||||
)
|
||||
) +
|
||||
tl::make_element (&GerberImportData::reference_points, "reference-points",
|
||||
tl::make_element<std::pair <db::DPoint, db::DPoint>, std::vector<std::pair <db::DPoint, db::DPoint> >::const_iterator, std::vector<std::pair <db::DPoint, db::DPoint> > > (&std::vector<std::pair <db::DPoint, db::DPoint> >::begin, &std::vector<std::pair <db::DPoint, db::DPoint> >::end, &std::vector<std::pair <db::DPoint, db::DPoint> >::push_back, "reference-point",
|
||||
tl::make_member (&std::pair <db::DPoint, db::DPoint>::first, "pcb", db::PointConverter<db::DPoint> ()) +
|
||||
tl::make_member (&std::pair <db::DPoint, db::DPoint>::second, "layout", db::PointConverter<db::DPoint> ())
|
||||
)
|
||||
) +
|
||||
tl::make_member (&GerberImportData::explicit_trans, "explicit-trans", db::TransformationConverter<db::DCplxTrans> ()) +
|
||||
tl::make_member (&GerberImportData::layer_properties_file, "layer-properties-file") +
|
||||
tl::make_member (&GerberImportData::num_circle_points, "num-circle-points") +
|
||||
tl::make_member (&GerberImportData::merge_flag, "merge-flag") +
|
||||
tl::make_member (&GerberImportData::dbu, "dbu") +
|
||||
tl::make_member (&GerberImportData::topcell_name, "cell-name")
|
||||
);
|
||||
|
||||
void
|
||||
GerberImportData::load (const std::string &file)
|
||||
{
|
||||
reset ();
|
||||
current_file = file;
|
||||
tl::XMLFileSource in (file);
|
||||
pcb_project_structure.parse (in, *this);
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::load (tl::InputStream &stream)
|
||||
{
|
||||
reset ();
|
||||
current_file = std::string ();
|
||||
tl::XMLStreamSource in (stream);
|
||||
pcb_project_structure.parse (in, *this);
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::save (const std::string &file)
|
||||
{
|
||||
tl::OutputStream os (file, tl::OutputStream::OM_Plain);
|
||||
pcb_project_structure.write (os, *this);
|
||||
current_file = file;
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::from_string (const std::string &s)
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
if (ex.test ("free-layer-mapping")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (free_layer_mapping);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("invert-negative-layers")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (invert_negative_layers);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("border")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (border);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("import-mode")) {
|
||||
|
||||
ex.test ("=");
|
||||
int m = 0;
|
||||
ex.read (m);
|
||||
mode = (mode_type) m;
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("base-dir")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read_word_or_quoted (base_dir);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("layout-layers")) {
|
||||
|
||||
ex.test ("=");
|
||||
layout_layers.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
layout_layers.push_back (db::LayerProperties ());
|
||||
layout_layers.back ().read (ex);
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("mounting")) {
|
||||
|
||||
ex.test ("=");
|
||||
std::string m;
|
||||
ex.read_word (m);
|
||||
mounting = (m == "top") ? MountingTop : MountingBottom;
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("num-metal-layers")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (num_metal_layers);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("num-via-types")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (num_via_types);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("artwork-files")) {
|
||||
|
||||
ex.test ("=");
|
||||
artwork_files.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
ex.test ("(");
|
||||
artwork_files.push_back (db::GerberArtworkFileDescriptor ());
|
||||
ex.read_word_or_quoted (artwork_files.back ().filename);
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("drill-files")) {
|
||||
|
||||
ex.test ("=");
|
||||
drill_files.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
ex.test ("(");
|
||||
drill_files.push_back (db::GerberDrillFileDescriptor ());
|
||||
ex.read (drill_files.back ().start);
|
||||
ex.test (",");
|
||||
ex.read (drill_files.back ().stop);
|
||||
ex.test (",");
|
||||
ex.read_word_or_quoted (drill_files.back ().filename);
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("free-files")) {
|
||||
|
||||
ex.test ("=");
|
||||
free_files.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
ex.test ("(");
|
||||
free_files.push_back (db::GerberFreeFileDescriptor ());
|
||||
ex.read_word_or_quoted (free_files.back ().filename);
|
||||
ex.test (",");
|
||||
while (! ex.test (")") && ! ex.at_end ()) {
|
||||
int i = -1;
|
||||
ex.read (i);
|
||||
free_files.back ().layout_layers.push_back (i);
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("reference-points")) {
|
||||
|
||||
ex.test ("=");
|
||||
reference_points.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
double x1, y1, x2, y2;
|
||||
ex.test ("(");
|
||||
ex.test ("(");
|
||||
ex.read (x1);
|
||||
ex.test (",");
|
||||
ex.read (y1);
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
ex.test ("(");
|
||||
ex.read (x2);
|
||||
ex.test (",");
|
||||
ex.read (y2);
|
||||
ex.test (")");
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
reference_points.push_back (std::make_pair (db::DPoint (x1, y1), db::DPoint (x2, y2)));
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("explicit-trans")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (explicit_trans);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("layer-properties-file")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read_word_or_quoted (layer_properties_file);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("num-circle-points")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (num_circle_points);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("merge-flag")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (merge_flag);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("dbu")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (dbu);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("cell-name")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read_word_or_quoted (topcell_name);
|
||||
ex.test (";");
|
||||
|
||||
} else {
|
||||
ex.expect_end ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
GerberImportData::to_string () const
|
||||
{
|
||||
std::string s;
|
||||
s += "free-layer-mapping=" + tl::to_string(free_layer_mapping) + ";";
|
||||
s += "import-mode=" + tl::to_string(int (mode)) + ";";
|
||||
s += "base-dir=" + tl::to_quoted_string (base_dir) + ";";
|
||||
s += "invert-negative-layers=" + tl::to_string (invert_negative_layers) + ";";
|
||||
s += "border=" + tl::to_string (border) + ";";
|
||||
|
||||
s += "layout-layers=";
|
||||
for (std::vector <db::LayerProperties>::const_iterator ll = layout_layers.begin (); ll != layout_layers.end (); ++ll) {
|
||||
if (ll != layout_layers.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += ll->to_string ();
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "mounting=" + std::string (mounting == MountingTop ? "top" : "bottom") + ";";
|
||||
s += "num-metal-layers=" + tl::to_string (num_metal_layers) + ";";
|
||||
s += "num-via-types=" + tl::to_string (num_via_types) + ";";
|
||||
|
||||
s += "artwork-files=";
|
||||
for (std::vector <GerberArtworkFileDescriptor>::const_iterator f = artwork_files.begin (); f != artwork_files.end (); ++f) {
|
||||
if (f != artwork_files.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "(" + tl::to_quoted_string (f->filename) + ")";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "drill-files=";
|
||||
for (std::vector <GerberDrillFileDescriptor>::const_iterator f = drill_files.begin (); f != drill_files.end (); ++f) {
|
||||
if (f != drill_files.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "(" + tl::to_string (f->start) + "," + tl::to_string (f->stop) + "," + tl::to_quoted_string (f->filename) + ")";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "free-files=";
|
||||
for (std::vector <GerberFreeFileDescriptor>::const_iterator f = free_files.begin (); f != free_files.end (); ++f) {
|
||||
if (f != free_files.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "(" + tl::to_quoted_string (f->filename);
|
||||
for (std::vector <int>::const_iterator i = f->layout_layers.begin (); i != f->layout_layers.end (); ++i) {
|
||||
s += "," + tl::to_string (*i);
|
||||
}
|
||||
s += ")";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "reference-points=";
|
||||
for (std::vector <std::pair <db::DPoint, db::DPoint> >::const_iterator rp = reference_points.begin (); rp != reference_points.end (); ++rp) {
|
||||
if (rp != reference_points.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "((" + tl::to_string (rp->first.x ()) + "," + tl::to_string (rp->first.y ()) + "),("
|
||||
+ tl::to_string (rp->second.x ()) + "," + tl::to_string (rp->second.y ()) + "))";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "explicit-trans=" + explicit_trans.to_string () + ";";
|
||||
s += "layer-properties-file=" + tl::to_quoted_string (layer_properties_file) + ";";
|
||||
s += "num-circle-points=" + tl::to_string (num_circle_points) + ";";
|
||||
s += "merge-flag=" + tl::to_string (merge_flag) + ";";
|
||||
s += "dbu=" + tl::to_string (dbu) + ";";
|
||||
s += "cell-name=" + tl::to_quoted_string (topcell_name) + ";";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2018 Matthias Koefferlein
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbGerberImportData
|
||||
#define HDR_dbGerberImportData
|
||||
|
||||
#include "dbTrans.h"
|
||||
#include "dbLayerProperties.h"
|
||||
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class GerberImporter;
|
||||
|
||||
struct GerberArtworkFileDescriptor
|
||||
{
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
struct GerberDrillFileDescriptor
|
||||
{
|
||||
GerberDrillFileDescriptor () : start (-1), stop (-1) { }
|
||||
|
||||
int start;
|
||||
int stop;
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
struct GerberFreeFileDescriptor
|
||||
{
|
||||
std::string filename;
|
||||
std::vector<int> layout_layers;
|
||||
};
|
||||
|
||||
struct GerberImportData
|
||||
{
|
||||
public:
|
||||
GerberImportData ();
|
||||
|
||||
enum mode_type { ModeIntoLayout = 0, ModeSamePanel, ModeNewPanel };
|
||||
enum mounting_type { MountingTop = 0, MountingBottom };
|
||||
|
||||
bool invert_negative_layers;
|
||||
double border;
|
||||
bool free_layer_mapping;
|
||||
mode_type mode;
|
||||
std::string base_dir;
|
||||
std::string current_file;
|
||||
std::vector <db::LayerProperties> layout_layers;
|
||||
mounting_type mounting;
|
||||
int num_metal_layers;
|
||||
int num_via_types;
|
||||
std::vector <GerberArtworkFileDescriptor> artwork_files;
|
||||
std::vector <GerberDrillFileDescriptor> drill_files;
|
||||
std::vector <GerberFreeFileDescriptor> free_files;
|
||||
std::vector <std::pair <db::DPoint, db::DPoint> > reference_points;
|
||||
db::DCplxTrans explicit_trans;
|
||||
std::string layer_properties_file;
|
||||
int num_circle_points;
|
||||
bool merge_flag;
|
||||
double dbu;
|
||||
std::string topcell_name;
|
||||
|
||||
std::string get_layer_properties_file () const;
|
||||
void setup_importer (db::GerberImporter *importer);
|
||||
void reset ();
|
||||
void load (tl::InputStream &stream);
|
||||
void load (const std::string &file);
|
||||
void save (const std::string &file);
|
||||
void from_string (const std::string &s);
|
||||
std::string to_string () const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -22,8 +22,12 @@
|
|||
|
||||
|
||||
#include "dbGerberImporter.h"
|
||||
#include "dbGerberImportData.h"
|
||||
#include "dbGerberDrillFileReader.h"
|
||||
#include "dbRS274XReader.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbStream.h"
|
||||
|
||||
#include "tlStream.h"
|
||||
#include "tlString.h"
|
||||
#include "tlString.h"
|
||||
|
|
@ -1070,5 +1074,111 @@ GerberImporter::do_read (db::Layout &layout, db::cell_index_type cell_index)
|
|||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Plugin for the stream reader
|
||||
|
||||
|
||||
class GerberReader
|
||||
: public db::ReaderBase
|
||||
{
|
||||
public:
|
||||
|
||||
GerberReader (tl::InputStream &s)
|
||||
: m_stream (s)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
~GerberReader ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions & /*options*/) throw (tl::Exception)
|
||||
{
|
||||
// TODO: too simple, should provide at least a layer filtering.
|
||||
return read (layout);
|
||||
}
|
||||
|
||||
virtual const db::LayerMap &read (db::Layout &layout) throw (tl::Exception)
|
||||
{
|
||||
db::GerberImportData data;
|
||||
|
||||
std::string fn (m_stream.source ());
|
||||
if (! fn.empty ()) {
|
||||
data.base_dir = tl::absolute_path (fn);
|
||||
}
|
||||
|
||||
data.load (m_stream);
|
||||
|
||||
db::GerberImporter importer;
|
||||
data.setup_importer (&importer);
|
||||
|
||||
importer.read (layout);
|
||||
|
||||
std::string lyr_file = data.get_layer_properties_file ();
|
||||
if (! lyr_file.empty ()) {
|
||||
layout.add_meta_info (db::MetaInfo ("layer-properties-file", "Layer Properties File", lyr_file));
|
||||
}
|
||||
|
||||
return m_layers;
|
||||
}
|
||||
|
||||
virtual const char *format () const
|
||||
{
|
||||
return "GerberPCB";
|
||||
}
|
||||
|
||||
private:
|
||||
tl::InputStream &m_stream;
|
||||
db::LayerMap m_layers;
|
||||
};
|
||||
|
||||
class GerberFormatDeclaration
|
||||
: public db::StreamFormatDeclaration
|
||||
{
|
||||
virtual std::string format_name () const { return "GerberPCB"; }
|
||||
virtual std::string format_desc () const { return "Gerber PCB"; }
|
||||
virtual std::string format_title () const { return "Gerber PCB (project files)"; }
|
||||
virtual std::string file_format () const { return "Gerber PCB project files (*.pcb)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
// The test is that somewhere within the first 1000 bytes, a <pcb-project> XML tag appears.
|
||||
// 1000 bytes are within the initial block that the stream reader reads and hence
|
||||
// this does not trigger any reread which is not available on some sources.
|
||||
// TODO: this is pretty simple test. A more elaborate test would be in place here.
|
||||
std::string h = stream.read_all (1000);
|
||||
// HINT: this assumes UTF8 or ISO encoding ...
|
||||
if (h.find ("<pcb-project>") != std::string::npos) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual db::ReaderBase *create_reader (tl::InputStream &s) const
|
||||
{
|
||||
return new GerberReader (s);
|
||||
}
|
||||
|
||||
virtual db::WriterBase *create_writer () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual bool can_read () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool can_write () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<db::StreamFormatDeclaration> format_decl (new GerberFormatDeclaration (), 1000, "GerberPCB");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ HEADERS = \
|
|||
dbGerberDrillFileReader.h \
|
||||
dbGerberImporter.h \
|
||||
dbRS274XApertures.h \
|
||||
dbRS274XReader.h
|
||||
dbRS274XReader.h \
|
||||
dbGerberImportData.h
|
||||
|
||||
SOURCES = \
|
||||
dbGerberDrillFileReader.cc \
|
||||
dbGerberImporter.cc \
|
||||
dbRS274XApertures.cc \
|
||||
dbRS274XReader.cc
|
||||
dbRS274XReader.cc \
|
||||
dbGerberImportData.cc
|
||||
|
|
|
|||
|
|
@ -191,113 +191,5 @@ private:
|
|||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new lay::GerberImportPluginDeclaration (), 1200, "db::GerberImportPlugin");
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Plugin for the stream reader
|
||||
|
||||
|
||||
class GerberReader
|
||||
: public db::ReaderBase
|
||||
{
|
||||
public:
|
||||
|
||||
GerberReader (tl::InputStream &s)
|
||||
: m_stream (s)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
~GerberReader ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions & /*options*/) throw (tl::Exception)
|
||||
{
|
||||
// TODO: too simple, should provide at least a layer filtering.
|
||||
return read (layout);
|
||||
}
|
||||
|
||||
virtual const db::LayerMap &read (db::Layout &layout) throw (tl::Exception)
|
||||
{
|
||||
GerberImportData data;
|
||||
|
||||
std::string fn (m_stream.source ());
|
||||
if (! fn.empty ()) {
|
||||
QFileInfo fi (tl::to_qstring (fn));
|
||||
data.base_dir = tl::to_string (fi.absoluteDir ().path ());
|
||||
}
|
||||
|
||||
data.load (m_stream);
|
||||
|
||||
db::GerberImporter importer;
|
||||
data.setup_importer (&importer);
|
||||
|
||||
importer.read (layout);
|
||||
|
||||
std::string lyr_file = data.get_layer_properties_file ();
|
||||
if (! lyr_file.empty ()) {
|
||||
layout.add_meta_info (db::MetaInfo ("layer-properties-file", "Layer Properties File", lyr_file));
|
||||
}
|
||||
|
||||
return m_layers;
|
||||
}
|
||||
|
||||
virtual const char *format () const
|
||||
{
|
||||
return "GerberPCB";
|
||||
}
|
||||
|
||||
private:
|
||||
tl::InputStream &m_stream;
|
||||
db::LayerMap m_layers;
|
||||
};
|
||||
|
||||
class GerberFormatDeclaration
|
||||
: public db::StreamFormatDeclaration
|
||||
{
|
||||
virtual std::string format_name () const { return "GerberPCB"; }
|
||||
virtual std::string format_desc () const { return "Gerber PCB"; }
|
||||
virtual std::string format_title () const { return "Gerber PCB (project files)"; }
|
||||
virtual std::string file_format () const { return "Gerber PCB project files (*.pcb)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &stream) const
|
||||
{
|
||||
// The test is that somewhere within the first 1000 bytes, a <pcb-project> XML tag appears.
|
||||
// 1000 bytes are within the initial block that the stream reader reads and hence
|
||||
// this does not trigger any reread which is not available on some sources.
|
||||
// TODO: this is pretty simple test. A more elaborate test would be in place here.
|
||||
std::string h = stream.read_all (1000);
|
||||
// HINT: this assumes UTF8 or ISO encoding ...
|
||||
if (h.find ("<pcb-project>") != std::string::npos) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual db::ReaderBase *create_reader (tl::InputStream &s) const
|
||||
{
|
||||
return new GerberReader (s);
|
||||
}
|
||||
|
||||
virtual db::WriterBase *create_writer () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual bool can_read () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool can_write () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<db::StreamFormatDeclaration> format_decl (new GerberFormatDeclaration (), 1000, "GerberPCB");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,491 +42,6 @@
|
|||
namespace lay
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// GerberImportData implementation
|
||||
|
||||
GerberImportData::GerberImportData ()
|
||||
: invert_negative_layers (false), border (5000),
|
||||
free_layer_mapping (false), mode (ModeSamePanel), mounting (MountingTop),
|
||||
num_metal_layers (0), num_via_types (0), num_circle_points (-1),
|
||||
merge_flag (false), dbu (0.001), topcell_name ("PCB")
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::reset ()
|
||||
{
|
||||
double dbu_saved = dbu;
|
||||
std::string base_dir_saved = base_dir;
|
||||
bool free_layer_mapping_saved = free_layer_mapping;
|
||||
mode_type mode_saved = mode;
|
||||
|
||||
*this = GerberImportData ();
|
||||
|
||||
dbu = dbu_saved;
|
||||
base_dir = base_dir_saved;
|
||||
free_layer_mapping = free_layer_mapping_saved;
|
||||
mode = mode_saved;
|
||||
}
|
||||
|
||||
std::string
|
||||
GerberImportData::get_layer_properties_file () const
|
||||
{
|
||||
std::string lyp_file = layer_properties_file;
|
||||
if (! lyp_file.empty ()) {
|
||||
QFileInfo lyp_file_info (tl::to_qstring (lyp_file));
|
||||
if (! base_dir.empty () && ! lyp_file_info.isAbsolute ()) {
|
||||
lyp_file_info = QFileInfo (QDir (tl::to_qstring (base_dir)), tl::to_qstring (lyp_file));
|
||||
lyp_file = tl::to_string (lyp_file_info.absoluteFilePath ());
|
||||
}
|
||||
}
|
||||
|
||||
return lyp_file;
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::setup_importer (db::GerberImporter *importer)
|
||||
{
|
||||
if (num_circle_points >= 4) {
|
||||
importer->set_circle_points (num_circle_points);
|
||||
}
|
||||
|
||||
importer->set_dbu (dbu);
|
||||
importer->set_cell_name (topcell_name);
|
||||
importer->set_dir (base_dir);
|
||||
importer->set_global_trans (explicit_trans);
|
||||
importer->set_reference_points (reference_points);
|
||||
importer->set_merge (merge_flag);
|
||||
importer->set_invert_negative_layers (invert_negative_layers);
|
||||
importer->set_border (border);
|
||||
|
||||
if (free_layer_mapping) {
|
||||
|
||||
for (std::vector<GerberFreeFileDescriptor>::iterator file = free_files.begin (); file != free_files.end (); ++file) {
|
||||
|
||||
if (! file->filename.empty ()) {
|
||||
|
||||
db::GerberFile file_spec;
|
||||
file_spec.set_filename (file->filename);
|
||||
|
||||
for (std::vector <int>::const_iterator i = file->layout_layers.begin (); i != file->layout_layers.end (); ++i) {
|
||||
if (*i >= 0 && *i < int (layout_layers.size ())) {
|
||||
file_spec.add_layer_spec (layout_layers [*i]);
|
||||
}
|
||||
}
|
||||
|
||||
importer->add_file (file_spec);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (std::vector<GerberArtworkFileDescriptor>::iterator file = artwork_files.begin (); file != artwork_files.end (); ++file) {
|
||||
|
||||
if (! file->filename.empty ()) {
|
||||
|
||||
size_t n;
|
||||
if (mounting == MountingTop) {
|
||||
n = std::distance (artwork_files.begin (), file);
|
||||
} else {
|
||||
n = std::distance (file, artwork_files.end ()) - 1;
|
||||
}
|
||||
|
||||
if (n * 2 < layout_layers.size ()) {
|
||||
db::GerberFile file_spec;
|
||||
file_spec.set_filename (file->filename);
|
||||
file_spec.add_layer_spec (layout_layers [n * 2]);
|
||||
importer->add_file (file_spec);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<GerberDrillFileDescriptor>::iterator file = drill_files.begin (); file != drill_files.end (); ++file) {
|
||||
|
||||
if (! file->filename.empty ()) {
|
||||
|
||||
size_t nstart, nstop;
|
||||
if (mounting == MountingTop) {
|
||||
nstart = std::distance (artwork_files.begin (), artwork_files.begin () + file->start);
|
||||
nstop = std::distance (artwork_files.begin (), artwork_files.begin () + file->stop);
|
||||
} else {
|
||||
nstop = std::distance (artwork_files.begin () + file->start, artwork_files.end ()) - 1;
|
||||
nstart = std::distance (artwork_files.begin () + file->stop, artwork_files.end ()) - 1;
|
||||
}
|
||||
|
||||
db::GerberFile file_spec;
|
||||
file_spec.set_filename (file->filename);
|
||||
|
||||
for (size_t n = nstart; n < nstop; ++n) {
|
||||
if (n * 2 + 1 < layout_layers.size ()) {
|
||||
file_spec.add_layer_spec (layout_layers [n * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
importer->add_file (file_spec);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct MountingConverter
|
||||
{
|
||||
std::string to_string (GerberImportData::mounting_type m) const
|
||||
{
|
||||
return m == GerberImportData::MountingTop ? "top" : "bottom";
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, GerberImportData::mounting_type &m) const
|
||||
{
|
||||
if (s == "top") {
|
||||
m = GerberImportData::MountingTop;
|
||||
} else if (s == "bottom") {
|
||||
m = GerberImportData::MountingBottom;
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Invalid mounting specification: %s")), s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// declaration of the layer properties file XML structure
|
||||
static const tl::XMLStruct <GerberImportData>
|
||||
pcb_project_structure ("pcb-project",
|
||||
tl::make_member (&GerberImportData::invert_negative_layers, "invert-negative-layers") +
|
||||
tl::make_member (&GerberImportData::border, "border") +
|
||||
tl::make_member (&GerberImportData::free_layer_mapping, "free-layer-mapping") +
|
||||
tl::make_element (&GerberImportData::layout_layers, "layout-layers",
|
||||
tl::make_member<db::LayerProperties, std::vector<db::LayerProperties>::const_iterator, std::vector<db::LayerProperties> > (&std::vector<db::LayerProperties>::begin, &std::vector<db::LayerProperties>::end, &std::vector<db::LayerProperties>::push_back, "layout-layer", lay::LayoutLayerConverter ())
|
||||
) +
|
||||
tl::make_member (&GerberImportData::mounting, "mounting", MountingConverter ()) +
|
||||
tl::make_member (&GerberImportData::num_metal_layers, "num-metal-layers") +
|
||||
tl::make_member (&GerberImportData::num_via_types, "num-via-types") +
|
||||
tl::make_element (&GerberImportData::artwork_files, "artwork-files",
|
||||
tl::make_element<GerberArtworkFileDescriptor, std::vector<GerberArtworkFileDescriptor>::const_iterator, std::vector<GerberArtworkFileDescriptor> > (&std::vector<GerberArtworkFileDescriptor>::begin, &std::vector<GerberArtworkFileDescriptor>::end, &std::vector<GerberArtworkFileDescriptor>::push_back, "artwork-file",
|
||||
tl::make_member (&GerberArtworkFileDescriptor::filename, "filename")
|
||||
)
|
||||
) +
|
||||
tl::make_element (&GerberImportData::drill_files, "drill-files",
|
||||
tl::make_element<GerberDrillFileDescriptor, std::vector<GerberDrillFileDescriptor>::const_iterator, std::vector<GerberDrillFileDescriptor> > (&std::vector<GerberDrillFileDescriptor>::begin, &std::vector<GerberDrillFileDescriptor>::end, &std::vector<GerberDrillFileDescriptor>::push_back, "drill-file",
|
||||
tl::make_member (&GerberDrillFileDescriptor::start, "start") +
|
||||
tl::make_member (&GerberDrillFileDescriptor::stop, "stop") +
|
||||
tl::make_member (&GerberDrillFileDescriptor::filename, "filename")
|
||||
)
|
||||
) +
|
||||
tl::make_element (&GerberImportData::free_files, "free-files",
|
||||
tl::make_element<GerberFreeFileDescriptor, std::vector<GerberFreeFileDescriptor>::const_iterator, std::vector<GerberFreeFileDescriptor> > (&std::vector<GerberFreeFileDescriptor>::begin, &std::vector<GerberFreeFileDescriptor>::end, &std::vector<GerberFreeFileDescriptor>::push_back, "free-file",
|
||||
tl::make_member (&GerberFreeFileDescriptor::filename, "filename") +
|
||||
tl::make_element (&GerberFreeFileDescriptor::layout_layers, "layout-layers",
|
||||
tl::make_member<int, std::vector<int>::const_iterator, std::vector<int> > (&std::vector<int>::begin, &std::vector<int>::end, &std::vector<int>::push_back, "index")
|
||||
)
|
||||
)
|
||||
) +
|
||||
tl::make_element (&GerberImportData::reference_points, "reference-points",
|
||||
tl::make_element<std::pair <db::DPoint, db::DPoint>, std::vector<std::pair <db::DPoint, db::DPoint> >::const_iterator, std::vector<std::pair <db::DPoint, db::DPoint> > > (&std::vector<std::pair <db::DPoint, db::DPoint> >::begin, &std::vector<std::pair <db::DPoint, db::DPoint> >::end, &std::vector<std::pair <db::DPoint, db::DPoint> >::push_back, "reference-point",
|
||||
tl::make_member (&std::pair <db::DPoint, db::DPoint>::first, "pcb", lay::PointConverter<db::DPoint> ()) +
|
||||
tl::make_member (&std::pair <db::DPoint, db::DPoint>::second, "layout", lay::PointConverter<db::DPoint> ())
|
||||
)
|
||||
) +
|
||||
tl::make_member (&GerberImportData::explicit_trans, "explicit-trans", lay::TransformationConverter<db::DCplxTrans> ()) +
|
||||
tl::make_member (&GerberImportData::layer_properties_file, "layer-properties-file") +
|
||||
tl::make_member (&GerberImportData::num_circle_points, "num-circle-points") +
|
||||
tl::make_member (&GerberImportData::merge_flag, "merge-flag") +
|
||||
tl::make_member (&GerberImportData::dbu, "dbu") +
|
||||
tl::make_member (&GerberImportData::topcell_name, "cell-name")
|
||||
);
|
||||
|
||||
void
|
||||
GerberImportData::load (const std::string &file)
|
||||
{
|
||||
reset ();
|
||||
current_file = file;
|
||||
tl::XMLFileSource in (file);
|
||||
pcb_project_structure.parse (in, *this);
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::load (tl::InputStream &stream)
|
||||
{
|
||||
reset ();
|
||||
current_file = std::string ();
|
||||
tl::XMLStreamSource in (stream);
|
||||
pcb_project_structure.parse (in, *this);
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::save (const std::string &file)
|
||||
{
|
||||
tl::OutputStream os (file, tl::OutputStream::OM_Plain);
|
||||
pcb_project_structure.write (os, *this);
|
||||
current_file = file;
|
||||
}
|
||||
|
||||
void
|
||||
GerberImportData::from_string (const std::string &s)
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
while (! ex.at_end ()) {
|
||||
|
||||
if (ex.test ("free-layer-mapping")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (free_layer_mapping);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("invert-negative-layers")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (invert_negative_layers);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("border")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (border);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("import-mode")) {
|
||||
|
||||
ex.test ("=");
|
||||
int m = 0;
|
||||
ex.read (m);
|
||||
mode = (mode_type) m;
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("base-dir")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read_word_or_quoted (base_dir);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("layout-layers")) {
|
||||
|
||||
ex.test ("=");
|
||||
layout_layers.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
layout_layers.push_back (db::LayerProperties ());
|
||||
layout_layers.back ().read (ex);
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("mounting")) {
|
||||
|
||||
ex.test ("=");
|
||||
std::string m;
|
||||
ex.read_word (m);
|
||||
mounting = (m == "top") ? MountingTop : MountingBottom;
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("num-metal-layers")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (num_metal_layers);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("num-via-types")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (num_via_types);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("artwork-files")) {
|
||||
|
||||
ex.test ("=");
|
||||
artwork_files.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
ex.test ("(");
|
||||
artwork_files.push_back (lay::GerberArtworkFileDescriptor ());
|
||||
ex.read_word_or_quoted (artwork_files.back ().filename);
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("drill-files")) {
|
||||
|
||||
ex.test ("=");
|
||||
drill_files.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
ex.test ("(");
|
||||
drill_files.push_back (lay::GerberDrillFileDescriptor ());
|
||||
ex.read (drill_files.back ().start);
|
||||
ex.test (",");
|
||||
ex.read (drill_files.back ().stop);
|
||||
ex.test (",");
|
||||
ex.read_word_or_quoted (drill_files.back ().filename);
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("free-files")) {
|
||||
|
||||
ex.test ("=");
|
||||
free_files.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
ex.test ("(");
|
||||
free_files.push_back (lay::GerberFreeFileDescriptor ());
|
||||
ex.read_word_or_quoted (free_files.back ().filename);
|
||||
ex.test (",");
|
||||
while (! ex.test (")") && ! ex.at_end ()) {
|
||||
int i = -1;
|
||||
ex.read (i);
|
||||
free_files.back ().layout_layers.push_back (i);
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (",");
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("reference-points")) {
|
||||
|
||||
ex.test ("=");
|
||||
reference_points.clear ();
|
||||
while (! ex.test (";") && ! ex.at_end ()) {
|
||||
double x1, y1, x2, y2;
|
||||
ex.test ("(");
|
||||
ex.test ("(");
|
||||
ex.read (x1);
|
||||
ex.test (",");
|
||||
ex.read (y1);
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
ex.test ("(");
|
||||
ex.read (x2);
|
||||
ex.test (",");
|
||||
ex.read (y2);
|
||||
ex.test (")");
|
||||
ex.test (")");
|
||||
ex.test (",");
|
||||
reference_points.push_back (std::make_pair (db::DPoint (x1, y1), db::DPoint (x2, y2)));
|
||||
}
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("explicit-trans")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (explicit_trans);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("layer-properties-file")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read_word_or_quoted (layer_properties_file);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("num-circle-points")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (num_circle_points);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("merge-flag")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (merge_flag);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("dbu")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read (dbu);
|
||||
ex.test (";");
|
||||
|
||||
} else if (ex.test ("cell-name")) {
|
||||
|
||||
ex.test ("=");
|
||||
ex.read_word_or_quoted (topcell_name);
|
||||
ex.test (";");
|
||||
|
||||
} else {
|
||||
ex.expect_end ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
GerberImportData::to_string () const
|
||||
{
|
||||
std::string s;
|
||||
s += "free-layer-mapping=" + tl::to_string(free_layer_mapping) + ";";
|
||||
s += "import-mode=" + tl::to_string(int (mode)) + ";";
|
||||
s += "base-dir=" + tl::to_quoted_string (base_dir) + ";";
|
||||
s += "invert-negative-layers=" + tl::to_string (invert_negative_layers) + ";";
|
||||
s += "border=" + tl::to_string (border) + ";";
|
||||
|
||||
s += "layout-layers=";
|
||||
for (std::vector <db::LayerProperties>::const_iterator ll = layout_layers.begin (); ll != layout_layers.end (); ++ll) {
|
||||
if (ll != layout_layers.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += ll->to_string ();
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "mounting=" + std::string (mounting == MountingTop ? "top" : "bottom") + ";";
|
||||
s += "num-metal-layers=" + tl::to_string (num_metal_layers) + ";";
|
||||
s += "num-via-types=" + tl::to_string (num_via_types) + ";";
|
||||
|
||||
s += "artwork-files=";
|
||||
for (std::vector <GerberArtworkFileDescriptor>::const_iterator f = artwork_files.begin (); f != artwork_files.end (); ++f) {
|
||||
if (f != artwork_files.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "(" + tl::to_quoted_string (f->filename) + ")";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "drill-files=";
|
||||
for (std::vector <GerberDrillFileDescriptor>::const_iterator f = drill_files.begin (); f != drill_files.end (); ++f) {
|
||||
if (f != drill_files.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "(" + tl::to_string (f->start) + "," + tl::to_string (f->stop) + "," + tl::to_quoted_string (f->filename) + ")";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "free-files=";
|
||||
for (std::vector <GerberFreeFileDescriptor>::const_iterator f = free_files.begin (); f != free_files.end (); ++f) {
|
||||
if (f != free_files.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "(" + tl::to_quoted_string (f->filename);
|
||||
for (std::vector <int>::const_iterator i = f->layout_layers.begin (); i != f->layout_layers.end (); ++i) {
|
||||
s += "," + tl::to_string (*i);
|
||||
}
|
||||
s += ")";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "reference-points=";
|
||||
for (std::vector <std::pair <db::DPoint, db::DPoint> >::const_iterator rp = reference_points.begin (); rp != reference_points.end (); ++rp) {
|
||||
if (rp != reference_points.begin ()) {
|
||||
s += ",";
|
||||
}
|
||||
s += "((" + tl::to_string (rp->first.x ()) + "," + tl::to_string (rp->first.y ()) + "),("
|
||||
+ tl::to_string (rp->second.x ()) + "," + tl::to_string (rp->second.y ()) + "))";
|
||||
}
|
||||
s += ";";
|
||||
|
||||
s += "explicit-trans=" + explicit_trans.to_string () + ";";
|
||||
s += "layer-properties-file=" + tl::to_quoted_string (layer_properties_file) + ";";
|
||||
s += "num-circle-points=" + tl::to_string (num_circle_points) + ";";
|
||||
s += "merge-flag=" + tl::to_string (merge_flag) + ";";
|
||||
s += "dbu=" + tl::to_string (dbu) + ";";
|
||||
s += "cell-name=" + tl::to_quoted_string (topcell_name) + ";";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// GerberImportDialogFileColumnEditorWidget implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "dbLayout.h"
|
||||
#include "dbPoint.h"
|
||||
#include "dbTrans.h"
|
||||
#include "dbGerberImportData.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -60,65 +61,6 @@ namespace db
|
|||
namespace lay
|
||||
{
|
||||
|
||||
struct GerberArtworkFileDescriptor
|
||||
{
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
struct GerberDrillFileDescriptor
|
||||
{
|
||||
GerberDrillFileDescriptor () : start (-1), stop (-1) { }
|
||||
|
||||
int start;
|
||||
int stop;
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
struct GerberFreeFileDescriptor
|
||||
{
|
||||
std::string filename;
|
||||
std::vector<int> layout_layers;
|
||||
};
|
||||
|
||||
struct GerberImportData
|
||||
{
|
||||
public:
|
||||
GerberImportData ();
|
||||
|
||||
enum mode_type { ModeIntoLayout = 0, ModeSamePanel, ModeNewPanel };
|
||||
enum mounting_type { MountingTop = 0, MountingBottom };
|
||||
|
||||
bool invert_negative_layers;
|
||||
double border;
|
||||
bool free_layer_mapping;
|
||||
mode_type mode;
|
||||
std::string base_dir;
|
||||
std::string current_file;
|
||||
std::vector <db::LayerProperties> layout_layers;
|
||||
mounting_type mounting;
|
||||
int num_metal_layers;
|
||||
int num_via_types;
|
||||
std::vector <GerberArtworkFileDescriptor> artwork_files;
|
||||
std::vector <GerberDrillFileDescriptor> drill_files;
|
||||
std::vector <GerberFreeFileDescriptor> free_files;
|
||||
std::vector <std::pair <db::DPoint, db::DPoint> > reference_points;
|
||||
db::DCplxTrans explicit_trans;
|
||||
std::string layer_properties_file;
|
||||
int num_circle_points;
|
||||
bool merge_flag;
|
||||
double dbu;
|
||||
std::string topcell_name;
|
||||
|
||||
std::string get_layer_properties_file () const;
|
||||
void setup_importer (db::GerberImporter *importer);
|
||||
void reset ();
|
||||
void load (tl::InputStream &stream);
|
||||
void load (const std::string &file);
|
||||
void save (const std::string &file);
|
||||
void from_string (const std::string &s);
|
||||
std::string to_string () const;
|
||||
};
|
||||
|
||||
// The item editor for the file column
|
||||
class GerberImportDialogFileColumnEditorWidget
|
||||
: public QFrame
|
||||
|
|
|
|||
|
|
@ -0,0 +1,203 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
|
||||
// this software, either in source code form or as a compiled binary, for any
|
||||
// purpose, commercial or non-commercial, and by any means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors of
|
||||
// this software dedicate any and all copyright interest in the software to the
|
||||
// public domain. We make this dedication for the benefit of the public at
|
||||
// large and to the detriment of our heirs and successors. We intend this
|
||||
// dedication to be an overt act of relinquishment in perpetuity of all present
|
||||
// and future rights to this software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ATOMIC_ATOMIC_H_
|
||||
#define ATOMIC_ATOMIC_H_
|
||||
|
||||
// Macro for disallowing copying of an object.
|
||||
#if __cplusplus >= 201103L
|
||||
#define ATOMIC_DISALLOW_COPY(T) \
|
||||
T(const T&) = delete; \
|
||||
T& operator=(const T&) = delete;
|
||||
#else
|
||||
#define ATOMIC_DISALLOW_COPY(T) \
|
||||
T(const T&); \
|
||||
T& operator=(const T&);
|
||||
#endif
|
||||
|
||||
// A portable static assert.
|
||||
#if __cplusplus >= 201103L
|
||||
#define ATOMIC_STATIC_ASSERT(condition, message) \
|
||||
static_assert((condition), message)
|
||||
#else
|
||||
// Based on: http://stackoverflow.com/a/809465/5778708
|
||||
#define ATOMIC_STATIC_ASSERT(condition, message) \
|
||||
_impl_STATIC_ASSERT_LINE(condition, __LINE__)
|
||||
#define _impl_PASTE(a, b) a##b
|
||||
#ifdef __GNUC__
|
||||
#define _impl_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define _impl_UNUSED
|
||||
#endif
|
||||
#define _impl_STATIC_ASSERT_LINE(condition, line) \
|
||||
typedef char _impl_PASTE( \
|
||||
STATIC_ASSERT_failed_, \
|
||||
line)[(2 * static_cast<int>(!!(condition))) - 1] _impl_UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__) || defined(__xlc__)
|
||||
#define ATOMIC_USE_GCC_INTRINSICS
|
||||
#elif defined(_MSC_VER)
|
||||
#define ATOMIC_USE_MSVC_INTRINSICS
|
||||
#include "atomic_msvc.h"
|
||||
#elif __cplusplus >= 201103L
|
||||
#define ATOMIC_USE_CPP11_ATOMIC
|
||||
#include <atomic>
|
||||
#else
|
||||
#error Unsupported compiler / system.
|
||||
#endif
|
||||
|
||||
namespace atomic {
|
||||
template <typename T>
|
||||
class atomic {
|
||||
public:
|
||||
ATOMIC_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 ||
|
||||
sizeof(T) == 8,
|
||||
"Only types of size 1, 2, 4 or 8 are supported");
|
||||
|
||||
atomic() : value_(static_cast<T>(0)) {}
|
||||
|
||||
explicit atomic(const T value) : value_(value) {}
|
||||
|
||||
/// @brief Performs an atomic increment operation (value + 1).
|
||||
/// @returns The new value of the atomic object.
|
||||
T operator++() {
|
||||
#if defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_add_fetch(&value_, 1, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
return msvc::interlocked<T>::increment(&value_);
|
||||
#else
|
||||
return ++value_;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic decrement operation (value - 1).
|
||||
/// @returns The new value of the atomic object.
|
||||
T operator--() {
|
||||
#if defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_sub_fetch(&value_, 1, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
return msvc::interlocked<T>::decrement(&value_);
|
||||
#else
|
||||
return --value_;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic compare-and-swap (CAS) operation.
|
||||
///
|
||||
/// The value of the atomic object is only updated to the new value if the
|
||||
/// old value of the atomic object matches @c expected_val.
|
||||
///
|
||||
/// @param expected_val The expected value of the atomic object.
|
||||
/// @param new_val The new value to write to the atomic object.
|
||||
/// @returns True if new_value was written to the atomic object.
|
||||
bool compare_exchange(const T expected_val, const T new_val) {
|
||||
#if defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
T e = expected_val;
|
||||
return __atomic_compare_exchange_n(
|
||||
&value_, &e, new_val, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
const T old_val =
|
||||
msvc::interlocked<T>::compare_exchange(&value_, new_val, expected_val);
|
||||
return (old_val == expected_val);
|
||||
#else
|
||||
T e = expected_val;
|
||||
return value_.compare_exchange_weak(e, new_val);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic set operation.
|
||||
///
|
||||
/// The value of the atomic object is unconditionally updated to the new
|
||||
/// value.
|
||||
///
|
||||
/// @param new_val The new value to write to the atomic object.
|
||||
void store(const T new_val) {
|
||||
#if defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
__atomic_store_n(&value_, new_val, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
(void)msvc::interlocked<T>::exchange(&value_, new_val);
|
||||
#else
|
||||
value_.store(new_val);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @returns the current value of the atomic object.
|
||||
/// @note Be careful about how this is used, since any operations on the
|
||||
/// returned value are inherently non-atomic.
|
||||
T load() const {
|
||||
#if defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_load_n(&value_, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
// TODO(m): Is there a better solution for MSVC?
|
||||
return value_;
|
||||
#else
|
||||
return value_;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Performs an atomic exchange operation.
|
||||
///
|
||||
/// The value of the atomic object is unconditionally updated to the new
|
||||
/// value, and the old value is returned.
|
||||
///
|
||||
/// @param new_val The new value to write to the atomic object.
|
||||
/// @returns the old value.
|
||||
T exchange(const T new_val) {
|
||||
#if defined(ATOMIC_USE_GCC_INTRINSICS)
|
||||
return __atomic_exchange_n(&value_, new_val, __ATOMIC_SEQ_CST);
|
||||
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
return msvc::interlocked<T>::exchange(&value_, new_val);
|
||||
#else
|
||||
return value_.exchange(new_val);
|
||||
#endif
|
||||
}
|
||||
|
||||
T operator=(const T new_value) {
|
||||
store(new_value);
|
||||
return new_value;
|
||||
}
|
||||
|
||||
operator T() const {
|
||||
return load();
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(ATOMIC_USE_GCC_INTRINSICS) || defined(ATOMIC_USE_MSVC_INTRINSICS)
|
||||
volatile T value_;
|
||||
#else
|
||||
std::atomic<T> value_;
|
||||
#endif
|
||||
|
||||
ATOMIC_DISALLOW_COPY(atomic)
|
||||
};
|
||||
|
||||
} // namespace atomic
|
||||
|
||||
// Undef temporary defines.
|
||||
#undef ATOMIC_USE_GCC_INTRINSICS
|
||||
#undef ATOMIC_USE_MSVC_INTRINSICS
|
||||
#undef ATOMIC_USE_CPP11_ATOMIC
|
||||
|
||||
#endif // ATOMIC_ATOMIC_H_
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
|
||||
// this software, either in source code form or as a compiled binary, for any
|
||||
// purpose, commercial or non-commercial, and by any means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors of
|
||||
// this software dedicate any and all copyright interest in the software to the
|
||||
// public domain. We make this dedication for the benefit of the public at
|
||||
// large and to the detriment of our heirs and successors. We intend this
|
||||
// dedication to be an overt act of relinquishment in perpetuity of all present
|
||||
// and future rights to this software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ATOMIC_ATOMIC_MSVC_H_
|
||||
#define ATOMIC_ATOMIC_MSVC_H_
|
||||
|
||||
// Define which functions we need (don't include <intrin.h>).
|
||||
extern "C" {
|
||||
short _InterlockedIncrement16(short volatile*);
|
||||
long _InterlockedIncrement(long volatile*);
|
||||
__int64 _InterlockedIncrement64(__int64 volatile*);
|
||||
|
||||
short _InterlockedDecrement16(short volatile*);
|
||||
long _InterlockedDecrement(long volatile*);
|
||||
__int64 _InterlockedDecrement64(__int64 volatile*);
|
||||
|
||||
char _InterlockedExchange8(char volatile*, char);
|
||||
short _InterlockedExchange16(short volatile*, short);
|
||||
long __cdecl _InterlockedExchange(long volatile*, long);
|
||||
__int64 _InterlockedExchange64(__int64 volatile*, __int64);
|
||||
|
||||
char _InterlockedCompareExchange8(char volatile*, char, char);
|
||||
short _InterlockedCompareExchange16(short volatile*, short, short);
|
||||
long __cdecl _InterlockedCompareExchange(long volatile*, long, long);
|
||||
__int64 _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64);
|
||||
};
|
||||
|
||||
// Define which functions we want to use as inline intriniscs.
|
||||
#pragma intrinsic(_InterlockedIncrement)
|
||||
#pragma intrinsic(_InterlockedIncrement16)
|
||||
|
||||
#pragma intrinsic(_InterlockedDecrement)
|
||||
#pragma intrinsic(_InterlockedDecrement16)
|
||||
|
||||
#pragma intrinsic(_InterlockedCompareExchange)
|
||||
#pragma intrinsic(_InterlockedCompareExchange8)
|
||||
#pragma intrinsic(_InterlockedCompareExchange16)
|
||||
|
||||
#pragma intrinsic(_InterlockedExchange)
|
||||
#pragma intrinsic(_InterlockedExchange8)
|
||||
#pragma intrinsic(_InterlockedExchange16)
|
||||
|
||||
#if defined(_M_X64)
|
||||
#pragma intrinsic(_InterlockedIncrement64)
|
||||
#pragma intrinsic(_InterlockedDecrement64)
|
||||
#pragma intrinsic(_InterlockedCompareExchange64)
|
||||
#pragma intrinsic(_InterlockedExchange64)
|
||||
#endif // _M_X64
|
||||
|
||||
namespace atomic {
|
||||
namespace msvc {
|
||||
template <typename T, size_t N = sizeof(T)>
|
||||
struct interlocked {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 1> {
|
||||
static inline T increment(T volatile* x) {
|
||||
// There's no _InterlockedIncrement8().
|
||||
char old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<char>(*x);
|
||||
new_val = old_val + static_cast<char>(1);
|
||||
} while (_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
|
||||
new_val,
|
||||
old_val) != old_val);
|
||||
return static_cast<T>(new_val);
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
// There's no _InterlockedDecrement8().
|
||||
char old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<char>(*x);
|
||||
new_val = old_val - static_cast<char>(1);
|
||||
} while (_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
|
||||
new_val,
|
||||
old_val) != old_val);
|
||||
return static_cast<T>(new_val);
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
|
||||
static_cast<const char>(new_val),
|
||||
static_cast<const char>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
return static_cast<T>(_InterlockedExchange8(
|
||||
reinterpret_cast<volatile char*>(x), static_cast<const char>(new_val)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 2> {
|
||||
static inline T increment(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedIncrement16(reinterpret_cast<volatile short*>(x)));
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedDecrement16(reinterpret_cast<volatile short*>(x)));
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(x),
|
||||
static_cast<const short>(new_val),
|
||||
static_cast<const short>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedExchange16(reinterpret_cast<volatile short*>(x),
|
||||
static_cast<const short>(new_val)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 4> {
|
||||
static inline T increment(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedIncrement(reinterpret_cast<volatile long*>(x)));
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
return static_cast<T>(
|
||||
_InterlockedDecrement(reinterpret_cast<volatile long*>(x)));
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(
|
||||
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(x),
|
||||
static_cast<const long>(new_val),
|
||||
static_cast<const long>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
return static_cast<T>(_InterlockedExchange(
|
||||
reinterpret_cast<volatile long*>(x), static_cast<const long>(new_val)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct interlocked<T, 8> {
|
||||
static inline T increment(T volatile* x) {
|
||||
#if defined(_M_X64)
|
||||
return static_cast<T>(
|
||||
_InterlockedIncrement64(reinterpret_cast<volatile __int64*>(x)));
|
||||
#else
|
||||
// There's no _InterlockedIncrement64() for 32-bit x86.
|
||||
__int64 old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<__int64>(*x);
|
||||
new_val = old_val + static_cast<__int64>(1);
|
||||
} while (_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
|
||||
old_val);
|
||||
return static_cast<T>(new_val);
|
||||
#endif // _M_X64
|
||||
}
|
||||
|
||||
static inline T decrement(T volatile* x) {
|
||||
#if defined(_M_X64)
|
||||
return static_cast<T>(
|
||||
_InterlockedDecrement64(reinterpret_cast<volatile __int64*>(x)));
|
||||
#else
|
||||
// There's no _InterlockedDecrement64() for 32-bit x86.
|
||||
__int64 old_val, new_val;
|
||||
do {
|
||||
old_val = static_cast<__int64>(*x);
|
||||
new_val = old_val - static_cast<__int64>(1);
|
||||
} while (_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
|
||||
old_val);
|
||||
return static_cast<T>(new_val);
|
||||
#endif // _M_X64
|
||||
}
|
||||
|
||||
static inline T compare_exchange(T volatile* x,
|
||||
const T new_val,
|
||||
const T expected_val) {
|
||||
return static_cast<T>(_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x),
|
||||
static_cast<const __int64>(new_val),
|
||||
static_cast<const __int64>(expected_val)));
|
||||
}
|
||||
|
||||
static inline T exchange(T volatile* x, const T new_val) {
|
||||
#if defined(_M_X64)
|
||||
return static_cast<T>(
|
||||
_InterlockedExchange64(reinterpret_cast<volatile __int64*>(x),
|
||||
static_cast<const __int64>(new_val)));
|
||||
#else
|
||||
// There's no _InterlockedExchange64 for 32-bit x86.
|
||||
__int64 old_val;
|
||||
do {
|
||||
old_val = static_cast<__int64>(*x);
|
||||
} while (_InterlockedCompareExchange64(
|
||||
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
|
||||
old_val);
|
||||
return static_cast<T>(old_val);
|
||||
#endif // _M_X64
|
||||
}
|
||||
};
|
||||
} // namespace msvc
|
||||
} // namespace atomic
|
||||
|
||||
#endif // ATOMIC_ATOMIC_MSVC_H_
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
|
||||
// this software, either in source code form or as a compiled binary, for any
|
||||
// purpose, commercial or non-commercial, and by any means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors of
|
||||
// this software dedicate any and all copyright interest in the software to the
|
||||
// public domain. We make this dedication for the benefit of the public at
|
||||
// large and to the detriment of our heirs and successors. We intend this
|
||||
// dedication to be an overt act of relinquishment in perpetuity of all present
|
||||
// and future rights to this software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org/>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ATOMIC_SPINLOCK_H_
|
||||
#define ATOMIC_SPINLOCK_H_
|
||||
|
||||
#include "atomic/atomic.h"
|
||||
|
||||
namespace atomic {
|
||||
class spinlock {
|
||||
public:
|
||||
spinlock() : value_(0) {}
|
||||
|
||||
/// @brief Acquire the lock (blocking).
|
||||
/// @note Trying to acquire a lock that is already held by the calling thread
|
||||
/// will dead-lock (block indefinitely).
|
||||
void lock() {
|
||||
while (!value_.compare_exchange(UNLOCKED, LOCKED))
|
||||
;
|
||||
}
|
||||
|
||||
/// @brief Release the lock.
|
||||
/// @note It is an error to release a lock that has not been previously
|
||||
/// acquired.
|
||||
void unlock() { value_.store(UNLOCKED); }
|
||||
|
||||
private:
|
||||
static const int UNLOCKED = 0;
|
||||
static const int LOCKED = 1;
|
||||
|
||||
atomic<int> value_;
|
||||
|
||||
ATOMIC_DISALLOW_COPY(spinlock)
|
||||
};
|
||||
|
||||
class lock_guard {
|
||||
public:
|
||||
/// @brief The constructor acquires the lock.
|
||||
/// @param lock The spinlock that will be locked.
|
||||
explicit lock_guard(spinlock& lock) : lock_(lock) {
|
||||
lock_.lock();
|
||||
}
|
||||
|
||||
/// @brief The destructor releases the lock.
|
||||
~lock_guard() {
|
||||
lock_.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
spinlock& lock_;
|
||||
|
||||
ATOMIC_DISALLOW_COPY(lock_guard)
|
||||
};
|
||||
|
||||
} // namespace atomic
|
||||
|
||||
#endif // ATOMIC_SPINLOCK_H_
|
||||
Loading…
Reference in New Issue