WIP: keep DXF and CIF layer names, DXF contour accuracy.

This commit is contained in:
Matthias Koefferlein 2018-04-16 00:55:57 +02:00
parent 1b0317c120
commit 085a2ee2b1
4 changed files with 393 additions and 209 deletions

View File

@ -138,6 +138,11 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd)
"This option specifies the database unit the resulting layer will have. "
"The value is given in micrometer units. The default value is 1nm (0.001)."
)
<< tl::arg (group +
"#--" + m_long_prefix + "keep-layer-names", &GenericReaderOptions::set_read_named_layers, "Keeps layer names",
"If this option is used, layers names are kept as pure names and no attempt is made to\n"
"translate them into GDS layer/datatypes."
)
;
}
@ -197,6 +202,11 @@ GenericReaderOptions::add_options (tl::CommandLineOptions &cmd)
"\n"
"The value is given in the units of the DXF file."
)
<< tl::arg (group +
"#--" + m_long_prefix + "dxf-contour-accuracy=value", &m_dxf_reader_options.contour_accuracy, "Specifies the point accuracy for contour closing",
"This value specifies the distance (in units of the DXF file) by which points can be separated and still\n"
"be considered to be connected. This value is effective in polyline mode 3 and 4.\n"
)
<< tl::arg (group +
"#--" + m_long_prefix + "dxf-render-texts-as-polygons", &m_dxf_reader_options.render_texts_as_polygons, "Renders texts as polygons",
"If this option is used, texts are converted to polygons instead of being converted to labels."
@ -222,6 +232,12 @@ void GenericReaderOptions::set_layer_map (const std::string &lm)
}
}
void GenericReaderOptions::set_read_named_layers (bool f)
{
m_dxf_reader_options.read_named_layers = f;
m_cif_reader_options.read_named_layers = f;
}
void GenericReaderOptions::set_dbu (double dbu)
{
m_dxf_reader_options.dbu = dbu;

View File

@ -101,6 +101,7 @@ private:
std::string m_prefix, m_long_prefix, m_group_prefix;
db::LayerMap m_layer_map;
bool m_create_other_layers;
bool m_read_named_layers;
db::CommonReaderOptions m_common_reader_options;
db::GDS2ReaderOptions m_gds2_reader_options;
db::OASISReaderOptions m_oasis_reader_options;
@ -109,6 +110,7 @@ private:
void set_layer_map (const std::string &lm);
void set_dbu (double dbu);
void set_read_named_layers (bool f);
};
}

View File

