mirror of https://github.com/KLayout/klayout.git
WIP: basic framework
This commit is contained in:
parent
20976d7521
commit
2acb66182a
|
|
@ -190,7 +190,7 @@
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../lay/lay/layResources.qrc">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/clear.png</normaloff>:/clear.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -204,7 +204,7 @@
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../lay/lay/layResources.qrc">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/add.png</normaloff>:/add.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -218,7 +218,7 @@
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../lay/lay/layResources.qrc">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/up.png</normaloff>:/up.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../lay/lay/layResources.qrc">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/down.png</normaloff>:/down.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
@ -298,7 +298,7 @@
|
|||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../lay/lay/layResources.qrc"/>
|
||||
<include location="../../../../lay/lay/layResources.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbMAG.h"
|
||||
#include "dbMAGReader.h"
|
||||
#include "dbMAGWriter.h"
|
||||
#include "dbStream.h"
|
||||
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// MAGDiagnostics implementation
|
||||
|
||||
MAGDiagnostics::~MAGDiagnostics ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// MAG format declaration
|
||||
|
||||
class MAGFormatDeclaration
|
||||
: public db::StreamFormatDeclaration
|
||||
{
|
||||
public:
|
||||
MAGFormatDeclaration ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual std::string format_name () const { return "MAG"; }
|
||||
virtual std::string format_desc () const { return "Magic"; }
|
||||
virtual std::string format_title () const { return "MAG (Magic layout format)"; }
|
||||
virtual std::string file_format () const { return "MAG files (*.MAG *.msg *.mag.gz *.MAG.gz)"; }
|
||||
|
||||
virtual bool detect (tl::InputStream &s) const
|
||||
{
|
||||
return s.read_all (5) == "magic";
|
||||
}
|
||||
|
||||
virtual ReaderBase *create_reader (tl::InputStream &s) const
|
||||
{
|
||||
return new db::MAGReader (s);
|
||||
}
|
||||
|
||||
virtual WriterBase *create_writer () const
|
||||
{
|
||||
return new db::MAGWriter ();
|
||||
}
|
||||
|
||||
virtual bool can_read () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool can_write () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual tl::XMLElementBase *xml_reader_options_element () const
|
||||
{
|
||||
return new db::ReaderOptionsXMLElement<db::MAGReaderOptions> ("cif",
|
||||
tl::make_member (&db::MAGReaderOptions::lambda, "lambda") +
|
||||
tl::make_member (&db::MAGReaderOptions::dbu, "dbu") +
|
||||
tl::make_member (&db::MAGReaderOptions::layer_map, "layer-map") +
|
||||
tl::make_member (&db::MAGReaderOptions::create_other_layers, "create-other-layers") +
|
||||
tl::make_member (&db::MAGReaderOptions::keep_layer_names, "keep-layer-names") +
|
||||
tl::make_element<std::vector<std::string>, db::MAGReaderOptions> (&db::MAGReaderOptions::lib_paths, "lib-paths",
|
||||
tl::make_member<std::string, std::vector<std::string>::const_iterator, std::vector<std::string> > (&std::vector<std::string>::begin, &std::vector<std::string>::end, &std::vector<std::string>::push_back, "lib-path")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
virtual tl::XMLElementBase *xml_writer_options_element () const
|
||||
{
|
||||
// @@@
|
||||
return new db::WriterOptionsXMLElement<db::MAGWriterOptions> ("cif",
|
||||
tl::make_member (&db::MAGWriterOptions::dummy_calls, "dummy-calls") +
|
||||
tl::make_member (&db::MAGWriterOptions::blank_separator, "blank-separator")
|
||||
);
|
||||
// @@@
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: Because MAG has such a high degree of syntactic freedom, the detection is somewhat
|
||||
// fuzzy: do MAG at the very end of the detection chain
|
||||
static tl::RegisteredClass<db::StreamFormatDeclaration> reader_decl (new MAGFormatDeclaration (), 2200, "MAG");
|
||||
|
||||
// provide a symbol to force linking against
|
||||
int force_link_MAG = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_dbMAG
|
||||
#define HDR_dbMAG
|
||||
|
||||
#include "dbPoint.h"
|
||||
|
||||
#include "tlException.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlString.h"
|
||||
#include "tlAssert.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The diagnostics interface for reporting problems in the reader or writer
|
||||
*/
|
||||
class MAGDiagnostics
|
||||
{
|
||||
public:
|
||||
virtual ~MAGDiagnostics ();
|
||||
|
||||
/**
|
||||
* @brief Issue an error with positional information
|
||||
*/
|
||||
virtual void error (const std::string &txt) = 0;
|
||||
|
||||
/**
|
||||
* @brief Issue a warning with positional information
|
||||
*/
|
||||
virtual void warn (const std::string &txt) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_dbMAGFormat
|
||||
#define HDR_dbMAGFormat
|
||||
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "dbPluginCommon.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Structure that holds the MAG specific options for the reader
|
||||
* NOTE: this structure is non-public linkage by intention. This way it's instantiated
|
||||
* in all compile units and the shared object does not need to be linked.
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC MAGReaderOptions
|
||||
: public FormatSpecificReaderOptions
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
MAGReaderOptions ()
|
||||
: lambda (1.0),
|
||||
dbu (0.001),
|
||||
create_other_layers (true),
|
||||
keep_layer_names (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Specifies the lambda value
|
||||
*
|
||||
* The lambda value is the basic scaling parameter
|
||||
*/
|
||||
double lambda;
|
||||
|
||||
/**
|
||||
* @brief Specify the database unit to produce
|
||||
*
|
||||
* Specify the database unit which the resulting layout will receive.
|
||||
*/
|
||||
double dbu;
|
||||
|
||||
/**
|
||||
* @brief Specifies a layer mapping
|
||||
*
|
||||
* If a layer mapping is specified, only the given layers are read.
|
||||
* Otherwise, all layers are read.
|
||||
* Setting "create_other_layers" to true will make the reader
|
||||
* create other layers for all layers not given in the layer map.
|
||||
* Setting an empty layer map and create_other_layers to true effectively
|
||||
* enables all layers for reading.
|
||||
*/
|
||||
db::LayerMap layer_map;
|
||||
|
||||
/**
|
||||
* @brief A flag indicating that a new layers shall be created
|
||||
*
|
||||
* If this flag is set to true, layers not listed in the layer map a created
|
||||
* too.
|
||||
*/
|
||||
bool create_other_layers;
|
||||
|
||||
/**
|
||||
* @brief A flag indicating whether the names of layers shall be kept as such
|
||||
*
|
||||
* If this flag is set to false (the default), layer name translation happens.
|
||||
* If set to true, translation will not happen.
|
||||
* 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 keep_layer_names;
|
||||
|
||||
/**
|
||||
* @brief The library paths
|
||||
*
|
||||
* The library paths are the places where library references are looked up from.
|
||||
* Expression interpolation happens inside these paths.
|
||||
* "tech_dir", "tech_file", "tech_name" are variables by which you can refer to
|
||||
* technology parameters. Relative paths will be resolved relative to the current
|
||||
* file read.
|
||||
*/
|
||||
std::vector<std::string> lib_paths;
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificReaderOptions
|
||||
*/
|
||||
virtual FormatSpecificReaderOptions *clone () const
|
||||
{
|
||||
return new MAGReaderOptions (*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificReaderOptions
|
||||
*/
|
||||
virtual const std::string &format_name () const
|
||||
{
|
||||
static const std::string n ("MAG");
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure that holds the MAG specific options for the Writer
|
||||
* NOTE: this structure is non-public linkage by intention. This way it's instantiated
|
||||
* in all compile units and the shared object does not need to be linked.
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC MAGWriterOptions
|
||||
: public FormatSpecificWriterOptions
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
MAGWriterOptions ()
|
||||
: dummy_calls (false), blank_separator (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A flag indicating whether dummy calls shall be written
|
||||
* If this flag is true, the writer will produce dummy cell calls on global
|
||||
* level for all top cells.
|
||||
*/
|
||||
bool dummy_calls;
|
||||
|
||||
/**
|
||||
* @brief A flag indicating whether to use blanks as x/y separators
|
||||
* If this flag is true, blank characters will be used to separate x and y values.
|
||||
* Otherwise comma characters will be used.
|
||||
*/
|
||||
bool blank_separator;
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificWriterOptions
|
||||
*/
|
||||
virtual FormatSpecificWriterOptions *clone () const
|
||||
{
|
||||
return new MAGWriterOptions (*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implementation of FormatSpecificWriterOptions
|
||||
*/
|
||||
virtual const std::string &format_name () const
|
||||
{
|
||||
static std::string n ("MAG");
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,862 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbMAGReader.h"
|
||||
#include "dbStream.h"
|
||||
#include "dbObjectWithProperties.h"
|
||||
#include "dbArray.h"
|
||||
#include "dbStatic.h"
|
||||
|
||||
#include "tlException.h"
|
||||
#include "tlString.h"
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// MAGReader
|
||||
|
||||
|
||||
MAGReader::MAGReader (tl::InputStream &s)
|
||||
: m_stream (s),
|
||||
m_progress (tl::to_string (tr ("Reading MAG file")), 1000),
|
||||
m_lambda (1.0), m_dbu (0.001)
|
||||
{
|
||||
m_progress.set_format (tl::to_string (tr ("%.0fk lines")));
|
||||
m_progress.set_format_unit (1000.0);
|
||||
m_progress.set_unit (100000.0);
|
||||
}
|
||||
|
||||
MAGReader::~MAGReader ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
const LayerMap &
|
||||
MAGReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||
{
|
||||
prepare_layers ();
|
||||
|
||||
const db::MAGReaderOptions &specific_options = options.get_options<db::MAGReaderOptions> ();
|
||||
m_lambda = specific_options.lambda;
|
||||
m_dbu = specific_options.dbu;
|
||||
m_lib_paths = specific_options.lib_paths;
|
||||
|
||||
db::LayerMap lm = specific_options.layer_map;
|
||||
lm.prepare (layout);
|
||||
set_layer_map (lm);
|
||||
set_create_layers (specific_options.create_other_layers);
|
||||
set_keep_layer_names (specific_options.keep_layer_names);
|
||||
|
||||
do_read (layout);
|
||||
|
||||
finish_layers (layout);
|
||||
return layer_map ();
|
||||
}
|
||||
|
||||
const LayerMap &
|
||||
MAGReader::read (db::Layout &layout)
|
||||
{
|
||||
return read (layout, db::LoadLayoutOptions ());
|
||||
}
|
||||
|
||||
void
|
||||
MAGReader::error (const std::string &msg)
|
||||
{
|
||||
throw MAGReaderException (msg, m_stream.line_number (), m_stream.source ());
|
||||
}
|
||||
|
||||
void
|
||||
MAGReader::warn (const std::string &msg)
|
||||
{
|
||||
// TODO: compress
|
||||
tl::warn << msg
|
||||
<< tl::to_string (tr (" (line=")) << m_stream.line_number ()
|
||||
<< tl::to_string (tr (", file=")) << m_stream.source ()
|
||||
<< ")";
|
||||
}
|
||||
|
||||
#if 0 // @@@
|
||||
/**
|
||||
* @brief Skip blanks in the sense of MAG
|
||||
* A blank in MAG is "any ASCII character except digit, upperChar, '-', '(', ')', or ';'"
|
||||
*/
|
||||
void
|
||||
MAGReader::skip_blanks()
|
||||
{
|
||||
while (! m_stream.at_end ()) {
|
||||
char c = m_stream.peek_char ();
|
||||
if (isupper (c) || isdigit (c) || c == '-' || c == '(' || c == ')' || c == ';') {
|
||||
return;
|
||||
}
|
||||
m_stream.get_char ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Skips separators
|
||||
*/
|
||||
void
|
||||
MAGReader::skip_sep ()
|
||||
{
|
||||
while (! m_stream.at_end ()) {
|
||||
char c = m_stream.peek_char ();
|
||||
if (isdigit (c) || c == '-' || c == '(' || c == ')' || c == ';') {
|
||||
return;
|
||||
}
|
||||
m_stream.get_char ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Skip comments
|
||||
* This assumes that the reader is after the first '(' and it will stop
|
||||
* after the final ')'.
|
||||
*/
|
||||
void
|
||||
MAGReader::skip_comment ()
|
||||
{
|
||||
char c;
|
||||
int bl = 0;
|
||||
while (! m_stream.at_end () && ((c = m_stream.get_char ()) != ')' || bl > 0)) {
|
||||
// check for nested comments (bl is the nesting level)
|
||||
if (c == '(') {
|
||||
++bl;
|
||||
} else if (c == ')') {
|
||||
--bl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a character and issues an error if the stream is at the end
|
||||
*/
|
||||
char
|
||||
MAGReader::get_char ()
|
||||
{
|
||||
if (m_stream.at_end ()) {
|
||||
error ("Unexpected end of file");
|
||||
return 0;
|
||||
} else {
|
||||
return m_stream.get_char ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests whether the next character is a semicolon (after blanks)
|
||||
*/
|
||||
bool
|
||||
MAGReader::test_semi ()
|
||||
{
|
||||
skip_blanks ();
|
||||
if (! m_stream.at_end () && m_stream.peek_char () == ';') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests whether a semicolon follows and issue an error if not
|
||||
*/
|
||||
void
|
||||
MAGReader::expect_semi ()
|
||||
{
|
||||
if (! test_semi ()) {
|
||||
error ("Expected ';' command terminator");
|
||||
} else {
|
||||
get_char ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Skips all until the next semicolon
|
||||
*/
|
||||
void
|
||||
MAGReader::skip_to_end ()
|
||||
{
|
||||
while (! m_stream.at_end () && m_stream.get_char () != ';') {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches an integer
|
||||
*/
|
||||
int
|
||||
MAGReader::read_integer_digits ()
|
||||
{
|
||||
if (m_stream.at_end () || ! isdigit (m_stream.peek_char ())) {
|
||||
error ("Digit expected");
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (! m_stream.at_end () && isdigit (m_stream.peek_char ())) {
|
||||
|
||||
if (i > std::numeric_limits<int>::max () / 10) {
|
||||
|
||||
error ("Integer overflow");
|
||||
while (! m_stream.at_end () && isdigit (m_stream.peek_char ())) {
|
||||
m_stream.get_char ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
char c = m_stream.get_char ();
|
||||
i = i * 10 + int (c - '0');
|
||||
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches an integer
|
||||
*/
|
||||
int
|
||||
MAGReader::read_integer ()
|
||||
{
|
||||
skip_sep ();
|
||||
return read_integer_digits ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches a signed integer
|
||||
*/
|
||||
int
|
||||
MAGReader::read_sinteger ()
|
||||
{
|
||||
skip_sep ();
|
||||
|
||||
bool neg = false;
|
||||
if (m_stream.peek_char () == '-') {
|
||||
m_stream.get_char ();
|
||||
neg = true;
|
||||
}
|
||||
|
||||
int i = read_integer_digits ();
|
||||
return neg ? -i : i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches a string (layer name)
|
||||
*/
|
||||
const std::string &
|
||||
MAGReader::read_name ()
|
||||
{
|
||||
skip_blanks ();
|
||||
|
||||
m_cmd_buffer.clear ();
|
||||
if (m_stream.at_end ()) {
|
||||
return m_cmd_buffer;
|
||||
}
|
||||
|
||||
// Note: officially only upper and digits are allowed in names. But we allow lower case and "_" too ...
|
||||
while (! m_stream.at_end () && (isupper (m_stream.peek_char ()) || islower (m_stream.peek_char ()) || m_stream.peek_char () == '_' || isdigit (m_stream.peek_char ()))) {
|
||||
m_cmd_buffer += m_stream.get_char ();
|
||||
}
|
||||
|
||||
return m_cmd_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetches a string (in labels, texts)
|
||||
*/
|
||||
const std::string &
|
||||
MAGReader::read_string ()
|
||||
{
|
||||
m_stream.skip ();
|
||||
|
||||
m_cmd_buffer.clear ();
|
||||
if (m_stream.at_end ()) {
|
||||
return m_cmd_buffer;
|
||||
}
|
||||
|
||||
char q = m_stream.peek_char ();
|
||||
if (q == '"' || q == '\'') {
|
||||
|
||||
get_char ();
|
||||
|
||||
// read a quoted string (KLayout extension)
|
||||
while (! m_stream.at_end () && m_stream.peek_char () != q) {
|
||||
char c = m_stream.get_char ();
|
||||
if (c == '\\' && ! m_stream.at_end ()) {
|
||||
c = m_stream.get_char ();
|
||||
}
|
||||
m_cmd_buffer += c;
|
||||
}
|
||||
|
||||
if (! m_stream.at_end ()) {
|
||||
get_char ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
while (! m_stream.at_end () && !isspace (m_stream.peek_char ()) && m_stream.peek_char () != ';') {
|
||||
m_cmd_buffer += m_stream.get_char ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return m_cmd_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads a double value (extension)
|
||||
*/
|
||||
double
|
||||
MAGReader::read_double ()
|
||||
{
|
||||
m_stream.skip ();
|
||||
|
||||
// read a quoted string (KLayout extension)
|
||||
m_cmd_buffer.clear ();
|
||||
while (! m_stream.at_end () && (isdigit (m_stream.peek_char ()) || m_stream.peek_char () == '.' || m_stream.peek_char () == '-' || m_stream.peek_char () == 'e' || m_stream.peek_char () == 'E')) {
|
||||
m_cmd_buffer += m_stream.get_char ();
|
||||
}
|
||||
|
||||
double v = 0.0;
|
||||
tl::from_string (m_cmd_buffer, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
bool
|
||||
MAGReader::read_cell (db::Layout &layout, db::Cell &cell, double sf, int level)
|
||||
{
|
||||
if (fabs (sf - floor (sf + 0.5)) > 1e-6) {
|
||||
warn ("Scaling factor is not an integer - snapping errors may occur in cell '" + m_cellname + "'");
|
||||
}
|
||||
|
||||
int nx = 0, ny = 0, dx = 0, dy = 0;
|
||||
int layer = -2; // no layer defined yet.
|
||||
int path_mode = -1;
|
||||
size_t insts = 0;
|
||||
size_t shapes = 0;
|
||||
size_t layer_specs = 0;
|
||||
std::vector <db::Point> poly_pts;
|
||||
|
||||
while (true) {
|
||||
|
||||
skip_blanks ();
|
||||
|
||||
char c = get_char ();
|
||||
if (c == ';') {
|
||||
|
||||
// empty command
|
||||
|
||||
} else if (c == '(') {
|
||||
|
||||
skip_comment ();
|
||||
|
||||
} else if (c == 'E') {
|
||||
|
||||
if (level > 0) {
|
||||
error ("'E' command must be outside a cell specification");
|
||||
}
|
||||
|
||||
skip_blanks ();
|
||||
break;
|
||||
|
||||
} else if (c == 'D') {
|
||||
|
||||
skip_blanks ();
|
||||
|
||||
c = get_char ();
|
||||
if (c == 'S') {
|
||||
|
||||
// DS command:
|
||||
// "D" blank* "S" integer (sep integer sep integer)?
|
||||
|
||||
unsigned int n = 0, denom = 1, divider = 1;
|
||||
n = read_integer ();
|
||||
if (! test_semi ()) {
|
||||
denom = read_integer ();
|
||||
divider = read_integer ();
|
||||
if (divider == 0) {
|
||||
error ("'DS' command: divider cannot be zero");
|
||||
}
|
||||
}
|
||||
|
||||
expect_semi ();
|
||||
|
||||
std::string outer_cell = "C" + tl::to_string (n);
|
||||
std::swap (m_cellname, outer_cell);
|
||||
|
||||
std::map <unsigned int, db::cell_index_type>::const_iterator c = m_cells_by_id.find (n);
|
||||
db::cell_index_type ci;
|
||||
if (c == m_cells_by_id.end ()) {
|
||||
ci = layout.add_cell (m_cellname.c_str ());
|
||||
m_cells_by_id.insert (std::make_pair (n, ci));
|
||||
} else {
|
||||
ci = c->second;
|
||||
}
|
||||
|
||||
db::Cell &cell = layout.cell (ci);
|
||||
|
||||
read_cell (layout, cell, sf * double (denom) / double (divider), level + 1);
|
||||
|
||||
std::swap (m_cellname, outer_cell);
|
||||
|
||||
} else if (c == 'F') {
|
||||
|
||||
// DF command:
|
||||
// "D" blank* "F"
|
||||
if (level == 0) {
|
||||
error ("'DF' command must be inside a cell specification");
|
||||
}
|
||||
|
||||
// skip the rest of the command
|
||||
skip_to_end ();
|
||||
|
||||
break;
|
||||
|
||||
} else if (c == 'D') {
|
||||
|
||||
// DD command:
|
||||
// "D" blank* "D" integer
|
||||
|
||||
read_integer ();
|
||||
warn ("'DD' command ignored");
|
||||
skip_to_end ();
|
||||
|
||||
} else {
|
||||
|
||||
error ("Invalid 'D' sub-command");
|
||||
skip_to_end ();
|
||||
|
||||
}
|
||||
|
||||
} else if (c == 'C') {
|
||||
|
||||
// C command:
|
||||
// "C" integer transformation
|
||||
// transformation := (blank* ("T" point |"M" blank* "X" |"M" blank* "Y" |"R" point)*)*
|
||||
|
||||
++insts;
|
||||
|
||||
unsigned int n = read_integer ();
|
||||
std::map <unsigned int, db::cell_index_type>::const_iterator c = m_cells_by_id.find (n);
|
||||
if (c == m_cells_by_id.end ()) {
|
||||
std::string cn = "C" + tl::to_string (n);
|
||||
c = m_cells_by_id.insert (std::make_pair (n, layout.add_cell (cn.c_str ()))).first;
|
||||
}
|
||||
|
||||
db::DCplxTrans trans;
|
||||
|
||||
while (! test_semi ()) {
|
||||
|
||||
skip_blanks ();
|
||||
|
||||
char ct = get_char ();
|
||||
if (ct == 'M') {
|
||||
|
||||
skip_blanks ();
|
||||
|
||||
char ct2 = get_char ();
|
||||
if (ct2 == 'X') {
|
||||
trans = db::DCplxTrans (db::FTrans::m90) * trans;
|
||||
} else if (ct2 == 'Y') {
|
||||
trans = db::DCplxTrans (db::FTrans::m0) * trans;
|
||||
} else {
|
||||
error ("Invalid 'M' transformation specification");
|
||||
// skip everything to avoid more errors here
|
||||
while (! test_semi ()) {
|
||||
get_char ();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ct == 'T') {
|
||||
|
||||
int x = read_sinteger ();
|
||||
int y = read_sinteger ();
|
||||
trans = db::DCplxTrans (db::DVector (x * sf, y * sf)) * trans;
|
||||
|
||||
} else if (ct == 'R') {
|
||||
|
||||
int x = read_sinteger ();
|
||||
int y = read_sinteger ();
|
||||
|
||||
if (y != 0 || x != 0) {
|
||||
double a = atan2 (double (y), double (x)) * 180.0 / M_PI;
|
||||
trans = db::DCplxTrans (1.0, a, false, db::DVector ()) * trans;
|
||||
}
|
||||
|
||||
} else {
|
||||
error ("Invalid transformation specification");
|
||||
// skip everything to avoid more errors here
|
||||
while (! test_semi ()) {
|
||||
get_char ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (nx > 0 || ny > 0) {
|
||||
if (trans.is_ortho () && ! trans.is_mag ()) {
|
||||
cell.insert (db::CellInstArray (db::CellInst (c->second), db::Trans (db::ICplxTrans (trans)), db::Vector (dx * sf, 0.0), db::Vector (0.0, dy * sf), std::max (1, nx), std::max (1, ny)));
|
||||
} else {
|
||||
cell.insert (db::CellInstArray (db::CellInst (c->second), db::ICplxTrans (trans), db::Vector (dx * sf, 0.0), db::Vector (0.0, dy * sf), std::max (1, nx), std::max (1, ny)));
|
||||
}
|
||||
} else {
|
||||
if (trans.is_ortho () && ! trans.is_mag ()) {
|
||||
cell.insert (db::CellInstArray (db::CellInst (c->second), db::Trans (db::ICplxTrans (trans))));
|
||||
} else {
|
||||
cell.insert (db::CellInstArray (db::CellInst (c->second), db::ICplxTrans (trans)));
|
||||
}
|
||||
}
|
||||
|
||||
nx = ny = 0;
|
||||
dx = dy = 0;
|
||||
|
||||
expect_semi ();
|
||||
|
||||
} else if (c == 'L') {
|
||||
|
||||
skip_blanks ();
|
||||
|
||||
++layer_specs;
|
||||
|
||||
std::string name = read_name ();
|
||||
if (name.empty ()) {
|
||||
error ("Missing layer name in 'L' command");
|
||||
}
|
||||
|
||||
std::pair<bool, unsigned int> ll = open_layer (layout, name);
|
||||
if (! ll.first) {
|
||||
layer = -1; // ignore geometric objects on this layer
|
||||
} else {
|
||||
layer = int (ll.second);
|
||||
}
|
||||
|
||||
expect_semi ();
|
||||
|
||||
} else if (c == 'B') {
|
||||
|
||||
++shapes;
|
||||
|
||||
if (layer < 0) {
|
||||
|
||||
if (layer < -1) {
|
||||
warn ("'B' command ignored since no layer was selected");
|
||||
}
|
||||
skip_to_end ();
|
||||
|
||||
} else {
|
||||
|
||||
unsigned int w = 0, h = 0;
|
||||
int x = 0, y = 0;
|
||||
|
||||
w = read_integer ();
|
||||
h = read_integer ();
|
||||
x = read_sinteger ();
|
||||
y = read_sinteger ();
|
||||
|
||||
int rx = 0, ry = 0;
|
||||
if (! test_semi ()) {
|
||||
rx = read_sinteger ();
|
||||
ry = read_sinteger ();
|
||||
}
|
||||
|
||||
if (rx >= 0 && ry == 0) {
|
||||
|
||||
cell.shapes ((unsigned int) layer).insert (db::Box (sf * (x - 0.5 * w), sf * (y - 0.5 * h), sf * (x + 0.5 * w), sf * (y + 0.5 * h)));
|
||||
|
||||
} else {
|
||||
|
||||
double n = 1.0 / sqrt (double (rx) * double (rx) + double (ry) * double (ry));
|
||||
|
||||
double xw = sf * w * 0.5 * rx * n, yw = sf * w * 0.5 * ry * n;
|
||||
double xh = -sf * h * 0.5 * ry * n, yh = sf * h * 0.5 * rx * n;
|
||||
|
||||
db::Point c (sf * x, sf * y);
|
||||
|
||||
db::Point points [4];
|
||||
points [0] = c + db::Vector (-xw - xh, -yw - yh);
|
||||
points [1] = c + db::Vector (-xw + xh, -yw + yh);
|
||||
points [2] = c + db::Vector (xw + xh, yw + yh);
|
||||
points [3] = c + db::Vector (xw - xh, yw - yh);
|
||||
|
||||
db::Polygon p;
|
||||
p.assign_hull (points, points + 4);
|
||||
cell.shapes ((unsigned int) layer).insert (p);
|
||||
|
||||
}
|
||||
|
||||
expect_semi ();
|
||||
|
||||
}
|
||||
|
||||
} else if (c == 'P') {
|
||||
|
||||
++shapes;
|
||||
|
||||
if (layer < 0) {
|
||||
|
||||
if (layer < -1) {
|
||||
warn ("'P' command ignored since no layer was selected");
|
||||
}
|
||||
skip_to_end ();
|
||||
|
||||
} else {
|
||||
|
||||
poly_pts.clear ();
|
||||
|
||||
while (! test_semi ()) {
|
||||
|
||||
int rx = read_sinteger ();
|
||||
int ry = read_sinteger ();
|
||||
|
||||
poly_pts.push_back (db::Point (sf * rx, sf * ry));
|
||||
|
||||
}
|
||||
|
||||
db::Polygon p;
|
||||
p.assign_hull (poly_pts.begin (), poly_pts.end ());
|
||||
cell.shapes ((unsigned int) layer).insert (p);
|
||||
|
||||
expect_semi ();
|
||||
|
||||
}
|
||||
|
||||
} else if (c == 'R') {
|
||||
|
||||
++shapes;
|
||||
|
||||
if (layer < 0) {
|
||||
|
||||
if (layer < -1) {
|
||||
warn ("'R' command ignored since no layer was selected");
|
||||
}
|
||||
skip_to_end ();
|
||||
|
||||
} else {
|
||||
|
||||
int w = read_integer ();
|
||||
|
||||
poly_pts.clear ();
|
||||
|
||||
int rx = read_sinteger ();
|
||||
int ry = read_sinteger ();
|
||||
|
||||
poly_pts.push_back (db::Point (sf * rx, sf * ry));
|
||||
|
||||
db::Path p (poly_pts.begin (), poly_pts.end (), db::coord_traits <db::Coord>::rounded (sf * w), db::coord_traits <db::Coord>::rounded (sf * w / 2), db::coord_traits <db::Coord>::rounded (sf * w / 2), true);
|
||||
cell.shapes ((unsigned int) layer).insert (p);
|
||||
|
||||
expect_semi ();
|
||||
|
||||
}
|
||||
|
||||
} else if (c == 'W') {
|
||||
|
||||
++shapes;
|
||||
|
||||
if (layer < 0) {
|
||||
|
||||
if (layer < -1) {
|
||||
warn ("'W' command ignored since no layer was selected");
|
||||
}
|
||||
|
||||
skip_to_end ();
|
||||
|
||||
} else {
|
||||
|
||||
int w = read_integer ();
|
||||
|
||||
poly_pts.clear ();
|
||||
|
||||
while (! test_semi ()) {
|
||||
|
||||
int rx = read_sinteger ();
|
||||
int ry = read_sinteger ();
|
||||
|
||||
poly_pts.push_back (db::Point (sf * rx, sf * ry));
|
||||
|
||||
}
|
||||
|
||||
if (path_mode == 0 || (path_mode < 0 && m_wire_mode == 1)) {
|
||||
// Flush-ended paths
|
||||
db::Path p (poly_pts.begin (), poly_pts.end (), db::coord_traits <db::Coord>::rounded (sf * w), 0, 0, false);
|
||||
cell.shapes ((unsigned int) layer).insert (p);
|
||||
} else if (path_mode == 1 || (path_mode < 0 && m_wire_mode == 2)) {
|
||||
// Round-ended paths
|
||||
db::Path p (poly_pts.begin (), poly_pts.end (), db::coord_traits <db::Coord>::rounded (sf * w), db::coord_traits <db::Coord>::rounded (sf * w / 2), db::coord_traits <db::Coord>::rounded (sf * w / 2), true);
|
||||
cell.shapes ((unsigned int) layer).insert (p);
|
||||
} else {
|
||||
// Square-ended paths
|
||||
db::Path p (poly_pts.begin (), poly_pts.end (), db::coord_traits <db::Coord>::rounded (sf * w), db::coord_traits <db::Coord>::rounded (sf * w / 2), db::coord_traits <db::Coord>::rounded (sf * w / 2), false);
|
||||
cell.shapes ((unsigned int) layer).insert (p);
|
||||
}
|
||||
|
||||
expect_semi ();
|
||||
|
||||
}
|
||||
|
||||
} else if (isdigit (c)) {
|
||||
|
||||
char cc = m_stream.peek_char ();
|
||||
if (c == '9' && cc == '3') {
|
||||
|
||||
get_char ();
|
||||
|
||||
nx = read_sinteger ();
|
||||
dx = read_sinteger ();
|
||||
ny = read_sinteger ();
|
||||
dy = read_sinteger ();
|
||||
|
||||
} else if (c == '9' && cc == '4') {
|
||||
|
||||
get_char ();
|
||||
|
||||
// label at location
|
||||
++shapes;
|
||||
|
||||
if (layer < 0) {
|
||||
if (layer < -1) {
|
||||
warn ("'94' command ignored since no layer was selected");
|
||||
}
|
||||
} else {
|
||||
|
||||
std::string text = read_string ();
|
||||
|
||||
int rx = read_sinteger ();
|
||||
int ry = read_sinteger ();
|
||||
|
||||
double h = 0.0;
|
||||
if (! test_semi ()) {
|
||||
h = read_double ();
|
||||
}
|
||||
|
||||
db::Text t (text.c_str (), db::Trans (db::Vector (sf * rx, sf * ry)), db::coord_traits <db::Coord>::rounded (h / m_dbu));
|
||||
cell.shapes ((unsigned int) layer).insert (t);
|
||||
|
||||
}
|
||||
|
||||
} else if (c == '9' && cc == '5') {
|
||||
|
||||
get_char ();
|
||||
|
||||
// label in box
|
||||
++shapes;
|
||||
|
||||
if (layer < 0) {
|
||||
if (layer < -1) {
|
||||
warn ("'95' command ignored since no layer was selected");
|
||||
}
|
||||
} else {
|
||||
|
||||
std::string text = read_string ();
|
||||
|
||||
// TODO: box dimensions are ignored currently.
|
||||
read_sinteger ();
|
||||
read_sinteger ();
|
||||
|
||||
int rx = read_sinteger ();
|
||||
int ry = read_sinteger ();
|
||||
|
||||
db::Text t (text.c_str (), db::Trans (db::Vector (sf * rx, sf * ry)));
|
||||
cell.shapes ((unsigned int) layer).insert (t);
|
||||
|
||||
}
|
||||
|
||||
} else if (c == '9' && cc == '8') {
|
||||
|
||||
get_char ();
|
||||
|
||||
// Path type (0: flush, 1: round, 2: square)
|
||||
path_mode = read_integer ();
|
||||
|
||||
} else if (c == '9' && ! isdigit (cc)) {
|
||||
|
||||
m_cellname = read_string ();
|
||||
m_cellname = layout.uniquify_cell_name (m_cellname.c_str ());
|
||||
layout.rename_cell (cell.cell_index (), m_cellname.c_str ());
|
||||
|
||||
} else {
|
||||
// ignore the command
|
||||
}
|
||||
|
||||
skip_to_end ();
|
||||
|
||||
} else {
|
||||
|
||||
// ignore the command
|
||||
warn ("Unknown command ignored");
|
||||
skip_to_end ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The cell is considered non-empty if it contains more than one instance, at least one shape or
|
||||
// has at least one "L" command.
|
||||
return insts > 1 || shapes > 0 || layer_specs > 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MAGReader::do_read (db::Layout &layout)
|
||||
{
|
||||
#if 0 // @@@
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, "File read");
|
||||
|
||||
try {
|
||||
|
||||
double sf = 0.01 / m_dbu;
|
||||
layout.dbu (m_dbu);
|
||||
|
||||
m_cellname = "{MAG top level}";
|
||||
|
||||
db::Cell &cell = layout.cell (layout.add_cell ());
|
||||
|
||||
if (! read_cell (layout, cell, sf, 0)) {
|
||||
// The top cell is empty or contains a single instance: discard it.
|
||||
layout.delete_cell (cell.cell_index ());
|
||||
} else {
|
||||
layout.rename_cell (cell.cell_index (), layout.uniquify_cell_name ("MAG_TOP").c_str ());
|
||||
}
|
||||
|
||||
m_cellname = std::string ();
|
||||
|
||||
skip_blanks ();
|
||||
|
||||
if (! m_stream.at_end ()) {
|
||||
warn ("E command is followed by more text");
|
||||
}
|
||||
|
||||
} catch (db::MAGReaderException &ex) {
|
||||
throw ex;
|
||||
} catch (tl::Exception &ex) {
|
||||
error (ex.msg ());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_dbMAGReader
|
||||
#define HDR_dbMAGReader
|
||||
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbNamedLayerReader.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbMAG.h"
|
||||
#include "dbMAGFormat.h"
|
||||
#include "dbStreamLayers.h"
|
||||
#include "dbPropertiesRepository.h"
|
||||
|
||||
#include "tlException.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlString.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Generic base class of MAG reader exceptions
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC MAGReaderException
|
||||
: public ReaderException
|
||||
{
|
||||
public:
|
||||
MAGReaderException (const std::string &msg, size_t l, const std::string &file)
|
||||
: ReaderException (tl::sprintf (tl::to_string (tr ("%s (line=%ld, file=%s)")), msg, l, file))
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The MAG format stream reader
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC MAGReader
|
||||
: public NamedLayerReader,
|
||||
public MAGDiagnostics
|
||||
{
|
||||
public:
|
||||
typedef std::vector<tl::Variant> property_value_list;
|
||||
|
||||
/**
|
||||
* @brief Construct a stream reader object
|
||||
*
|
||||
* @param s The stream delegate from which to read stream data from
|
||||
*/
|
||||
MAGReader (tl::InputStream &s);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~MAGReader ();
|
||||
|
||||
/**
|
||||
* @brief The basic read method
|
||||
*
|
||||
* This method will read the stream data and translate this to
|
||||
* insert calls into the layout object. This will not do much
|
||||
* on the layout object beside inserting the objects.
|
||||
* A set of options can be specified with the LoadLayoutOptions
|
||||
* object.
|
||||
* The returned map will contain all layers, the passed
|
||||
* ones and the newly created ones.
|
||||
*
|
||||
* @param layout The layout object to write to
|
||||
* @param map The LayerMap object
|
||||
* @param create true, if new layers should be created
|
||||
* @return The LayerMap object that tells where which layer was loaded
|
||||
*/
|
||||
virtual const LayerMap &read (db::Layout &layout, const LoadLayoutOptions &options);
|
||||
|
||||
/**
|
||||
* @brief The basic read method (without mapping)
|
||||
*
|
||||
* This method will read the stream data and translate this to
|
||||
* insert calls into the layout object. This will not do much
|
||||
* on the layout object beside inserting the objects.
|
||||
* This version will read all input layers and return a map
|
||||
* which tells which MAG layer has been read into which logical
|
||||
* layer.
|
||||
*
|
||||
* @param layout The layout object to write to
|
||||
* @return The LayerMap object
|
||||
*/
|
||||
virtual const LayerMap &read (db::Layout &layout);
|
||||
|
||||
/**
|
||||
* @brief Format
|
||||
*/
|
||||
virtual const char *format () const { return "MAG"; }
|
||||
|
||||
/**
|
||||
* @brief Issue an error with positional information
|
||||
*
|
||||
* Reimplements MAGDiagnostics
|
||||
*/
|
||||
virtual void error (const std::string &txt);
|
||||
|
||||
/**
|
||||
* @brief Issue a warning with positional information
|
||||
*
|
||||
* Reimplements MAGDiagnostics
|
||||
*/
|
||||
virtual void warn (const std::string &txt);
|
||||
|
||||
private:
|
||||
tl::TextInputStream m_stream;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
double m_lambda, m_dbu;
|
||||
std::vector<std::string> m_lib_paths;
|
||||
|
||||
void do_read (db::Layout &layout);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,445 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbMAGWriter.h"
|
||||
#include "dbPolygonGenerators.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlUtils.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// MAGWriter implementation
|
||||
|
||||
MAGWriter::MAGWriter ()
|
||||
: mp_stream (0),
|
||||
m_progress (tl::to_string (tr ("Writing MAG file")), 10000),
|
||||
m_needs_emit (false)
|
||||
{
|
||||
m_progress.set_format (tl::to_string (tr ("%.0f MB")));
|
||||
m_progress.set_unit (1024 * 1024);
|
||||
}
|
||||
|
||||
MAGWriter &
|
||||
MAGWriter::operator<<(const char *s)
|
||||
{
|
||||
mp_stream->put(s, strlen(s));
|
||||
return *this;
|
||||
}
|
||||
|
||||
MAGWriter &
|
||||
MAGWriter::operator<<(const std::string &s)
|
||||
{
|
||||
mp_stream->put(s.c_str(), s.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
MAGWriter &
|
||||
MAGWriter::operator<<(endl_tag)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
*this << "\r\n";
|
||||
#else
|
||||
*this << "\n";
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char *
|
||||
MAGWriter::xy_sep () const
|
||||
{
|
||||
return m_options.blank_separator ? " " : ",";
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||
{
|
||||
m_options = options.get_options<MAGWriterOptions> ();
|
||||
mp_stream = &stream;
|
||||
|
||||
// compute the scale factor to get to the 10 nm basic database unit of MAG
|
||||
double tl_scale = options.scale_factor () * layout.dbu () / 0.01;
|
||||
|
||||
std::vector <std::pair <unsigned int, db::LayerProperties> > layers;
|
||||
options.get_valid_layers (layout, layers, db::SaveLayoutOptions::LP_AssignName);
|
||||
|
||||
std::set <db::cell_index_type> cell_set;
|
||||
options.get_cells (layout, cell_set, layers);
|
||||
|
||||
// create a cell index vector sorted bottom-up
|
||||
std::vector <db::cell_index_type> cells;
|
||||
cells.reserve (cell_set.size ());
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator cell = layout.begin_bottom_up (); cell != layout.end_bottom_up (); ++cell) {
|
||||
if (cell_set.find (*cell) != cell_set.end ()) {
|
||||
cells.push_back (*cell);
|
||||
}
|
||||
}
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm tt = *localtime(&t);
|
||||
|
||||
char timestr[100];
|
||||
strftime(timestr, sizeof (timestr), "%F %T", &tt);
|
||||
|
||||
// Write header
|
||||
*this << "(MAG file written " << (const char *)timestr << " by KLayout);" << endl;
|
||||
|
||||
// TODO: this can be done more intelligently ..
|
||||
int tl_scale_divider;
|
||||
int tl_scale_denom;
|
||||
for (tl_scale_divider = 1; tl_scale_divider < 1000; ++tl_scale_divider) {
|
||||
tl_scale_denom = int (floor (0.5 + tl_scale * tl_scale_divider));
|
||||
if (fabs (tl_scale_denom - tl_scale * tl_scale_divider) < 1e-6) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int cell_index = 0;
|
||||
std::map <db::cell_index_type, int> db_to_cif_index_map;
|
||||
std::set <db::cell_index_type> called_cells;
|
||||
|
||||
// body
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
// cell body
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
|
||||
++cell_index;
|
||||
db_to_cif_index_map.insert (std::make_pair (*cell, cell_index));
|
||||
|
||||
double sf = 1.0;
|
||||
|
||||
*this << "DS " << cell_index << " " << tl_scale_denom << " " << tl_scale_divider << ";" << endl;
|
||||
*this << "9 " << tl::to_word_or_quoted_string (layout.cell_name (*cell)) << ";" << endl;
|
||||
|
||||
// instances
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
|
||||
// write only instances to selected cells
|
||||
if (cell_set.find (inst->cell_index ()) != cell_set.end ()) {
|
||||
|
||||
called_cells.insert (inst->cell_index ());
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
std::map<db::cell_index_type, int>::const_iterator cif_index = db_to_cif_index_map.find (inst->cell_index ());
|
||||
tl_assert(cif_index != db_to_cif_index_map.end ());
|
||||
|
||||
// resolve instance arrays
|
||||
for (db::Cell::cell_inst_array_type::iterator pp = inst->begin (); ! pp.at_end (); ++pp) {
|
||||
|
||||
*this << "C" << cif_index->second;
|
||||
|
||||
// convert the transformation into MAG's notation
|
||||
|
||||
db::CplxTrans t (inst->complex_trans (*pp));
|
||||
db::Vector d (t.disp() * sf);
|
||||
|
||||
if (t.is_mirror()) {
|
||||
*this << " MY";
|
||||
}
|
||||
|
||||
double a = t.angle();
|
||||
while (a < 0) {
|
||||
a += 360.0;
|
||||
}
|
||||
double ya = 0.0, xa = 0.0;
|
||||
if (a < 45 || a > 315) {
|
||||
xa = 1.0;
|
||||
ya = tan(a / 180.0 * M_PI);
|
||||
} else if (a < 135) {
|
||||
xa = 1.0 / tan(a / 180.0 * M_PI);
|
||||
ya = 1.0;
|
||||
} else if (a < 225) {
|
||||
xa = -1.0;
|
||||
ya = tan(a / 180.0 * M_PI);
|
||||
} else {
|
||||
xa = 1.0 / tan(a / 180.0 * M_PI);
|
||||
ya = -1.0;
|
||||
}
|
||||
|
||||
// TODO: that can be done smarter ...
|
||||
while (fabs (xa - floor (0.5 + xa)) > 1e-3 || fabs (ya - floor (0.5 + ya)) > 1e-3) {
|
||||
xa *= 2.0;
|
||||
ya *= 2.0;
|
||||
}
|
||||
|
||||
*this << " R" << floor (0.5 + xa) << xy_sep () << floor (0.5 + ya);
|
||||
|
||||
*this << " T" << d.x() << xy_sep () << d.y();
|
||||
|
||||
*this << ";" << endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// shapes
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
|
||||
m_needs_emit = true;
|
||||
m_layer = l->second;
|
||||
|
||||
write_texts (layout, cref, l->first, sf);
|
||||
write_polygons (layout, cref, l->first, sf);
|
||||
write_paths (layout, cref, l->first, sf);
|
||||
write_boxes (layout, cref, l->first, sf);
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
}
|
||||
|
||||
// end of cell
|
||||
*this << "DF;" << endl;
|
||||
|
||||
}
|
||||
|
||||
if (m_options.dummy_calls) {
|
||||
|
||||
// If requested, write dummy calls for all top cells
|
||||
for (std::vector<db::cell_index_type>::const_iterator cell = cells.begin (); cell != cells.end (); ++cell) {
|
||||
|
||||
if (called_cells.find (*cell) == called_cells.end ()) {
|
||||
|
||||
std::map<db::cell_index_type, int>::const_iterator cif_index = db_to_cif_index_map.find (*cell);
|
||||
tl_assert(cif_index != db_to_cif_index_map.end ());
|
||||
*this << "C" << cif_index->second << ";" << endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// end of file
|
||||
*this << "E" << endl;
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::emit_layer()
|
||||
{
|
||||
if (m_needs_emit) {
|
||||
m_needs_emit = false;
|
||||
*this << "L " << tl::to_word_or_quoted_string(m_layer.name, "0123456789_.$") << ";" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::write_texts (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double sf)
|
||||
{
|
||||
db::ShapeIterator shape (cell.shapes (layer).begin (db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
emit_layer ();
|
||||
|
||||
*this << "94 " << tl::to_word_or_quoted_string(shape->text_string(), "0123456789:<>/&%$!.-_#+*?\\[]{}");
|
||||
|
||||
double h = shape->text_size () * layout.dbu ();
|
||||
|
||||
db::Vector p (shape->text_trans ().disp () * sf);
|
||||
*this << " " << p.x() << xy_sep () << p.y () << " " << h << ";" << endl;
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::write_polygons (const db::Layout & /*layout*/, const db::Cell &cell, unsigned int layer, double sf)
|
||||
{
|
||||
db::ShapeIterator shape (cell.shapes (layer).begin (db::ShapeIterator::Polygons));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
db::Polygon poly;
|
||||
shape->polygon (poly);
|
||||
|
||||
if (poly.holes () > 0) {
|
||||
|
||||
// resolve holes or merge polygon as a preparation step for split_polygon which only works properly
|
||||
// on merged polygons ...
|
||||
std::vector<db::Polygon> polygons;
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
ep.insert_sequence (poly.begin_edge ());
|
||||
db::PolygonContainer pc (polygons);
|
||||
db::PolygonGenerator out (pc, true /*resolve holes*/, false /*min coherence for splitting*/);
|
||||
db::SimpleMerge op;
|
||||
ep.process (out, op);
|
||||
|
||||
for (std::vector<db::Polygon>::const_iterator p = polygons.begin (); p != polygons.end (); ++p) {
|
||||
write_polygon (*p, sf);
|
||||
}
|
||||
|
||||
} else {
|
||||
write_polygon (poly, sf);
|
||||
}
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::write_polygon (const db::Polygon &polygon, double sf)
|
||||
{
|
||||
emit_layer ();
|
||||
*this << "P";
|
||||
for (db::Polygon::polygon_contour_iterator p = polygon.begin_hull (); p != polygon.end_hull (); ++p) {
|
||||
db::Point pp (*p * sf);
|
||||
*this << " " << pp.x () << xy_sep () << pp.y ();
|
||||
}
|
||||
*this << ";" << endl;
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::write_boxes (const db::Layout & /*layout*/, const db::Cell &cell, unsigned int layer, double sf)
|
||||
{
|
||||
db::ShapeIterator shape (cell.shapes (layer).begin (db::ShapeIterator::Boxes));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
emit_layer ();
|
||||
|
||||
db::Box b (shape->bbox () * sf);
|
||||
*this << "B " << b.width () << " " << b.height () << " " << b.center ().x () << xy_sep () << b.center ().y () << ";" << endl;
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriter::write_paths (const db::Layout & /*layout*/, const db::Cell &cell, unsigned int layer, double sf)
|
||||
{
|
||||
db::ShapeIterator shape (cell.shapes (layer).begin (db::ShapeIterator::Paths));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
#if 0
|
||||
|
||||
// "official" code: write only round paths as such - other paths are converted to polygons
|
||||
if (shape->round_path ()) {
|
||||
|
||||
emit_layer ();
|
||||
|
||||
*this << "W " << long (floor (0.5 + sf * shape->path_width ()));
|
||||
|
||||
for (db::Shape::point_iterator p = shape->begin_point (); p != shape->end_point (); ++p) {
|
||||
db::Point pp (*p * sf);
|
||||
*this << " " << pp.x () << xy_sep () << pp.y ();
|
||||
}
|
||||
|
||||
*this << ";" << endl;
|
||||
|
||||
} else {
|
||||
db::Polygon poly;
|
||||
shape->polygon (poly);
|
||||
write_polygon (poly, sf);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Use 98 extension for path type. Only use polygons for custom extensions.
|
||||
int path_type = -1;
|
||||
if (shape->round_path ()) {
|
||||
if (shape->path_extensions ().first == shape->path_width () / 2 && shape->path_extensions ().second == shape->path_width () / 2) {
|
||||
path_type = 1;
|
||||
}
|
||||
} else {
|
||||
if (shape->path_extensions ().first == 0 && shape->path_extensions ().second == 0) {
|
||||
path_type = 0;
|
||||
} else if (shape->path_extensions ().first == shape->path_width () / 2 && shape->path_extensions ().second == shape->path_width () / 2) {
|
||||
path_type = 2;
|
||||
}
|
||||
}
|
||||
|
||||
size_t npts = 0;
|
||||
for (db::Shape::point_iterator p = shape->begin_point (); p != shape->end_point () && npts < 2; ++p) {
|
||||
++npts;
|
||||
}
|
||||
|
||||
if (npts == 0) {
|
||||
|
||||
// ignore paths with zero points
|
||||
|
||||
} else if (path_type == 1 && npts == 1) {
|
||||
|
||||
// produce a round flash for single-point round paths
|
||||
|
||||
emit_layer ();
|
||||
|
||||
*this << "R " << long (floor (0.5 + sf * shape->path_width ()));
|
||||
|
||||
db::Point pp (*shape->begin_point () * sf);
|
||||
*this << " " << pp.x () << xy_sep () << pp.y ();
|
||||
|
||||
*this << ";" << endl;
|
||||
|
||||
} else if (path_type >= 0 && npts > 1) {
|
||||
|
||||
emit_layer ();
|
||||
|
||||
*this << "98 " << path_type << ";" << endl;
|
||||
|
||||
*this << "W " << long (floor (0.5 + sf * shape->path_width ()));
|
||||
|
||||
for (db::Shape::point_iterator p = shape->begin_point (); p != shape->end_point (); ++p) {
|
||||
db::Point pp (*p * sf);
|
||||
*this << " " << pp.x () << xy_sep () << pp.y ();
|
||||
}
|
||||
|
||||
*this << ";" << endl;
|
||||
|
||||
} else {
|
||||
db::Polygon poly;
|
||||
shape->polygon (poly);
|
||||
write_polygon (poly, sf);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_dbMAGWriter
|
||||
#define HDR_dbMAGWriter
|
||||
|
||||
#include "dbPluginCommon.h"
|
||||
#include "dbWriter.h"
|
||||
#include "dbMAG.h"
|
||||
#include "dbMAGFormat.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "tlProgress.h"
|
||||
|
||||
namespace tl
|
||||
{
|
||||
class OutputStream;
|
||||
}
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Layout;
|
||||
class SaveLayoutOptions;
|
||||
|
||||
/**
|
||||
* @brief A MAG writer abstraction
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC MAGWriter
|
||||
: public db::WriterBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Instantiate the writer
|
||||
*/
|
||||
MAGWriter ();
|
||||
|
||||
/**
|
||||
* @brief Write the layout object
|
||||
*/
|
||||
void write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options);
|
||||
|
||||
private:
|
||||
struct endl_tag { };
|
||||
|
||||
tl::OutputStream *mp_stream;
|
||||
MAGWriterOptions m_options;
|
||||
tl::AbsoluteProgress m_progress;
|
||||
endl_tag endl;
|
||||
db::LayerProperties m_layer;
|
||||
bool m_needs_emit;
|
||||
|
||||
MAGWriter &operator<<(const char *s);
|
||||
MAGWriter &operator<<(const std::string &s);
|
||||
MAGWriter &operator<<(endl_tag);
|
||||
|
||||
template<class X> MAGWriter &operator<<(const X &x)
|
||||
{
|
||||
return (*this << tl::to_string(x));
|
||||
}
|
||||
|
||||
void write_texts (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
|
||||
void write_polygons (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
|
||||
void write_polygon (const db::Polygon &polygon, double tl_scale);
|
||||
void write_boxes (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
|
||||
void write_paths (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
|
||||
void write_edges (const db::Layout &layout, const db::Cell &cell, unsigned int layer, double tl_scale);
|
||||
const char *xy_sep () const;
|
||||
|
||||
void emit_layer();
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
TARGET = cif
|
||||
DESTDIR = $$OUT_PWD/../../../../db_plugins
|
||||
|
||||
include($$PWD/../../../db_plugin.pri)
|
||||
|
||||
HEADERS = \
|
||||
dbMAG.h \
|
||||
dbMAGReader.h \
|
||||
dbMAGWriter.h \
|
||||
dbMAGFormat.h \
|
||||
|
||||
SOURCES = \
|
||||
dbMAG.cc \
|
||||
dbMAGReader.cc \
|
||||
dbMAGWriter.cc \
|
||||
gsiDeclDbMAG.cc \
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbMAG.h"
|
||||
#include "dbMAGReader.h"
|
||||
#include "dbMAGWriter.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "gsiDecl.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// gsi Implementation of specific methods
|
||||
|
||||
static void set_mag_dbu (db::LoadLayoutOptions *options, double dbu)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().dbu = dbu;
|
||||
}
|
||||
|
||||
static double get_mag_dbu (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGReaderOptions> ().dbu;
|
||||
}
|
||||
|
||||
static void set_mag_lambda (db::LoadLayoutOptions *options, double lambda)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().lambda = lambda;
|
||||
}
|
||||
|
||||
static double get_mag_lambda (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGReaderOptions> ().lambda;
|
||||
}
|
||||
|
||||
static void set_mag_library_paths (db::LoadLayoutOptions *options, const std::vector<std::string> &lib_paths)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().lib_paths = lib_paths;
|
||||
}
|
||||
|
||||
static std::vector<std::string> get_mag_library_paths (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGReaderOptions> ().lib_paths;
|
||||
}
|
||||
|
||||
static void set_layer_map (db::LoadLayoutOptions *options, const db::LayerMap &lm, bool f)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().layer_map = lm;
|
||||
options->get_options<db::MAGReaderOptions> ().create_other_layers = f;
|
||||
}
|
||||
|
||||
static void set_layer_map1 (db::LoadLayoutOptions *options, const db::LayerMap &lm)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().layer_map = lm;
|
||||
}
|
||||
|
||||
static db::LayerMap &get_layer_map (db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGReaderOptions> ().layer_map;
|
||||
}
|
||||
|
||||
static void select_all_layers (db::LoadLayoutOptions *options)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().layer_map = db::LayerMap ();
|
||||
options->get_options<db::MAGReaderOptions> ().create_other_layers = true;
|
||||
}
|
||||
|
||||
static bool create_other_layers (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGReaderOptions> ().create_other_layers;
|
||||
}
|
||||
|
||||
static void set_create_other_layers (db::LoadLayoutOptions *options, bool l)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().create_other_layers = l;
|
||||
}
|
||||
|
||||
static bool keep_layer_names (const db::LoadLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGReaderOptions> ().keep_layer_names;
|
||||
}
|
||||
|
||||
static void set_keep_layer_names (db::LoadLayoutOptions *options, bool l)
|
||||
{
|
||||
options->get_options<db::MAGReaderOptions> ().keep_layer_names = l;
|
||||
}
|
||||
|
||||
// extend lay::LoadLayoutOptions with the MAG options
|
||||
static
|
||||
gsi::ClassExt<db::LoadLayoutOptions> mag_reader_options (
|
||||
gsi::method_ext ("mag_set_layer_map", &set_layer_map, gsi::arg ("map"), gsi::arg ("create_other_layers"),
|
||||
"@brief Sets the layer map\n"
|
||||
"This sets a layer mapping for the reader. The \"create_other_layers\" specifies whether to create layers that are not "
|
||||
"in the mapping and automatically assign layers to them.\n"
|
||||
"@param map The layer map to set."
|
||||
"@param create_other_layers The flag telling whether other layer should be created also. Set to false if just the layers in the mapping table should be read.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_layer_map=", &set_layer_map1, gsi::arg ("map"),
|
||||
"@brief Sets the layer map\n"
|
||||
"This sets a layer mapping for the reader. Unlike \\mag_set_layer_map, the 'create_other_layers' flag is not changed.\n"
|
||||
"@param map The layer map to set."
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_select_all_layers", &select_all_layers,
|
||||
"@brief Selects all layers and disables the layer map\n"
|
||||
"\n"
|
||||
"This disables any layer map and enables reading of all layers.\n"
|
||||
"New layers will be created when required.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_layer_map", &get_layer_map,
|
||||
"@brief Gets the layer map\n"
|
||||
"@return A reference to the layer map\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.25 and replaces the respective global option in \\LoadLayoutOptions "
|
||||
"in a format-specific fashion.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_create_other_layers?", &create_other_layers,
|
||||
"@brief Gets a value indicating whether other layers shall be created\n"
|
||||
"@return True, if other layers should be created.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_create_other_layers=", &set_create_other_layers, gsi::arg ("create"),
|
||||
"@brief Specifies whether other layers shall be created\n"
|
||||
"@param create True, if other layers should be created.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_keep_layer_names?", &keep_layer_names,
|
||||
"@brief Gets a value indicating whether layer names are kept\n"
|
||||
"@return True, if layer names are kept.\n"
|
||||
"\n"
|
||||
"When set to true, no attempt is made to translate "
|
||||
"layer names to GDS layer/datatype numbers. If set to false (the default), a layer named \"L2D15\" will be translated "
|
||||
"to GDS layer 2, datatype 15.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_keep_layer_names=", &set_keep_layer_names, gsi::arg ("keep"),
|
||||
"@brief Gets a value indicating whether layer names are kept\n"
|
||||
"@param keep True, if layer names are to be kept.\n"
|
||||
"\n"
|
||||
"See \\mag_keep_layer_names? for a description of this property.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.26.2."
|
||||
) +
|
||||
gsi::method_ext ("mag_library_paths=", &set_mag_library_paths, gsi::arg ("lib_paths"),
|
||||
"@brief Specifies the locations where to look up libraries (in this order)\n"
|
||||
"\n"
|
||||
"The reader will look up library reference in these paths when it can't find them locally.\n"
|
||||
"Relative paths in this collection are resolved relative to the initial file's path.\n"
|
||||
"Expression interpolation is supported in the path strings.\n"
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_library_paths", &get_mag_library_paths,
|
||||
"@brief Get the locations where to look up libraries (in this order)\n"
|
||||
"See \\mag_library_paths= method for a description of this attribute."
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_lambda=", &set_mag_lambda, gsi::arg ("lambda"),
|
||||
"@brief Specifies the lambda value to used for reading\n"
|
||||
"\n"
|
||||
"The lamdba value is the basic unit of the layout.\n"
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_lambda", &get_mag_lambda,
|
||||
"@brief Get the lambda value\n"
|
||||
"See \\mag_lambda= method for a description of this attribute."
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_dbu=", &set_mag_dbu, gsi::arg ("dbu"),
|
||||
"@brief Specifies the database unit which the reader uses and produces\n"
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_dbu", &get_mag_dbu,
|
||||
"@brief Specifies the database unit which the reader uses and produces\n"
|
||||
"See \\mag_dbu= method for a description of this property."
|
||||
"\nThis property has been added in version 0.26.2.\n"
|
||||
),
|
||||
""
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// gsi Implementation of specific methods
|
||||
|
||||
static void set_mag_dummy_calls (db::SaveLayoutOptions *options, bool f)
|
||||
{
|
||||
options->get_options<db::MAGWriterOptions> ().dummy_calls = f;
|
||||
}
|
||||
|
||||
static bool get_mag_dummy_calls (const db::SaveLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGWriterOptions> ().dummy_calls;
|
||||
}
|
||||
|
||||
static void set_mag_blank_separator (db::SaveLayoutOptions *options, bool f)
|
||||
{
|
||||
options->get_options<db::MAGWriterOptions> ().blank_separator = f;
|
||||
}
|
||||
|
||||
static bool get_mag_blank_separator (const db::SaveLayoutOptions *options)
|
||||
{
|
||||
return options->get_options<db::MAGWriterOptions> ().blank_separator;
|
||||
}
|
||||
|
||||
// extend lay::SaveLayoutOptions with the GDS2 options
|
||||
static
|
||||
gsi::ClassExt<db::SaveLayoutOptions> mag_writer_options (
|
||||
gsi::method_ext ("mag_dummy_calls=", &set_mag_dummy_calls,
|
||||
"@brief Sets a flag indicating whether dummy calls shall be written\n"
|
||||
"If this property is set to true, dummy calls will be written in the top level entity "
|
||||
"of the MAG file calling every top cell.\n"
|
||||
"This option is useful for enhanced compatibility with other tools.\n"
|
||||
"\nThis property has been added in version 0.23.10.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_dummy_calls?|#mag_dummy_calls", &get_mag_dummy_calls,
|
||||
"@brief Gets a flag indicating whether dummy calls shall be written\n"
|
||||
"See \\mag_dummy_calls= method for a description of that property."
|
||||
"\nThis property has been added in version 0.23.10.\n"
|
||||
"\nThe predicate version (mag_blank_separator?) has been added in version 0.25.1.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_blank_separator=", &set_mag_blank_separator,
|
||||
"@brief Sets a flag indicating whether blanks shall be used as x/y separator characters\n"
|
||||
"If this property is set to true, the x and y coordinates are separated with blank characters "
|
||||
"rather than comma characters."
|
||||
"\nThis property has been added in version 0.23.10.\n"
|
||||
) +
|
||||
gsi::method_ext ("mag_blank_separator?|#mag_blank_separator", &get_mag_blank_separator,
|
||||
"@brief Gets a flag indicating whether blanks shall be used as x/y separator characters\n"
|
||||
"See \\mag_blank_separator= method for a description of that property."
|
||||
"\nThis property has been added in version 0.23.10.\n"
|
||||
"\nThe predicate version (mag_blank_separator?) has been added in version 0.25.1.\n"
|
||||
),
|
||||
""
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,319 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MAGReaderOptionPage</class>
|
||||
<widget class="QWidget" name="MAGReaderOptionPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>584</width>
|
||||
<height>530</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Input Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="dbu_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Micron</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="keep_names_cbx">
|
||||
<property name="text">
|
||||
<string>Don't attempt to translate into layer/datatype numbers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Keep layer names</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lambda_le"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Micron</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Lambda value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Database unit </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Library paths</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" rowspan="5">
|
||||
<widget class="QListWidget" name="lib_path">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Ignored">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::InternalMove</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QToolButton" name="del_lib_path">
|
||||
<property name="toolTip">
|
||||
<string>Delete selected paths</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/clear.png</normaloff>:/clear.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QToolButton" name="move_lib_path_down">
|
||||
<property name="toolTip">
|
||||
<string>Move selected paths down</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/down.png</normaloff>:/down.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QToolButton" name="add_lib_path">
|
||||
<property name="toolTip">
|
||||
<string>Add new a directory</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/add.png</normaloff>:/add.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Relative paths are resolved relative to the file read.
|
||||
You can use expressions inside the path components for variable paths</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QToolButton" name="move_lib_path_up">
|
||||
<property name="toolTip">
|
||||
<string>Move selected paths up</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/up.png</normaloff>:/up.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="add_lib_path_with_choose">
|
||||
<property name="toolTip">
|
||||
<string>Add new a directory (file browser)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="layer_subset_grp">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Layer Subset And Layer Mapping</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="_2">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="read_all_cbx">
|
||||
<property name="text">
|
||||
<string>Read all layers (additionally to the ones in the mapping table)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" rowspan="10" colspan="2">
|
||||
<widget class="lay::LayerMappingWidget" name="layer_map">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>lay::LayerMappingWidget</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>layLayerMappingWidget.h</header>
|
||||
<container>1</container>
|
||||
<slots>
|
||||
<signal>enable_all_layers(bool)</signal>
|
||||
</slots>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>lambda_le</tabstop>
|
||||
<tabstop>dbu_le</tabstop>
|
||||
<tabstop>keep_names_cbx</tabstop>
|
||||
<tabstop>lib_path</tabstop>
|
||||
<tabstop>add_lib_path</tabstop>
|
||||
<tabstop>add_lib_path_with_choose</tabstop>
|
||||
<tabstop>del_lib_path</tabstop>
|
||||
<tabstop>move_lib_path_up</tabstop>
|
||||
<tabstop>move_lib_path_down</tabstop>
|
||||
<tabstop>read_all_cbx</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../../../lay/lay/layResources.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>layer_map</sender>
|
||||
<signal>enable_all_layers(bool)</signal>
|
||||
<receiver>read_all_cbx</receiver>
|
||||
<slot>setChecked(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>122</x>
|
||||
<y>186</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>109</x>
|
||||
<y>147</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MAGWriterOptionPage</class>
|
||||
<widget class="QWidget" name="MAGWriterOptionPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>619</width>
|
||||
<height>209</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>CIF Writer Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="blank_separator_cbx">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>If checked, a blank character is used as x/y coordinate
|
||||
separator. Otherweise a comma is used.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Blank as x/y separator</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Dummy cell calls</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="dummy_calls_cbx">
|
||||
<property name="text">
|
||||
<string>If checked, dummy cell calls are added on global level</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>601</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbMAG.h"
|
||||
#include "dbMAGReader.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "layMAGReaderPlugin.h"
|
||||
#include "ui_MAGReaderOptionPage.h"
|
||||
#include "gsiDecl.h"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QFileDialog>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// List manipulation utilities
|
||||
// @@@ TODO: move this to a central place
|
||||
static void
|
||||
refresh_item_flags (QListWidget *list)
|
||||
{
|
||||
for (int i = 0; i < list->count (); ++i) {
|
||||
list->item (i)->setFlags (Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_items_to_list (QListWidget *list, const QStringList &items)
|
||||
{
|
||||
for (QStringList::const_iterator f = items.begin (); f != items.end (); ++f) {
|
||||
list->addItem (*f);
|
||||
}
|
||||
refresh_item_flags (list);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_selected_items_from_list (QListWidget *list)
|
||||
{
|
||||
QStringList items;
|
||||
for (int i = 0; i < list->count (); ++i) {
|
||||
if (! list->item (i)->isSelected ()) {
|
||||
items.push_back (list->item (i)->text ());
|
||||
}
|
||||
}
|
||||
|
||||
list->clear ();
|
||||
for (QStringList::const_iterator f = items.begin (); f != items.end (); ++f) {
|
||||
list->addItem (*f);
|
||||
}
|
||||
refresh_item_flags (list);
|
||||
}
|
||||
|
||||
static void
|
||||
move_selected_items_up (QListWidget *list)
|
||||
{
|
||||
std::set<QString> selected;
|
||||
for (int i = 0; i < list->count (); ++i) {
|
||||
if (list->item (i)->isSelected ()) {
|
||||
selected.insert (list->item (i)->text ());
|
||||
}
|
||||
}
|
||||
|
||||
QStringList items;
|
||||
int j = -1;
|
||||
for (int i = 0; i < list->count (); ++i) {
|
||||
if (list->item (i)->isSelected ()) {
|
||||
items.push_back (list->item (i)->text ());
|
||||
} else {
|
||||
if (j >= 0) {
|
||||
items.push_back (list->item (j)->text ());
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
if (j >= 0) {
|
||||
items.push_back (list->item (j)->text ());
|
||||
}
|
||||
|
||||
list->clear ();
|
||||
for (QStringList::const_iterator f = items.begin (); f != items.end (); ++f) {
|
||||
list->addItem (*f);
|
||||
if (selected.find (*f) != selected.end ()) {
|
||||
list->item (list->count () - 1)->setSelected (true);
|
||||
}
|
||||
}
|
||||
refresh_item_flags (list);
|
||||
}
|
||||
|
||||
static void
|
||||
move_selected_items_down (QListWidget *list)
|
||||
{
|
||||
std::set<QString> selected;
|
||||
for (int i = 0; i < list->count (); ++i) {
|
||||
if (list->item (i)->isSelected ()) {
|
||||
selected.insert (list->item (i)->text ());
|
||||
}
|
||||
}
|
||||
|
||||
QStringList items;
|
||||
int j = -1;
|
||||
for (int i = list->count (); i > 0; ) {
|
||||
--i;
|
||||
if (list->item (i)->isSelected ()) {
|
||||
items.push_back (list->item (i)->text ());
|
||||
} else {
|
||||
if (j >= 0) {
|
||||
items.push_back (list->item (j)->text ());
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
if (j >= 0) {
|
||||
items.push_back (list->item (j)->text ());
|
||||
}
|
||||
|
||||
list->clear ();
|
||||
for (QStringList::const_iterator f = items.end (); f != items.begin (); ) {
|
||||
--f;
|
||||
list->addItem (*f);
|
||||
if (selected.find (*f) != selected.end ()) {
|
||||
list->item (list->count () - 1)->setSelected (true);
|
||||
}
|
||||
}
|
||||
refresh_item_flags (list);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// MAGReaderOptionPage definition and implementation
|
||||
|
||||
MAGReaderOptionPage::MAGReaderOptionPage (QWidget *parent)
|
||||
: StreamReaderOptionsPage (parent)
|
||||
{
|
||||
mp_ui = new Ui::MAGReaderOptionPage ();
|
||||
mp_ui->setupUi (this);
|
||||
|
||||
connect (mp_ui->add_lib_path, SIGNAL (clicked ()), this, SLOT (add_lib_path_clicked ()));
|
||||
connect (mp_ui->add_lib_path_with_choose, SIGNAL (clicked ()), this, SLOT (add_lib_path_clicked_with_choose ()));
|
||||
connect (mp_ui->del_lib_path, SIGNAL (clicked ()), this, SLOT (del_lib_paths_clicked ()));
|
||||
connect (mp_ui->move_lib_path_up, SIGNAL (clicked ()), this, SLOT (move_lib_paths_up_clicked ()));
|
||||
connect (mp_ui->move_lib_path_down, SIGNAL (clicked ()), this, SLOT (move_lib_paths_down_clicked ()));
|
||||
}
|
||||
|
||||
MAGReaderOptionPage::~MAGReaderOptionPage ()
|
||||
{
|
||||
delete mp_ui;
|
||||
mp_ui = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MAGReaderOptionPage::setup (const db::FormatSpecificReaderOptions *o, const db::Technology * /*tech*/)
|
||||
{
|
||||
static const db::MAGReaderOptions default_options;
|
||||
const db::MAGReaderOptions *options = dynamic_cast<const db::MAGReaderOptions *> (o);
|
||||
if (!options) {
|
||||
options = &default_options;
|
||||
}
|
||||
|
||||
mp_ui->dbu_le->setText (tl::to_qstring (tl::to_string (options->dbu)));
|
||||
mp_ui->lambda_le->setText (tl::to_qstring (tl::to_string (options->lambda)));
|
||||
mp_ui->layer_map->set_layer_map (options->layer_map);
|
||||
mp_ui->read_all_cbx->setChecked (options->create_other_layers);
|
||||
mp_ui->keep_names_cbx->setChecked (options->keep_layer_names);
|
||||
|
||||
mp_ui->lib_path->clear ();
|
||||
QStringList items;
|
||||
for (std::vector <std::string>::const_iterator f = options->lib_paths.begin (); f != options->lib_paths.end (); ++f) {
|
||||
items << tl::to_qstring (*f);
|
||||
}
|
||||
add_items_to_list (mp_ui->lib_path, items);
|
||||
}
|
||||
|
||||
void
|
||||
MAGReaderOptionPage::commit (db::FormatSpecificReaderOptions *o, const db::Technology * /*tech*/)
|
||||
{
|
||||
db::MAGReaderOptions *options = dynamic_cast<db::MAGReaderOptions *> (o);
|
||||
if (options) {
|
||||
|
||||
tl::from_string (tl::to_string (mp_ui->dbu_le->text ()), options->dbu);
|
||||
if (options->dbu > 1000.0 || options->dbu < 1e-9) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Invalid value for database unit")));
|
||||
}
|
||||
|
||||
tl::from_string (tl::to_string (mp_ui->lambda_le->text ()), options->lambda);
|
||||
if (options->lambda > 10000000.0 || options->lambda < 1e-9) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Invalid value for lambda")));
|
||||
}
|
||||
|
||||
options->layer_map = mp_ui->layer_map->get_layer_map ();
|
||||
options->create_other_layers = mp_ui->read_all_cbx->isChecked ();
|
||||
options->keep_layer_names = mp_ui->keep_names_cbx->isChecked ();
|
||||
|
||||
options->lib_paths.clear ();
|
||||
options->lib_paths.reserve (mp_ui->lib_path->count ());
|
||||
for (int i = 0; i < mp_ui->lib_path->count (); ++i) {
|
||||
options->lib_paths.push_back (tl::to_string (mp_ui->lib_path->item (i)->text ()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGReaderOptionPage::add_lib_path_clicked ()
|
||||
{
|
||||
QStringList dirs;
|
||||
dirs << tr ("Enter your path here ..");
|
||||
add_items_to_list (mp_ui->lib_path, dirs);
|
||||
mp_ui->lib_path->clearSelection ();
|
||||
mp_ui->lib_path->setCurrentItem (mp_ui->lib_path->item (mp_ui->lib_path->count () - 1));
|
||||
}
|
||||
|
||||
void
|
||||
MAGReaderOptionPage::add_lib_path_clicked_with_choose ()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory (this, QObject::tr ("Add library path"));
|
||||
if (! dir.isNull ()) {
|
||||
QStringList dirs;
|
||||
dirs << dir;
|
||||
add_items_to_list (mp_ui->lib_path, dirs);
|
||||
mp_ui->lib_path->clearSelection ();
|
||||
mp_ui->lib_path->setCurrentItem (mp_ui->lib_path->item (mp_ui->lib_path->count () - 1));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGReaderOptionPage::del_lib_paths_clicked ()
|
||||
{
|
||||
delete_selected_items_from_list (mp_ui->lib_path);
|
||||
}
|
||||
|
||||
void
|
||||
MAGReaderOptionPage::move_lib_paths_up_clicked ()
|
||||
{
|
||||
move_selected_items_up (mp_ui->lib_path);
|
||||
}
|
||||
|
||||
void
|
||||
MAGReaderOptionPage::move_lib_paths_down_clicked ()
|
||||
{
|
||||
move_selected_items_down (mp_ui->lib_path);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// MAGReaderPluginDeclaration definition and implementation
|
||||
|
||||
class MAGReaderPluginDeclaration
|
||||
: public StreamReaderPluginDeclaration
|
||||
{
|
||||
public:
|
||||
MAGReaderPluginDeclaration ()
|
||||
: StreamReaderPluginDeclaration (db::MAGReaderOptions ().format_name ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
StreamReaderOptionsPage *format_specific_options_page (QWidget *parent) const
|
||||
{
|
||||
return new MAGReaderOptionPage (parent);
|
||||
}
|
||||
|
||||
db::FormatSpecificReaderOptions *create_specific_options () const
|
||||
{
|
||||
return new db::MAGReaderOptions ();
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl (new lay::MAGReaderPluginDeclaration (), 10000, "MAGReader");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_layMAGReaderPlugin_h
|
||||
#define HDR_layMAGReaderPlugin_h
|
||||
|
||||
#include "layStream.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MAGReaderOptionPage;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class MAGReaderOptionPage
|
||||
: public StreamReaderOptionsPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MAGReaderOptionPage (QWidget *parent);
|
||||
~MAGReaderOptionPage ();
|
||||
|
||||
void setup (const db::FormatSpecificReaderOptions *options, const db::Technology *tech);
|
||||
void commit (db::FormatSpecificReaderOptions *options, const db::Technology *tech);
|
||||
|
||||
private slots:
|
||||
void add_lib_path_clicked ();
|
||||
void add_lib_path_clicked_with_choose ();
|
||||
void del_lib_paths_clicked ();
|
||||
void move_lib_paths_up_clicked ();
|
||||
void move_lib_paths_down_clicked ();
|
||||
|
||||
private:
|
||||
Ui::MAGReaderOptionPage *mp_ui;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbMAG.h"
|
||||
#include "dbMAGWriter.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "layMAGWriterPlugin.h"
|
||||
#include "ui_MAGWriterOptionPage.h"
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// MAGWriterOptionPage definition and implementation
|
||||
|
||||
MAGWriterOptionPage::MAGWriterOptionPage (QWidget *parent)
|
||||
: StreamWriterOptionsPage (parent)
|
||||
{
|
||||
mp_ui = new Ui::MAGWriterOptionPage ();
|
||||
mp_ui->setupUi (this);
|
||||
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
MAGWriterOptionPage::~MAGWriterOptionPage ()
|
||||
{
|
||||
delete mp_ui;
|
||||
mp_ui = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriterOptionPage::setup (const db::FormatSpecificWriterOptions *o, const db::Technology * /*tech*/)
|
||||
{
|
||||
const db::MAGWriterOptions *options = dynamic_cast<const db::MAGWriterOptions *> (o);
|
||||
if (options) {
|
||||
mp_ui->dummy_calls_cbx->setChecked (options->dummy_calls);
|
||||
mp_ui->blank_separator_cbx->setChecked (options->blank_separator);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MAGWriterOptionPage::commit (db::FormatSpecificWriterOptions *o, const db::Technology * /*tech*/, bool /*gzip*/)
|
||||
{
|
||||
db::MAGWriterOptions *options = dynamic_cast<db::MAGWriterOptions *> (o);
|
||||
if (options) {
|
||||
options->dummy_calls = mp_ui->dummy_calls_cbx->isChecked ();
|
||||
options->blank_separator = mp_ui->blank_separator_cbx->isChecked ();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// MAGWriterPluginDeclaration definition and implementation
|
||||
|
||||
class MAGWriterPluginDeclaration
|
||||
: public StreamWriterPluginDeclaration
|
||||
{
|
||||
public:
|
||||
MAGWriterPluginDeclaration ()
|
||||
: StreamWriterPluginDeclaration (db::MAGWriterOptions ().format_name ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
StreamWriterOptionsPage *format_specific_options_page (QWidget *parent) const
|
||||
{
|
||||
return new MAGWriterOptionPage (parent);
|
||||
}
|
||||
|
||||
db::FormatSpecificWriterOptions *create_specific_options () const
|
||||
{
|
||||
return new db::MAGWriterOptions ();
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> plugin_decl (new lay::MAGWriterPluginDeclaration (), 10000, "MAGWriter");
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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_layMAGWriterPlugin_h
|
||||
#define HDR_layMAGWriterPlugin_h
|
||||
|
||||
#include "layStream.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MAGWriterOptionPage;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class MAGWriterOptionPage
|
||||
: public StreamWriterOptionsPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MAGWriterOptionPage (QWidget *parent);
|
||||
~MAGWriterOptionPage ();
|
||||
|
||||
void setup (const db::FormatSpecificWriterOptions *options, const db::Technology *tech);
|
||||
void commit (db::FormatSpecificWriterOptions *options, const db::Technology *tech, bool gzip);
|
||||
|
||||
private:
|
||||
Ui::MAGWriterOptionPage *mp_ui;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
TARGET = cif_ui
|
||||
DESTDIR = $$OUT_PWD/../../../../lay_plugins
|
||||
|
||||
include($$PWD/../../../lay_plugin.pri)
|
||||
|
||||
INCLUDEPATH += $$PWD/../db_plugin
|
||||
DEPENDPATH += $$PWD/../db_plugin
|
||||
LIBS += -L$$DESTDIR/../db_plugins -lcif
|
||||
|
||||
!isEmpty(RPATH) {
|
||||
QMAKE_RPATHDIR += $$RPATH/db_plugins
|
||||
}
|
||||
|
||||
HEADERS = \
|
||||
layMAGReaderPlugin.h \
|
||||
layMAGWriterPlugin.h \
|
||||
|
||||
SOURCES = \
|
||||
layMAGReaderPlugin.cc \
|
||||
layMAGWriterPlugin.cc \
|
||||
|
||||
FORMS = \
|
||||
MAGWriterOptionPage.ui \
|
||||
MAGReaderOptionPage.ui \
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = db_plugin unit_tests
|
||||
unit_tests.depends += db_plugin
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
SUBDIRS += lay_plugin
|
||||
lay_plugin.depends += db_plugin
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 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 "dbMAGReader.h"
|
||||
#include "dbLayoutDiff.h"
|
||||
#include "dbWriter.h"
|
||||
#include "dbMAGWriter.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void run_test (tl::TestBase *_this, const std::string &base, const char *file, const char *file_au, const char *map = 0, double dbu = 0.001, bool dummy_calls = false, bool blank_sep = false)
|
||||
{
|
||||
db::MAGReaderOptions *opt = new db::MAGReaderOptions();
|
||||
opt->dbu = dbu;
|
||||
|
||||
db::LayerMap lm;
|
||||
if (map) {
|
||||
unsigned int ln = 0;
|
||||
tl::Extractor ex (map);
|
||||
while (! ex.at_end ()) {
|
||||
std::string n;
|
||||
int l;
|
||||
ex.read_word_or_quoted (n);
|
||||
ex.test (":");
|
||||
ex.read (l);
|
||||
ex.test (",");
|
||||
lm.map (n, ln++, db::LayerProperties (l, 0));
|
||||
}
|
||||
opt->layer_map = lm;
|
||||
opt->create_other_layers = true;
|
||||
}
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
options.set_options (opt);
|
||||
|
||||
db::Manager m;
|
||||
db::Layout layout (&m), layout2 (&m), layout2_cif (&m), layout_au (&m);
|
||||
|
||||
{
|
||||
std::string fn (base);
|
||||
fn += "/testdata/cif/";
|
||||
fn += file;
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
// generate a "unique" name ...
|
||||
unsigned int hash = 0;
|
||||
for (const char *cp = file_au; *cp; ++cp) {
|
||||
hash = (hash << 4) ^ (hash >> 4) ^ ((unsigned int) *cp);
|
||||
}
|
||||
|
||||
// normalize the layout by writing to GDS and reading from ..
|
||||
|
||||
std::string tmp_gds_file = _this->tmp_file (tl::sprintf ("tmp_%x.gds", hash));
|
||||
std::string tmp_cif_file = _this->tmp_file (tl::sprintf ("tmp_%x.cif", hash));
|
||||
|
||||
{
|
||||
tl::OutputStream stream (tmp_gds_file);
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_format ("GDS2");
|
||||
db::Writer writer (options);
|
||||
writer.write (layout, stream);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream stream (tmp_gds_file);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout2);
|
||||
}
|
||||
|
||||
// normalize the layout by writing to MAG and reading from ..
|
||||
|
||||
{
|
||||
tl::OutputStream stream (tmp_cif_file);
|
||||
|
||||
db::MAGWriterOptions *opt = new db::MAGWriterOptions();
|
||||
opt->dummy_calls = dummy_calls;
|
||||
opt->blank_separator = blank_sep;
|
||||
|
||||
db::MAGWriter writer;
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_options (opt);
|
||||
writer.write (layout, stream, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream stream (tmp_cif_file);
|
||||
|
||||
db::MAGReaderOptions *opt = new db::MAGReaderOptions();
|
||||
opt->dbu = dbu;
|
||||
db::LoadLayoutOptions reread_options;
|
||||
reread_options.set_options (opt);
|
||||
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout2_cif, reread_options);
|
||||
}
|
||||
|
||||
{
|
||||
std::string fn (base);
|
||||
fn += "/testdata/cif/";
|
||||
fn += file_au;
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout_au);
|
||||
}
|
||||
|
||||
bool equal = db::compare_layouts (layout2, layout_au, db::layout_diff::f_boxes_as_polygons | db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 1);
|
||||
if (! equal) {
|
||||
_this->raise (tl::sprintf ("Compare failed after reading - see %s vs %s\n", tmp_gds_file, file_au));
|
||||
}
|
||||
|
||||
equal = db::compare_layouts (layout, layout2_cif, db::layout_diff::f_boxes_as_polygons | db::layout_diff::f_verbose | db::layout_diff::f_flatten_array_insts, 1);
|
||||
if (! equal) {
|
||||
_this->raise (tl::sprintf ("Compare failed after writing - see %s vs %s\n", file, tmp_cif_file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(1a)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t1.cif.gz", "t1a_au.gds.gz");
|
||||
}
|
||||
|
||||
TEST(1b)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t1.cif.gz", "t1b_au.gds.gz", 0, 0.01);
|
||||
}
|
||||
|
||||
TEST(1c)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t1.cif.gz", "t1b_au.gds.gz", 0, 0.01, true);
|
||||
}
|
||||
|
||||
TEST(1d)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t1.cif.gz", "t1b_au.gds.gz", 0, 0.01, false, true);
|
||||
}
|
||||
|
||||
TEST(2)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t2.cif.gz", "t2_au.gds.gz");
|
||||
}
|
||||
|
||||
TEST(3a)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t3.cif.gz", "t3a_au.gds.gz", "CAA:43,CCA:48,CCP:47,CMF:49,CMS:51,CPG:46,CSN:45,CSP:44,CVA:50,CWN:42,XP:26");
|
||||
}
|
||||
|
||||
TEST(3b)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t3.cif.gz", "t3b_au.gds.gz", "CAA:43,CCA:48,CCP:47,CMF:49,CMS:51,CPG:46,CSN:45,CSP:44,CVA:50,CWN:42,XP:26", 0.00012);
|
||||
}
|
||||
|
||||
TEST(4)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t4.cif.gz", "t4_au.gds.gz");
|
||||
}
|
||||
|
||||
TEST(5)
|
||||
{
|
||||
run_test (_this, tl::testsrc_private (), "t5.cif.gz", "t5_au.gds.gz");
|
||||
}
|
||||
|
||||
// Issue #28
|
||||
TEST(lasi)
|
||||
{
|
||||
run_test (_this, tl::testsrc (), "lasi.cif.gz", "lasi_au.gds.gz");
|
||||
}
|
||||
|
||||
// Issue #305
|
||||
TEST(rot_boxes)
|
||||
{
|
||||
run_test (_this, tl::testsrc (), "issue_305.cif", "issue_305_au.gds");
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
DESTDIR_UT = $$OUT_PWD/../../../..
|
||||
|
||||
TARGET = cif_tests
|
||||
|
||||
include($$PWD/../../../../lib_ut.pri)
|
||||
|
||||
SOURCES = \
|
||||
dbMAGReader.cc \
|
||||
|
||||
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
|
||||
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
|
||||
|
||||
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
|
||||
|
||||
PLUGINPATH = $$OUT_PWD/../../../../db_plugins
|
||||
QMAKE_RPATHDIR += $$PLUGINPATH
|
||||
|
||||
LIBS += -L$$PLUGINPATH -lcif
|
||||
Loading…
Reference in New Issue