diff --git a/src/buddies/src/bd/bdReaderOptions.cc b/src/buddies/src/bd/bdReaderOptions.cc index f14a8fb9f..09f2ca72f 100644 --- a/src/buddies/src/bd/bdReaderOptions.cc +++ b/src/buddies/src/bd/bdReaderOptions.cc @@ -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; diff --git a/src/buddies/src/bd/bdReaderOptions.h b/src/buddies/src/bd/bdReaderOptions.h index 1e7b5e231..6bd8678f2 100644 --- a/src/buddies/src/bd/bdReaderOptions.h +++ b/src/buddies/src/bd/bdReaderOptions.h @@ -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); }; } diff --git a/src/db/db/dbDXFReader.cc b/src/db/db/dbDXFReader.cc index 8a4cd355f..e6b397c03 100644 --- a/src/db/db/dbDXFReader.cc +++ b/src/db/db/dbDXFReader.cc @@ -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 +NamedLayerReader::open_layer (db::Layout &layout, const std::string &n) +{ + int l = -1, d = -1; + std::string on; + + std::pair 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 (false, 0); + + } else { + + std::map ::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 (true, ll); + + } else { + return std::pair (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 > 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::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) { + + std::map::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::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) { + + std::map::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::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 +std::pair DXFReader::open_layer (db::Layout &layout, const std::string &n) { - std::string name (n); - - int l = -1, d = -1; - std::string on; - - std::pair 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 (false, 0); - } else { - - std::map ::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 (true, ll); - - } else { - return std::pair (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 ll = m_layer_map.logical (zero_layer_name); + std::pair 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 > 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::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) { - - std::map::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::iterator i = m_new_layers.begin (); i != m_new_layers.end (); ) { - - std::map::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::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 diff --git a/src/db/db/dbDXFReader.h b/src/db/db/dbDXFReader.h index 982c698ad..afff4e815 100644 --- a/src/db/db/dbDXFReader.h +++ b/src/db/db/dbDXFReader.h @@ -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 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 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 m_new_layers; std::map m_template_cells; std::set m_used_template_cells; std::map m_block_per_name; @@ -329,8 +447,8 @@ private: void do_read (db::Layout &layout, db::cell_index_type top); - std::pair 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 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 ();