@ -50,6 +50,237 @@
namespace db
{
// ---------------------------------------------------------------
// NamedLayerReader
NamedLayerReader::NamedLayerReader ()
: m_create_layers (true), m_read_named_layers (false), m_next_layer_index (0)
{
// .. nothing yet ..
}
void
NamedLayerReader::set_create_layers (bool f)
{
m_create_layers = f;
}
void
NamedLayerReader::set_read_named_layers (bool f)
{
m_read_named_layers = f;
}
void NamedLayerReader::set_layer_map (const LayerMap &lm)
{
m_layer_map = lm;
}
static bool
extract_plain_layer (const char *s, int &l)
{
l = 0;
if (! *s) {
return false;
}
while (*s && isdigit (*s)) {
l = l * 10 + (unsigned int) (*s - '0');
++s;
}
return (*s == 0);
}
static bool
extract_ld (const char *s, int &l, int &d, std::string &n)
{
l = d = 0;
if (*s == 'L') {
++s;
}
if (! *s || ! isdigit (*s)) {
return false;
}
while (*s && isdigit (*s)) {
l = l * 10 + (unsigned int) (*s - '0');
++s;
}
if (*s == 'D' || *s == '.') {
++s;
if (! *s || ! isdigit (*s)) {
return false;
}
while (*s && isdigit (*s)) {
d = d * 10 + (unsigned int) (*s - '0');
++s;
}
}
if (*s && (isspace (*s) || *s == '_')) {
++s;
n = s;
return true;
} else if (*s == 0) {
n.clear ();
return true;
} else {
return false;
}
}
std::pair <bool, unsigned int>
NamedLayerReader::open_layer (db::Layout &layout, const std::string &n)
{
int l = -1, d = -1;
std::string on;
std::pair<bool, unsigned int> ll (false, 0);
ll = m_layer_map.logical (n);
if (! ll.first && !m_read_named_layers) {
if (extract_plain_layer (n.c_str (), l)) {
db::LayerProperties lp;
lp.layer = l;
lp.datatype = 0;
ll = m_layer_map.logical (lp);
} else if (extract_ld (n.c_str (), l, d, on)) {
db::LayerProperties lp;
lp.layer = l;
lp.datatype = d;
lp.name = on;
ll = m_layer_map.logical (lp);
}
}
if (ll.first) {
// create the layer if it is not part of the layout yet.
if (! layout.is_valid_layer (ll.second)) {
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
}
return ll;
} else if (! m_create_layers) {
return std::pair<bool, unsigned int> (false, 0);
} else {
std::map <std::string, unsigned int>::const_iterator nl = m_new_layers.find (n);
if (nl == m_new_layers.end ()) {
unsigned int ll = m_next_layer_index++;
layout.insert_layer (ll, db::LayerProperties ());
m_new_layers.insert (std::make_pair (n, ll));
return std::pair<bool, unsigned int> (true, ll);
} else {
return std::pair<bool, unsigned int> (true, nl->second);
}
}
}
void
NamedLayerReader::map_layer (const std::string &name, unsigned int layer)
{
m_layer_map.map (name, layer);
}
void
NamedLayerReader::prepare_layers ()
{
m_new_layers.clear ();
m_next_layer_index = m_layer_map.next_index ();
}
void
NamedLayerReader::finish_layers (db::Layout &layout)
{
// assign layer numbers to new layers
if (! m_new_layers.empty () && !m_read_named_layers) {
std::set<std::pair<int, int> > used_ld;
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
used_ld.insert (std::make_pair((*l).second->layer, (*l).second->datatype));
}
// assign fixed layer numbers for all layers whose name is a fixed number unless there is already a layer with that number
for (std::map<std::string, unsigned int>::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) {
std::map<std::string, unsigned int>::iterator ii = i;
++ii;
int l = -1;
if (extract_plain_layer (i->first.c_str (), l) && used_ld.find (std::make_pair (l, 0)) == used_ld.end ()) {
used_ld.insert (std::make_pair (l, 0));
db::LayerProperties lp;
lp.layer = l;
lp.datatype = 0;
layout.set_properties (i->second, lp);
m_layer_map.map (lp, i->second);
m_new_layers.erase (i);
}
i = ii;
}
// assign fixed layer numbers for all layers whose name is a LxDy or Lx notation unless there is already a layer with that layer/datatype
for (std::map<std::string, unsigned int>::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) {
std::map<std::string, unsigned int>::iterator ii = i;
++ii;
int l = -1, d = -1;
std::string n;
if (extract_ld (i->first.c_str (), l, d, n) && used_ld.find (std::make_pair (l, d)) == used_ld.end ()) {
used_ld.insert (std::make_pair (l, d));
db::LayerProperties lp;
lp.layer = l;
lp.datatype = d;
lp.name = n;
layout.set_properties (i->second, lp);
m_layer_map.map (lp, i->second);
m_new_layers.erase (i);
}
i = ii;
}
}
// insert the remaining ones
for (std::map<std::string, unsigned int>::const_iterator i = m_new_layers.begin (); i != m_new_layers.end (); ++i) {
db::LayerProperties lp;
lp.name = i->first;
layout.set_properties (i->second, lp);
m_layer_map.map (lp, i->second);
}
}
// ---------------------------------------------------------------
// DXFReader
@ -57,11 +288,10 @@ static std::string zero_layer_name ("0");
DXFReader::DXFReader (tl::InputStream &s)
: m_stream (s),
m_create_layers (true),
m_progress (tl::to_string (QObject::tr ("Reading DXF file")), 1000),
m_dbu (0.001), m_unit (1.0), m_text_scaling (1.0), m_polyline_mode (0), m_circle_points (100), m_circle_accuracy (0.0),
m_dbu (0.001), m_unit (1.0), m_text_scaling (1.0), m_polyline_mode (0), m_circle_points (100), m_circle_accuracy (0.0), m_contour_accuracy (0.0),
m_ascii (false), m_initial (true), m_render_texts_as_polygons (false), m_keep_other_cells (false), m_line_number (0),
m_zero_layer (0), m_next_layer_index (0)
m_zero_layer (0)
{
m_progress.set_format (tl::to_string (QObject::tr ("%.0fk lines")));
m_progress.set_format_unit (1000.0);
@ -301,6 +531,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
m_polyline_mode = specific_options.polyline_mode;
m_circle_points = specific_options.circle_points;
m_circle_accuracy = specific_options.circle_accuracy;
m_contour_accuracy = specific_options.contour_accuracy;
m_render_texts_as_polygons = specific_options.render_texts_as_polygons;
m_keep_other_cells = specific_options.keep_other_cells;
@ -318,10 +549,11 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
m_stream.reset ();
m_initial = true;
m_line_number = 0;
m_layer_map = specific_options.layer_map;
m_layer_map.prepare (layout);
m_next_layer_index = 0;
m_create_layers = specific_options.create_other_layers;
db::LayerMap lm = specific_options.layer_map;
lm.prepare (layout);
set_layer_map (lm);
set_create_layers (specific_options.create_other_layers);
set_read_named_layers (specific_options.read_named_layers);
db::cell_index_type top = layout.add_cell("TOP"); // TODO: make variable ..
@ -329,7 +561,7 @@ DXFReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
do_read (layout, top);
cleanup (layout, top);
return m_layer_map;
return layer_map ();
}
const LayerMap &
@ -365,144 +597,29 @@ DXFReader::warn (const std::string &msg)
}
}
static bool
extract_plain_layer (const char *s, int &l)
{
l = 0;
if (! *s) {
return false;
}
while (*s && isdigit (*s)) {
l = l * 10 + (unsigned int) (*s - '0');
++s;
}
return (*s == 0);
}
static bool
extract_ld (const char *s, int &l, int &d, std::string &n)
{
l = d = 0;
if (*s == 'L') {
++s;
}
if (! *s || ! isdigit (*s)) {
return false;
}
while (*s && isdigit (*s)) {
l = l * 10 + (unsigned int) (*s - '0');
++s;
}
if (*s == 'D' || *s == '.') {
++s;
if (! *s || ! isdigit (*s)) {
return false;
}
while (*s && isdigit (*s)) {
d = d * 10 + (unsigned int) (*s - '0');
++s;
}
}
if (*s && (isspace (*s) || *s == '_')) {
++s;
n = s;
return true;
} else if (*s == 0) {
n.clear ();
return true;
} else {
return false;
}
}
std::pair <bool, unsigned int>
std::pair <bool, unsigned int>
DXFReader::open_layer (db::Layout &layout, const std::string &n)
{
std::string name (n);
int l = -1, d = -1;
std::string on;
std::pair<bool, unsigned int> ll (false, 0);
if (n == zero_layer_name) {
return std::make_pair (true, m_zero_layer);
}
ll = m_layer_map.logical (n);
if (! ll.first) {
if (extract_plain_layer (n.c_str (), l)) {
db::LayerProperties lp;
lp.layer = l;
lp.datatype = 0;
ll = m_layer_map.logical (lp);
} else if (extract_ld (n.c_str (), l, d, on)) {
db::LayerProperties lp;
lp.layer = l;
lp.datatype = d;
lp.name = on;
ll = m_layer_map.logical (lp);
}
}
if (ll.first) {
// create the layer if it is not part of the layout yet.
if (! layout.is_valid_layer (ll.second)) {
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
}
return ll;
} else if (! m_create_layers) {
return std::pair<bool, unsigned int> (false, 0);
} else {
std::map <std::string, unsigned int>::const_iterator nl = m_new_layers.find (n);
if (nl == m_new_layers.end ()) {
unsigned int ll = m_next_layer_index++;
layout.insert_layer (ll, db::LayerProperties ());
m_new_layers.insert (std::make_pair (n, ll));
return std::pair<bool, unsigned int> (true, ll);
} else {
return std::pair<bool, unsigned int> (true, nl->second);
}
return NamedLayerReader::open_layer (layout, n);
}
}
void
void
DXFReader::do_read (db::Layout &layout, db::cell_index_type top)
{
tl::SelfTimer timer (tl::verbosity () >= 21, "File read");
m_new_layers.clear ();
// create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as
// a layer named "0".
std::pair<bool, unsigned int> ll = m_layer_map.logical (zero_layer_name);
std::pair<bool, unsigned int> ll = layer_map ().logical (zero_layer_name);
if (ll.first) {
// create the layer if it is not part of the layout yet.
if (! layout.is_valid_layer (ll.second)) {
layout.insert_layer (ll.second, m_layer_map.mapping (ll.second));
layout.insert_layer (ll.second, layer_map ().mapping (ll.second));
}
m_zero_layer = ll.second;
@ -510,13 +627,13 @@ DXFReader::do_read (db::Layout &layout, db::cell_index_type top)
} else {
// or explicitly create the layer:
m_zero_layer = m_layer_map.next_index ();
m_zero_layer = layer_map ().next_index ();
layout.insert_layer (m_zero_layer, db::LayerProperties (0, 0, zero_layer_name));
m_layer_map.map (zero_layer_name, m_zero_layer);
map_layer (zero_layer_name, m_zero_layer);
}
m_next_layer_index = m_layer_map.next_index ();
prepare_layers ();
// Read sections
int g;
@ -630,76 +747,7 @@ DXFReader::do_read (db::Layout &layout, db::cell_index_type top)
}
// assign layer numbers to new layers
if (! m_new_layers.empty ()) {
std::set<std::pair<int, int> > used_ld;
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
used_ld.insert (std::make_pair((*l).second->layer, (*l).second->datatype));
}
// assign fixed layer numbers for all layers whose name is a fixed number unless there is already a layer with that number
for (std::map<std::string, unsigned int>::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) {
std::map<std::string, unsigned int>::iterator ii = i;
++ii;
int l = -1;
if (extract_plain_layer (i->first.c_str (), l) && used_ld.find (std::make_pair (l, 0)) == used_ld.end ()) {
used_ld.insert (std::make_pair (l, 0));
db::LayerProperties lp;
lp.layer = l;
lp.datatype = 0;
layout.set_properties (i->second, lp);
m_layer_map.map (lp, i->second);
m_new_layers.erase (i);
}
i = ii;
}
// assign fixed layer numbers for all layers whose name is a LxDy or Lx notation unless there is already a layer with that layer/datatype
for (std::map<std::string, unsigned int>::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) {
std::map<std::string, unsigned int>::iterator ii = i;
++ii;
int l = -1, d = -1;
std::string n;
if (extract_ld (i->first.c_str (), l, d, n) && used_ld.find (std::make_pair (l, d)) == used_ld.end ()) {
used_ld.insert (std::make_pair (l, d));
db::LayerProperties lp;
lp.layer = l;
lp.datatype = d;
lp.name = n;
layout.set_properties (i->second, lp);
m_layer_map.map (lp, i->second);
m_new_layers.erase (i);
}
i = ii;
}
// insert the remaining ones
for (std::map<std::string, unsigned int>::const_iterator i = m_new_layers.begin (); i != m_new_layers.end (); ++i) {
db::LayerProperties lp;
lp.name = i->first;
layout.set_properties (i->second, lp);
m_layer_map.map (lp, i->second);
}
}
finish_layers (layout);
}
void

View File

@ -62,9 +62,11 @@ public:
polyline_mode (0),
circle_points (100),
circle_accuracy (0.0),
contour_accuracy (0.0),
render_texts_as_polygons (false),
keep_other_cells (false),
create_other_layers (true)
create_other_layers (true),
read_named_layers (false)
{
// .. nothing yet ..
}
@ -128,6 +130,17 @@ public:
*/
double circle_accuracy;
/**
* @brief Accuracy for closing polylines
*
* When polylines need to be connected or closed, this
* value is used to indicate the accuracy. This is the value
* by while points may be separated and still be considered
* connected. The default is 0.0 which implies exact
* (within one DBU) closing.
*/
double contour_accuracy;
/**
* @brief If set to true, converts texts to polygons on read
*
@ -160,6 +173,14 @@ public:
*/
bool create_other_layers;
/**
* @brief A flag indicating whether the names of layers shall be read (maintained)
*
* Name translation will try to extract GDS layer/datatype numbers from the
* layer names. If this value is set to true, no name translation happens.
*/
bool read_named_layers;
/**
* @brief Implementation of FormatSpecificReaderOptions
*/
@ -194,11 +215,111 @@ public:
{ }
};
/**
* @brief A reader base class for streams with named-only layers
*
* This class implements the layer name translation logic.
* Specifically:
* - a number is translated to the corresponding layer, datatype 0
* - Lx is translated to layer x, datatype 0
* - Lx_SUFFIX is translated to layer x, datatype 0, name "SUFFIX"
* - LxDy is translated to layer x, datatype y
* - LxDy_SUFFIX is translated to layer x, datatype y, name "SUFFIX"
*
* Furthermore, the layer map and creation of new layers is handled in this
* base class.
*/
class DB_PUBLIC NamedLayerReader
: public ReaderBase
{
public:
/**
* @brief The constructor
*/
NamedLayerReader ();
/**
* @brief Sets a value indicating whether to create new layers
*/
void set_create_layers (bool f);
/**
* @brief Gets a value indicating whether to create new layers
*/
bool create_layers () const
{
return m_create_layers;
}
/**
* @brief Sets the layer map
*/
void set_layer_map (const LayerMap &lm);
/**
* @brief Gets the layer map
*/
const LayerMap &layer_map ()
{
return m_layer_map;
}
/**
* @brief Sets a value indicating whether layer names are kept
* If set to true, no name translation is performed and layers are
* always named only. If set the false (the default), layer names will
* be translated to GDS layer/datatypes if possible.
*/
void set_read_named_layers (bool f);
/**
* @brief Gets a value indicating whether layer names are kept
*/
bool read_named_layers () const
{
return m_read_named_layers;
}
protected:
/**
* @brief Opens a new layer
* This method will create or locate a layer for a given name.
* The result's first attribute is true, if such a layer could be found
* or created. In this case, the second attribute is the layer index.
*/
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name);
/**
* @brief Force mapping of a name to a layer index
*/
void map_layer (const std::string &name, unsigned int layer);
/**
* @brief Finish reading
* This method must be called after the reading has been done.
* It will finalize the layers.
*/
void finish_layers (db::Layout &layout);
/**
* @brief Prepares reading
* This method must be called before the reading is done.
*/
void prepare_layers ();
private:
bool m_create_layers;
bool m_read_named_layers;
LayerMap m_layer_map;
unsigned int m_next_layer_index;
std::map <std::string, unsigned int> m_new_layers;
};
/**
* @brief The DXF format stream reader
*/
class DB_PUBLIC DXFReader
: public ReaderBase,
: public NamedLayerReader,
public DXFDiagnostics
{
public:
@ -303,8 +424,6 @@ private:
};
tl::InputStream &m_stream;
bool m_create_layers;
LayerMap m_layer_map;
tl::AbsoluteProgress m_progress;
double m_dbu;
double m_unit;
@ -312,6 +431,7 @@ private:
int m_polyline_mode;
int m_circle_points;
double m_circle_accuracy;
double m_contour_accuracy;
std::string m_cellname;
std::string m_line;
bool m_ascii;
@ -320,8 +440,6 @@ private:
bool m_keep_other_cells;
int m_line_number;
unsigned int m_zero_layer;
unsigned int m_next_layer_index;
std::map <std::string, unsigned int> m_new_layers;
std::map <db::cell_index_type, std::string> m_template_cells;
std::set <db::cell_index_type> m_used_template_cells;
std::map <std::string, db::cell_index_type> m_block_per_name;
@ -329,8 +447,8 @@ private:
void do_read (db::Layout &layout, db::cell_index_type top);
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &name);
db::cell_index_type make_layer_variant (db::Layout &layout, const std::string &cellname, db::cell_index_type template_cell, unsigned int layer, double sx, double sy);
std::pair <bool, unsigned int> open_layer (db::Layout &layout, const std::string &n);
db::cell_index_type make_layer_variant (db::Layout &layout, const std::string &cellname, db::cell_index_type template_cell, unsigned int layer, double sx, double sy);
void cleanup (db::Layout &layout, db::cell_index_type top);
int read_int16 ();