mirror of https://github.com/KLayout/klayout.git
Compare commits
11 Commits
07fcd4f652
...
ad1a3a0be3
| Author | SHA1 | Date |
|---|---|---|
|
|
ad1a3a0be3 | |
|
|
3a069427cd | |
|
|
fdeab5d104 | |
|
|
ff49a81723 | |
|
|
d015b98534 | |
|
|
b454d2ae42 | |
|
|
b9906180e8 | |
|
|
fc3185165f | |
|
|
b523f05f80 | |
|
|
e8e2858af3 | |
|
|
e6e85ab3b3 |
|
|
@ -30,9 +30,23 @@ namespace bd
|
|||
{
|
||||
|
||||
GenericWriterOptions::GenericWriterOptions ()
|
||||
: m_scale_factor (1.0)
|
||||
{
|
||||
db::SaveLayoutOptions save_options;
|
||||
db::SaveLayoutOptions options;
|
||||
init_from_options (options);
|
||||
}
|
||||
|
||||
GenericWriterOptions::GenericWriterOptions (const db::SaveLayoutOptions &options)
|
||||
{
|
||||
init_from_options (options);
|
||||
}
|
||||
|
||||
void
|
||||
GenericWriterOptions::init_from_options (const db::SaveLayoutOptions &save_options_nc)
|
||||
{
|
||||
// const_cast needed because "get_option_by_name" is not const as it should be
|
||||
db::SaveLayoutOptions &save_options = const_cast<db::SaveLayoutOptions &> (save_options_nc);
|
||||
|
||||
m_scale_factor = 1.0;
|
||||
|
||||
m_dbu = save_options.get_option_by_name ("dbu").to_double ();
|
||||
m_libname = save_options.get_option_by_name ("libname").to_string ();
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ public:
|
|||
*/
|
||||
GenericWriterOptions ();
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* The "options" object specifies the defaults to be used.
|
||||
*/
|
||||
GenericWriterOptions (const db::SaveLayoutOptions &options);
|
||||
|
||||
/**
|
||||
* @brief Adds the generic options to the command line parser object
|
||||
* The format string gives a hint about the target format. Certain options will be
|
||||
|
|
@ -142,6 +149,7 @@ private:
|
|||
int m_dxf_polygon_mode;
|
||||
|
||||
void set_oasis_substitution_char (const std::string &text);
|
||||
void init_from_options (const db::SaveLayoutOptions &options);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -380,7 +380,9 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
generic_reader_options_a.add_options (cmd);
|
||||
generic_reader_options_b.add_options (cmd);
|
||||
|
||||
bd::GenericWriterOptions writer_options;
|
||||
db::SaveLayoutOptions def_writer_options;
|
||||
def_writer_options.set_dont_write_empty_cells (true);
|
||||
bd::GenericWriterOptions writer_options (def_writer_options);
|
||||
writer_options.add_options (cmd);
|
||||
|
||||
cmd << tl::arg ("input_a", &infile_a, "The first input file (any format, may be gzip compressed)")
|
||||
|
|
@ -447,7 +449,7 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
|
|||
cmd.parse (argc, argv);
|
||||
|
||||
if (top_a.empty () != top_b.empty ()) {
|
||||
throw tl::Exception ("Both -ta|--top-a and -tb|--top-b top cells must be given");
|
||||
throw tl::Exception ("Both -ta|--top-a and -tb|--top-b top cells must be given, not just one of them");
|
||||
}
|
||||
|
||||
if (tolerances.empty ()) {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,48 @@ TEST(1A_Deep)
|
|||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "--deep", "--drop-empty-cells=false", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (this, layout, au, db::NormalizationMode (db::NoNormalization | db::AsPolygons));
|
||||
EXPECT_EQ (cap.captured_text (),
|
||||
"Layer 10/0 is not present in first layout, but in second\n"
|
||||
"Result summary (layers without differences are not shown):\n"
|
||||
"\n"
|
||||
" Layer Output Differences (hierarchical shape count)\n"
|
||||
" ----------------------------------------------------------------\n"
|
||||
" 3/0 3/0 3\n"
|
||||
" 6/0 6/0 314\n"
|
||||
" 8/1 8/1 1\n"
|
||||
" 10/0 - (no such layer in first layout)\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(1A_DeepNoEmptyCells)
|
||||
{
|
||||
tl::CaptureChannel cap;
|
||||
|
||||
std::string input_a = tl::testdata ();
|
||||
input_a += "/bd/strmxor_in1.gds";
|
||||
|
||||
std::string input_b = tl::testdata ();
|
||||
input_b += "/bd/strmxor_in2.gds";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/bd/strmxor_au1d2.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "--deep", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
|
@ -342,7 +384,7 @@ TEST(2_Deep)
|
|||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-l", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "--drop-empty-cells=false", "-l", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
|
|
@ -508,7 +550,7 @@ TEST(3_Deep)
|
|||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
// NOTE: -p is ignored in deep mode
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-p=1.0", "-n=4", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
const char *argv[] = { "x", "-u", "--drop-empty-cells=false", "--no-summary", "-p=1.0", "-n=4", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
|
|
@ -607,7 +649,7 @@ TEST(4_Deep)
|
|||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-p=1.0", "-n=4", "-t=0.0,0.005,0.01,0.02,0.09,0.1", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
const char *argv[] = { "x", "-u", "--drop-empty-cells=false", "--no-summary", "-p=1.0", "-n=4", "-t=0.0,0.005,0.01,0.02,0.09,0.1", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
|
|
@ -673,7 +715,7 @@ TEST(5_Deep)
|
|||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
const char *argv[] = { "x", "-u", "--no-summary", "-b=1000", "-t=0.0,0.005,0.01,0.02,0.09,0.1", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
const char *argv[] = { "x", "-u", "--drop-empty-cells=false", "--no-summary", "-b=1000", "-t=0.0,0.005,0.01,0.02,0.09,0.1", input_a.c_str (), input_b.c_str (), output.c_str () };
|
||||
|
||||
EXPECT_EQ (strmxor (sizeof (argv) / sizeof (argv[0]), (char **) argv), 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,18 @@ created as well.
|
|||
This method must be reimplemented in a PCell class to identify the PCell in human-readable form.
|
||||
This text is shown in the cell tree for the PCell for example.
|
||||
|
||||
@method cell_name_impl
|
||||
|
||||
@brief Delivers the cell name to be used for the PCell variant
|
||||
|
||||
A PCell variant is represented in the cell tree by a placeholder cell. By
|
||||
default, the name of this cell is the PCell name. Since multiple variants
|
||||
may exist, usually a disambiguator is added to the name (e.g. "..$1").
|
||||
|
||||
This method allows encoding the PCell parameters into that cell name,
|
||||
so the PCell variant is easier to identify in the cell tree - for example
|
||||
in the GDS file - instead of the unspecific disambiguator.
|
||||
|
||||
@method produce_impl
|
||||
|
||||
@brief Produces the layout
|
||||
|
|
@ -466,6 +478,19 @@ module RBA
|
|||
text
|
||||
end
|
||||
|
||||
# implementation of cell_name
|
||||
def cell_name(parameters)
|
||||
self._start
|
||||
@param_values = parameters
|
||||
text = ""
|
||||
begin
|
||||
text = cell_name_impl
|
||||
ensure
|
||||
self._finish
|
||||
end
|
||||
text
|
||||
end
|
||||
|
||||
# get the parameters
|
||||
def get_parameters
|
||||
@param_decls
|
||||
|
|
@ -568,6 +593,11 @@ module RBA
|
|||
""
|
||||
end
|
||||
|
||||
# default implementation
|
||||
def cell_name_impl
|
||||
self.name
|
||||
end
|
||||
|
||||
# default implementation
|
||||
def coerce_parameters_impl
|
||||
end
|
||||
|
|
|
|||
|
|
@ -158,6 +158,18 @@ created as well.
|
|||
This method must be reimplemented in a PCell class to identify the PCell in human-readable form.
|
||||
This text is shown in the cell tree for the PCell for example.
|
||||
|
||||
@method cell_name_impl
|
||||
|
||||
@brief Delivers the cell name to be used for the PCell variant
|
||||
|
||||
A PCell variant is represented in the cell tree by a placeholder cell. By
|
||||
default, the name of this cell is the PCell name. Since multiple variants
|
||||
may exist, usually a disambiguator is added to the name (e.g. "..$1").
|
||||
|
||||
This method allows encoding the PCell parameters into that cell name,
|
||||
so the PCell variant is easier to identify in the cell tree - for example
|
||||
in the GDS file - instead of the unspecific disambiguator.
|
||||
|
||||
@method produce_impl
|
||||
|
||||
@brief Produces the layout
|
||||
|
|
|
|||
|
|
@ -862,6 +862,12 @@ Cell::get_basic_name () const
|
|||
return layout ()->cell_name (cell_index ());
|
||||
}
|
||||
|
||||
std::string
|
||||
Cell::get_variant_name () const
|
||||
{
|
||||
return get_basic_name ();
|
||||
}
|
||||
|
||||
std::string
|
||||
Cell::get_qualified_name () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -890,7 +890,7 @@ public:
|
|||
void set_name (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Get the basic name
|
||||
* @brief Gets the basic name
|
||||
*
|
||||
* The basic name of the cell is either the cell name or the cell name in the
|
||||
* target library (for library proxies) or the PCell name (for PCell proxies).
|
||||
|
|
@ -898,6 +898,14 @@ public:
|
|||
*/
|
||||
virtual std::string get_basic_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the variant name
|
||||
*
|
||||
* The variant name is the PCell's "cell_name" - which may encode the PCell parameters
|
||||
* into a formal name. Usually that is identical to the PCell name.
|
||||
*/
|
||||
virtual std::string get_variant_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the display name
|
||||
*
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ ColdProxy::get_basic_name () const
|
|||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
std::string
|
||||
ColdProxy::get_display_name () const
|
||||
{
|
||||
if (! mp_context_info->lib_name.empty ()) {
|
||||
|
|
|
|||
|
|
@ -2462,7 +2462,7 @@ Layout::get_pcell_variant_dict (pcell_id_type pcell_id, const std::map<std::stri
|
|||
pcell_variant_type *variant = header->get_variant (*this, parameters);
|
||||
if (! variant) {
|
||||
|
||||
std::string b (header->get_name ());
|
||||
std::string b (header->declaration ()->get_cell_name (parameters));
|
||||
if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) {
|
||||
b = uniquify_cell_name (b.c_str ());
|
||||
}
|
||||
|
|
@ -2501,7 +2501,7 @@ Layout::get_pcell_variant (pcell_id_type pcell_id, const std::vector<tl::Variant
|
|||
pcell_variant_type *variant = header->get_variant (*this, parameters);
|
||||
if (! variant) {
|
||||
|
||||
std::string b (header->get_name ());
|
||||
std::string b (header->declaration ()->get_cell_name (parameters));
|
||||
if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) {
|
||||
b = uniquify_cell_name (b.c_str ());
|
||||
}
|
||||
|
|
@ -2627,9 +2627,18 @@ Layout::convert_cell_to_static (db::cell_index_type ci)
|
|||
|
||||
const cell_type &org_cell = cell (ci);
|
||||
|
||||
// Note: convert to static cell by explicitly cloning to the db::Cell class
|
||||
ret_ci = add_cell (org_cell.get_basic_name ().c_str ());
|
||||
std::string vn = org_cell.get_variant_name ();
|
||||
if (vn == std::string (cell_name (ci), vn.size ())) {
|
||||
// there is a cell name conflict: give priority to the static cell, so it
|
||||
// will see the variant name or at least the original disambiguated name
|
||||
std::string rename_org = uniquify_cell_name (vn.c_str ());
|
||||
vn = cell_name (ci);
|
||||
rename_cell (ci, rename_org.c_str ());
|
||||
}
|
||||
|
||||
ret_ci = add_cell (vn.c_str ());
|
||||
cell_type &new_cell = cell (ret_ci);
|
||||
// Note: we convert to static cell by explicitly converting to the db::Cell class
|
||||
new_cell = org_cell;
|
||||
new_cell.set_cell_index (ret_ci);
|
||||
|
||||
|
|
@ -3126,6 +3135,12 @@ Layout::basic_name (cell_index_type cell_index) const
|
|||
return cell (cell_index).get_basic_name ();
|
||||
}
|
||||
|
||||
std::string
|
||||
Layout::variant_name (cell_index_type cell_index) const
|
||||
{
|
||||
return cell (cell_index).get_variant_name ();
|
||||
}
|
||||
|
||||
void
|
||||
Layout::register_lib_proxy (db::LibraryProxy *lib_proxy)
|
||||
{
|
||||
|
|
@ -3161,7 +3176,7 @@ Layout::get_lib_proxy (Library *lib, cell_index_type cell_index)
|
|||
} else {
|
||||
|
||||
// create a new unique name
|
||||
std::string b (lib->layout ().basic_name (cell_index));
|
||||
std::string b (lib->layout ().variant_name (cell_index));
|
||||
if (m_cell_map.find (b.c_str ()) != m_cell_map.end ()) {
|
||||
b = uniquify_cell_name (b.c_str ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -675,7 +675,7 @@ public:
|
|||
std::string display_name (cell_index_type cell_index) const;
|
||||
|
||||
/**
|
||||
* @brief Return the basic name for the given cell
|
||||
* @brief Returns the basic name for the given cell
|
||||
*
|
||||
* This method is forwarded to the respective method of the cell.
|
||||
* The basic name is the "original" cell name within the library or
|
||||
|
|
@ -684,7 +684,16 @@ public:
|
|||
*/
|
||||
std::string basic_name (cell_index_type cell_index) const;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Returns the variant name for the given cell
|
||||
*
|
||||
* The variant name usually is the basic name. For PCells, this name
|
||||
* can encode PCell parameters, depending on the definition of the
|
||||
* PCell.
|
||||
*/
|
||||
std::string variant_name (cell_index_type cell_index) const;
|
||||
|
||||
/**
|
||||
* @brief Add a cell object with the given ID and name
|
||||
*
|
||||
* This method is basically supposed to be used for "undo" and "redo".
|
||||
|
|
|
|||
|
|
@ -257,7 +257,23 @@ LibraryProxy::get_basic_name () const
|
|||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
std::string
|
||||
LibraryProxy::get_variant_name () const
|
||||
{
|
||||
Library *lib = LibraryManager::instance ().lib (lib_id ());
|
||||
if (lib) {
|
||||
if (! lib->layout ().is_valid_cell_index (library_cell_index ())) {
|
||||
return "<defunct>";
|
||||
} else {
|
||||
const db::Cell &lib_cell = lib->layout ().cell (library_cell_index ());
|
||||
return lib_cell.get_variant_name ();
|
||||
}
|
||||
} else {
|
||||
return Cell::get_variant_name ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
LibraryProxy::get_display_name () const
|
||||
{
|
||||
Library *lib = LibraryManager::instance ().lib (lib_id ());
|
||||
|
|
|
|||
|
|
@ -96,25 +96,28 @@ public:
|
|||
/**
|
||||
* @brief Gets the basic name
|
||||
*
|
||||
* The basic name of the cell is either the cell name or the cell name in the
|
||||
* target library (for library proxies) or the PCell name (for PCell proxies).
|
||||
* The actual name may be different by a extension to make it unique.
|
||||
* This returns the basic name of the proxy target
|
||||
*/
|
||||
virtual std::string get_basic_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the variant name
|
||||
*
|
||||
* This returns the basic name of the proxy target
|
||||
*/
|
||||
virtual std::string get_variant_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the display name
|
||||
*
|
||||
* The display name is some "nice" descriptive name of the cell (variant)
|
||||
* For normal cells this name is equivalent to the normal cell name.
|
||||
* This returns the basic name of the proxy target
|
||||
*/
|
||||
virtual std::string get_display_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the qualified name
|
||||
*
|
||||
* The qualified name for a library proxy is made from the library name, a
|
||||
* dot and the cell's name.
|
||||
* Gets a combination of the library name and the target cell's qualified name
|
||||
*/
|
||||
virtual std::string get_qualified_name () const;
|
||||
|
||||
|
|
|
|||
|
|
@ -673,6 +673,18 @@ public:
|
|||
return std::string ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a cell name for the PCell, which can depend on the parameters
|
||||
*
|
||||
* The actual cell name in the layout may differ by disambiguation. This method
|
||||
* delivers a proposal for a cell name.
|
||||
* By default, the PCell name is returned.
|
||||
*/
|
||||
virtual std::string get_cell_name (const pcell_parameters_type &) const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the description text of the PCell
|
||||
*
|
||||
|
|
|
|||
|
|
@ -86,7 +86,18 @@ PCellVariant::get_basic_name () const
|
|||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
std::string
|
||||
PCellVariant::get_variant_name () const
|
||||
{
|
||||
const PCellHeader *header = pcell_header ();
|
||||
if (header) {
|
||||
return m_variant_name;
|
||||
} else {
|
||||
return Cell::get_basic_name ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
PCellVariant::get_display_name () const
|
||||
{
|
||||
const PCellHeader *header = pcell_header ();
|
||||
|
|
@ -172,6 +183,7 @@ PCellVariant::update (ImportLayerMapping *layer_mapping)
|
|||
header->declaration ()->produce (*layout (), layer_ids, plist, *this);
|
||||
|
||||
m_display_name = header->declaration ()->get_display_name (plist);
|
||||
m_variant_name = header->declaration ()->get_cell_name (plist);
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
||||
|
|
|
|||
|
|
@ -94,42 +94,37 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Get the basic name
|
||||
*
|
||||
* The basic name of the cell is either the cell name or the cell name in the
|
||||
* target library (for library proxies) or the PCell name (for PCell proxies).
|
||||
* The actual name may be different by a extension to make it unique.
|
||||
* @brief Gets the basic name
|
||||
*/
|
||||
virtual std::string get_basic_name () const;
|
||||
|
||||
/**
|
||||
* @brief Get the display name
|
||||
*
|
||||
* The display name is some "nice" descriptive name of the cell (variant)
|
||||
* For normal cells this name is equivalent to the normal cell name.
|
||||
* @brief Gets the variant name
|
||||
*/
|
||||
virtual std::string get_variant_name () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the display name
|
||||
*/
|
||||
virtual std::string get_display_name () const;
|
||||
|
||||
/**
|
||||
* @brief Unregister a cell from it's context.
|
||||
* @brief Unregisters a cell from its context.
|
||||
*/
|
||||
virtual void unregister ();
|
||||
|
||||
/**
|
||||
* @brief Reregister a cell inside it's context.
|
||||
* @brief Re-registers a cell inside its context.
|
||||
*/
|
||||
virtual void reregister ();
|
||||
|
||||
/**
|
||||
* @brief Update the layout
|
||||
* @brief Updates the layout
|
||||
*/
|
||||
virtual void update (ImportLayerMapping *layer_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief Tell, if this cell is a proxy cell
|
||||
*
|
||||
* Proxy cells are such whose layout represents a snapshot of another entity.
|
||||
* Such cells can be PCell variants or library references for example.
|
||||
* @brief Gets a value indicating if this cell is a proxy cell
|
||||
*/
|
||||
virtual bool is_proxy () const
|
||||
{
|
||||
|
|
@ -138,7 +133,7 @@ public:
|
|||
|
||||
protected:
|
||||
/**
|
||||
* @brief Get the PCell header for this variant
|
||||
* @brief Gets the PCell header for this variant
|
||||
*/
|
||||
PCellHeader *pcell_header ()
|
||||
{
|
||||
|
|
@ -146,7 +141,7 @@ protected:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Get the PCell header for this variant
|
||||
* @brief Gets the PCell header for this variant
|
||||
*/
|
||||
const PCellHeader *pcell_header () const
|
||||
{
|
||||
|
|
@ -156,6 +151,7 @@ protected:
|
|||
private:
|
||||
pcell_parameters_type m_parameters;
|
||||
mutable std::string m_display_name;
|
||||
mutable std::string m_variant_name;
|
||||
db::pcell_id_type m_pcell_id;
|
||||
bool m_registered;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -368,6 +368,7 @@ Class<db::PCellDeclaration> decl_PCellDeclaration_Native ("db", "PCellDeclaratio
|
|||
gsi::method ("via_types", &db::PCellDeclaration::via_types) +
|
||||
gsi::method ("description", &db::PCellDeclaration::get_description) +
|
||||
gsi::method ("display_text", &db::PCellDeclaration::get_display_name, gsi::arg ("parameters")) +
|
||||
gsi::method ("cell_name", &db::PCellDeclaration::get_cell_name, gsi::arg ("parameters")) +
|
||||
gsi::method ("layout", &db::PCellDeclaration::layout,
|
||||
"@brief Gets the Layout object the PCell is registered in or nil if it is not registered yet.\n"
|
||||
"This attribute has been added in version 0.27.5."
|
||||
|
|
@ -659,6 +660,20 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::string get_cell_name_fb (const db::pcell_parameters_type ¶meters) const
|
||||
{
|
||||
return db::PCellDeclaration::get_cell_name (parameters);
|
||||
}
|
||||
|
||||
virtual std::string get_cell_name (const db::pcell_parameters_type ¶meters) const
|
||||
{
|
||||
if (cb_get_cell_name.can_issue ()) {
|
||||
return cb_get_cell_name.issue<db::PCellDeclaration, std::string, const db::pcell_parameters_type &> (&db::PCellDeclaration::get_cell_name, parameters);
|
||||
} else {
|
||||
return db::PCellDeclaration::get_cell_name (parameters);
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback cb_get_layer_declarations;
|
||||
gsi::Callback cb_get_parameter_declarations;
|
||||
gsi::Callback cb_produce;
|
||||
|
|
@ -669,6 +684,7 @@ public:
|
|||
gsi::Callback cb_coerce_parameters;
|
||||
gsi::Callback cb_callback;
|
||||
gsi::Callback cb_get_display_name;
|
||||
gsi::Callback cb_get_cell_name;
|
||||
gsi::Callback cb_get_description;
|
||||
gsi::Callback cb_via_types;
|
||||
};
|
||||
|
|
@ -682,6 +698,7 @@ Class<PCellDeclarationImpl> decl_PCellDeclaration (decl_PCellDeclaration_Native,
|
|||
gsi::method ("parameters_from_shape", &PCellDeclarationImpl::parameters_from_shape_fb, "@hide") +
|
||||
gsi::method ("transformation_from_shape", &PCellDeclarationImpl::transformation_from_shape_fb, "@hide") +
|
||||
gsi::method ("display_text", &PCellDeclarationImpl::get_display_name_fb, "@hide") +
|
||||
gsi::method ("cell_name", &PCellDeclarationImpl::get_cell_name_fb, "@hide") +
|
||||
gsi::method ("wants_lazy_evaluation", &PCellDeclarationImpl::wants_lazy_evaluation_fb, "@hide") +
|
||||
gsi::method ("description", &PCellDeclarationImpl::get_description_fb, "@hide") +
|
||||
gsi::method ("via_types", &PCellDeclarationImpl::via_types_fb, "@hide") +
|
||||
|
|
@ -809,6 +826,13 @@ Class<PCellDeclarationImpl> decl_PCellDeclaration (decl_PCellDeclaration_Native,
|
|||
"@brief Returns the display text for this PCell given a certain parameter set\n"
|
||||
"Reimplement this method to create a distinct display text for a PCell variant with \n"
|
||||
"the given parameter set. If this method is not implemented, a default text is created. \n"
|
||||
) +
|
||||
gsi::callback ("cell_name", &PCellDeclarationImpl::get_cell_name, &PCellDeclarationImpl::cb_get_cell_name, gsi::arg ("parameters"),
|
||||
"@brief Returns a cell name used for the PCell variant\n"
|
||||
"Reimplement this method to create a cell name the system uses for the PCell variant. By default that is the PCell name.\n"
|
||||
"This feature allows encoding the PCell parameters into the cell name for easier identification of the PCell variant in a cell tree.\n"
|
||||
"\n"
|
||||
"This feature has been added in version 0.30.5.\n"
|
||||
),
|
||||
"@brief A PCell declaration providing the parameters and code to produce the PCell\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -88,6 +88,13 @@ class PD
|
|||
|
||||
cell.shapes (l_metal0).insert (db::Box (0, 0, width, height));
|
||||
}
|
||||
|
||||
virtual std::string get_display_name (const db::pcell_parameters_type ¶meters) const
|
||||
{
|
||||
db::Coord width = db::coord_traits<db::Coord>::rounded (parameters[0].to_double () * 1000.0);
|
||||
db::Coord height = db::coord_traits<db::Coord>::rounded (parameters[1].to_double () * 1000.0);
|
||||
return tl::sprintf ("PD(W=%d,H=%d)", width, height);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(0)
|
||||
|
|
@ -252,3 +259,114 @@ TEST(1)
|
|||
}
|
||||
}
|
||||
|
||||
// PCell names, convert PCell to static
|
||||
|
||||
class PD2
|
||||
: public PD
|
||||
{
|
||||
public:
|
||||
virtual std::string get_cell_name (const db::pcell_parameters_type ¶meters) const
|
||||
{
|
||||
db::Coord width = db::coord_traits<db::Coord>::rounded (parameters[0].to_double () * 1000.0);
|
||||
db::Coord height = db::coord_traits<db::Coord>::rounded (parameters[1].to_double () * 1000.0);
|
||||
return tl::sprintf ("PD_W%d_H%d", width, height);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(2)
|
||||
{
|
||||
db::Manager m (true);
|
||||
db::Layout layout(&m);
|
||||
layout.dbu (0.001);
|
||||
|
||||
db::LayerProperties p;
|
||||
|
||||
p.layer = 23;
|
||||
p.datatype = 0;
|
||||
unsigned int l_cont = layout.insert_layer (p);
|
||||
|
||||
p.layer = 16;
|
||||
p.datatype = 0;
|
||||
unsigned int l_gate = layout.insert_layer (p);
|
||||
|
||||
db::Cell &cell_a = layout.cell (layout.add_cell ("A"));
|
||||
cell_a.shapes(l_cont).insert(db::Box (50, 50, 150, 150));
|
||||
cell_a.shapes(l_gate).insert(db::Box (0, 0, 200, 1000));
|
||||
|
||||
db::Cell &top = layout.cell (layout.add_cell ("TOP"));
|
||||
|
||||
db::pcell_id_type pd = layout.register_pcell ("PD", new PD2 ());
|
||||
|
||||
std::vector<tl::Variant> parameters;
|
||||
parameters.push_back (tl::Variant ());
|
||||
parameters.push_back (tl::Variant ());
|
||||
parameters.push_back (tl::Variant ());
|
||||
tl::Variant &width = parameters[0];
|
||||
tl::Variant &height = parameters[1];
|
||||
tl::Variant &orientation = parameters[2];
|
||||
|
||||
width = 0.5;
|
||||
height = 1.0;
|
||||
orientation = long (0);
|
||||
|
||||
db::cell_index_type pd1 = layout.get_pcell_variant (pd, parameters);
|
||||
top.insert (db::CellInstArray (db::CellInst (pd1), db::Trans (db::Vector (0, 0))));
|
||||
|
||||
EXPECT_EQ (layout.display_name (pd1), "PD(W=500,H=1000)");
|
||||
EXPECT_EQ (layout.cell_name (pd1), "PD_W500_H1000");
|
||||
EXPECT_EQ (layout.variant_name (pd1), "PD_W500_H1000");
|
||||
|
||||
width = 0.4;
|
||||
height = 0.8;
|
||||
|
||||
db::cell_index_type pd2 = layout.get_pcell_variant (pd, parameters);
|
||||
top.insert (db::CellInstArray (db::CellInst (pd2), db::Trans (db::Vector (0, 2000))));
|
||||
|
||||
EXPECT_EQ (layout.display_name (pd2), "PD(W=400,H=800)");
|
||||
EXPECT_EQ (layout.cell_name (pd2), "PD_W400_H800");
|
||||
EXPECT_EQ (layout.variant_name (pd2), "PD_W400_H800");
|
||||
|
||||
EXPECT_NE (pd1, pd2);
|
||||
|
||||
width = 0.4;
|
||||
height = 0.8;
|
||||
orientation = long (1);
|
||||
|
||||
db::cell_index_type pd3 = layout.get_pcell_variant (pd, parameters);
|
||||
auto i3 = top.insert (db::CellInstArray (db::CellInst (pd3), db::Trans (db::Vector (2000, 0))));
|
||||
|
||||
EXPECT_EQ (layout.display_name (pd3), "PD(W=400,H=800)");
|
||||
EXPECT_EQ (layout.cell_name (pd3), "PD_W400_H800$1");
|
||||
EXPECT_EQ (layout.variant_name (pd3), "PD_W400_H800");
|
||||
|
||||
EXPECT_NE (pd2, pd3);
|
||||
|
||||
auto pd3_org = pd3;
|
||||
pd3 = layout.convert_cell_to_static (pd3);
|
||||
EXPECT_NE (pd3, pd3_org);
|
||||
|
||||
auto ci3 = i3.cell_inst ();
|
||||
ci3.object ().cell_index (pd3);
|
||||
top.replace (i3, ci3);
|
||||
|
||||
EXPECT_EQ (layout.cell (pd3_org).is_proxy (), true);
|
||||
EXPECT_EQ (layout.cell (pd3).is_proxy (), false);
|
||||
|
||||
EXPECT_EQ (layout.display_name (pd3_org), "PD(W=400,H=800)");
|
||||
EXPECT_EQ (layout.cell_name (pd3_org), "PD_W400_H800$2");
|
||||
EXPECT_EQ (layout.variant_name (pd3_org), "PD_W400_H800");
|
||||
|
||||
layout.do_cleanup (true);
|
||||
layout.cleanup ();
|
||||
|
||||
EXPECT_EQ (layout.is_valid_cell_index (pd3_org), false);
|
||||
|
||||
EXPECT_EQ (layout.display_name (pd3), "PD_W400_H800$1");
|
||||
EXPECT_EQ (layout.cell_name (pd3), "PD_W400_H800$1");
|
||||
EXPECT_EQ (layout.variant_name (pd3), "PD_W400_H800$1");
|
||||
|
||||
|
||||
|
||||
CHECKPOINT ();
|
||||
db::compare_layouts (_this, layout, tl::testdata () + "/gds/pcell_test20.gds", db::NoNormalization);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1327,6 +1327,13 @@ static std::string path_to_string (const db::Layout &layout, const lay::ObjectIn
|
|||
void
|
||||
Service::display_status (bool transient)
|
||||
{
|
||||
if (transient && view ()->canvas ()->begin_mouse_receivers () != view ()->canvas ()->end_mouse_receivers ()
|
||||
&& (*view ()->canvas ()->begin_mouse_receivers ())->claims_message_bar ()) {
|
||||
// do not display transient if there is a plugin active that has captured the mouse and claims the message bar -
|
||||
// this way we can use messages in active plugins and still get visual feedback by the transient selection.
|
||||
return;
|
||||
}
|
||||
|
||||
EditableSelectionIterator r = transient ? begin_transient_selection () : begin_selection ();
|
||||
EditableSelectionIterator rr = r;
|
||||
|
||||
|
|
|
|||
|
|
@ -621,6 +621,11 @@ struct LAYBASIC_PUBLIC AbstractMenuItem
|
|||
return m_primary;
|
||||
}
|
||||
|
||||
void set_primary (bool p)
|
||||
{
|
||||
m_primary = p;
|
||||
}
|
||||
|
||||
std::list <AbstractMenuItem> children;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static int inst_point_sel_tests = 10000;
|
|||
|
||||
Finder::Finder (bool point_mode, bool top_level_sel)
|
||||
: m_min_level (0), m_max_level (0),
|
||||
mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_catch_all (false), m_top_level_sel (top_level_sel)
|
||||
mp_layout (0), mp_view (0), m_cv_index (0), m_point_mode (point_mode), m_catch_all (false), m_consider_viewport (true), m_top_level_sel (top_level_sel)
|
||||
{
|
||||
m_distance = std::numeric_limits<double>::max ();
|
||||
}
|
||||
|
|
@ -482,7 +482,10 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
|
|||
checkpoint ();
|
||||
|
||||
// Viewport in current cell coordinate space (DBU)
|
||||
db::Box viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ());
|
||||
db::Box viewport_box;
|
||||
if (consider_viewport ()) {
|
||||
viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ());
|
||||
}
|
||||
|
||||
if (! m_context_layers.empty ()) {
|
||||
|
||||
|
|
@ -583,7 +586,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
|
|||
|
||||
bool any_valid_edge = m_capture_all_shapes;
|
||||
for (db::Shape::polygon_edge_iterator e = shape->begin_edge (); ! e.at_end (); ++e) {
|
||||
if ((*e).clipped (viewport_box).first) {
|
||||
if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
|
||||
any_valid_edge = true;
|
||||
test_edge (t, *e, d, match);
|
||||
}
|
||||
|
|
@ -606,7 +609,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
|
|||
++pt;
|
||||
for (; pt != shape->end_point (); ++pt) {
|
||||
db::Edge e (p, *pt);
|
||||
if (e.clipped (viewport_box).first) {
|
||||
if (viewport_box.empty () || e.clipped (viewport_box).first) {
|
||||
any_valid_edge = true;
|
||||
test_edge (t, e, d, match);
|
||||
}
|
||||
|
|
@ -618,7 +621,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
|
|||
db::Polygon poly;
|
||||
shape->polygon (poly);
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
|
||||
if ((*e).clipped (viewport_box).first) {
|
||||
if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
|
||||
any_valid_edge = true;
|
||||
test_edge (t, *e, d, match);
|
||||
}
|
||||
|
|
@ -651,7 +654,7 @@ ShapeFinder::visit_cell (const db::Cell &cell, const db::Box &hit_box, const db:
|
|||
// convert to polygon and test those edges
|
||||
db::Polygon poly (box);
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
|
||||
if ((*e).clipped (viewport_box).first) {
|
||||
if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
|
||||
any_valid_edge = true;
|
||||
test_edge (t, *e, d, match);
|
||||
}
|
||||
|
|
@ -819,7 +822,10 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
|
|||
checkpoint ();
|
||||
|
||||
// Viewport in current cell coordinate space (DBU)
|
||||
db::Box viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ());
|
||||
db::Box viewport_box;
|
||||
if (consider_viewport ()) {
|
||||
viewport_box = (vp * db::CplxTrans (layout ().dbu ()) * t).inverted () * db::DBox (0, 0, view ()->viewport ().width (), view ()->viewport ().height ());
|
||||
}
|
||||
|
||||
if (! point_mode ()) {
|
||||
|
||||
|
|
@ -952,7 +958,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
|
|||
bool any_valid_edge = false;
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
|
||||
// only consider edges that cut through the viewport
|
||||
if ((*e).clipped (viewport_box).first) {
|
||||
if (viewport_box.empty () || (*e).clipped (viewport_box).first) {
|
||||
any_valid_edge = true;
|
||||
test_edge (t, *e, d, match);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,25 @@ public:
|
|||
m_catch_all = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating that the viewport will be considered
|
||||
*/
|
||||
bool consider_viewport () const
|
||||
{
|
||||
return m_consider_viewport;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating that the viewport will be considered
|
||||
* If this flag is true (the default), only shapes and instances will be considered
|
||||
* if edges (or polygons) or boundary edges (for instances) are visible in the
|
||||
* viewport. If this flag is false, shapes or instances are considered always.
|
||||
*/
|
||||
void set_consider_viewport (bool f)
|
||||
{
|
||||
m_consider_viewport = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor (just provided to please the compiler)
|
||||
*/
|
||||
|
|
@ -217,6 +236,7 @@ private:
|
|||
double m_distance;
|
||||
bool m_point_mode;
|
||||
bool m_catch_all;
|
||||
bool m_consider_viewport;
|
||||
bool m_top_level_sel;
|
||||
db::box_convert <db::CellInst, false> m_box_convert;
|
||||
db::box_convert <db::Cell, false> m_cell_box_convert;
|
||||
|
|
|
|||
|
|
@ -197,6 +197,12 @@ PluginDeclaration::init_menu (lay::Dispatcher *dispatcher)
|
|||
|
||||
if (! m->copy_from.empty ()) {
|
||||
|
||||
// As a general strategy for now we take primary ownership from the copy source as pass it to
|
||||
// the copy. This is important for "next/prev_display_state" as the first registry is @toolbar
|
||||
// (which is not accessible by Setup menu) and the second one is "zoom_menu" which should be
|
||||
// the primary one. For later, we may want to make this configurable (move/leave primary flag).
|
||||
menu.find_item_exact (m->copy_from)->set_primary (false);
|
||||
|
||||
menu.insert_item (m->insert_pos, m->menu_name, menu.action (m->copy_from));
|
||||
|
||||
} else if (m->separator) {
|
||||
|
|
|
|||
|
|
@ -621,7 +621,10 @@ END_PROTECTED
|
|||
void
|
||||
ViewObjectUI::set_cursor (lay::Cursor::cursor_shape cursor)
|
||||
{
|
||||
m_cursor = cursor;
|
||||
if (m_cursor != cursor) {
|
||||
m_cursor = cursor;
|
||||
realize_cursor ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -629,15 +632,7 @@ ViewObjectUI::set_default_cursor (lay::Cursor::cursor_shape cursor)
|
|||
{
|
||||
if (cursor != m_default_cursor) {
|
||||
m_default_cursor = cursor;
|
||||
#if defined(HAVE_QT)
|
||||
if (m_cursor == lay::Cursor::none && mp_widget) {
|
||||
if (m_default_cursor == lay::Cursor::none) {
|
||||
mp_widget->unsetCursor ();
|
||||
} else {
|
||||
mp_widget->setCursor (lay::Cursor::qcursor (m_default_cursor));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
realize_cursor ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -652,11 +647,17 @@ ViewObjectUI::ensure_entered ()
|
|||
void
|
||||
ViewObjectUI::begin_mouse_event (lay::Cursor::cursor_shape cursor)
|
||||
{
|
||||
m_cursor = cursor;
|
||||
set_cursor (cursor);
|
||||
}
|
||||
|
||||
void
|
||||
ViewObjectUI::end_mouse_event ()
|
||||
{
|
||||
realize_cursor ();
|
||||
}
|
||||
|
||||
void
|
||||
ViewObjectUI::realize_cursor ()
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_widget) {
|
||||
|
|
|
|||
|
|
@ -285,6 +285,14 @@ public:
|
|||
*/
|
||||
virtual void drag_cancel () { }
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the mouse receiver claims the view message bar
|
||||
*
|
||||
* If this method returns true, other services are not supposed to emit transient
|
||||
* messages.
|
||||
*/
|
||||
virtual bool claims_message_bar () const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether a cursor position it set
|
||||
*/
|
||||
|
|
@ -1121,6 +1129,7 @@ private:
|
|||
void objects_changed ();
|
||||
int widget_height () const;
|
||||
int widget_width () const;
|
||||
void realize_cursor ();
|
||||
|
||||
/**
|
||||
* @brief Register a service
|
||||
|
|
|
|||
|
|
@ -202,13 +202,32 @@ NetTracerDialog::item_double_clicked (QListWidgetItem *item)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetTracerDialog::drag_cancel ()
|
||||
{
|
||||
if (m_mouse_state > 0) {
|
||||
|
||||
view ()->message ();
|
||||
ui ()->ungrab_mouse (this);
|
||||
set_cursor (lay::Cursor::none);
|
||||
|
||||
m_mouse_state = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
NetTracerDialog::claims_message_bar () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NetTracerDialog::mouse_move_event (const db::DPoint & /*p*/, unsigned int /*buttons*/, bool prio)
|
||||
{
|
||||
if (prio && m_mouse_state != 0) {
|
||||
set_cursor (lay::Cursor::cross);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -397,11 +416,13 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
{
|
||||
unsigned int start_layer = 0;
|
||||
db::Point start_point;
|
||||
db::Shape start_shape;
|
||||
|
||||
// locate the seed
|
||||
{
|
||||
|
||||
lay::ShapeFinder finder (true /*point mode*/, false /*all levels*/, db::ShapeIterator::All);
|
||||
finder.set_consider_viewport (false);
|
||||
|
||||
// go through all visible layers of all cellviews and find a seed shape
|
||||
for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) {
|
||||
|
|
@ -417,7 +438,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
}
|
||||
|
||||
m_cv_index = r->cv_index ();
|
||||
|
||||
start_shape = r->shape ();
|
||||
start_layer = r->layer ();
|
||||
|
||||
}
|
||||
|
|
@ -440,6 +461,12 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
|
||||
start_point = tt.inverted ().trans (start_search_box.center ());
|
||||
|
||||
// stop if the center start point is not inside the start polygon
|
||||
db::Polygon poly;
|
||||
if (start_shape.polygon (poly) && db::inside_poly (poly.begin_edge (), start_point) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Set up the net tracer environment
|
||||
|
|
@ -455,6 +482,7 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
if (trace_path) {
|
||||
|
||||
lay::ShapeFinder finder (true /*point mode*/, false /*all levels*/, db::ShapeIterator::All);
|
||||
finder.set_consider_viewport (false);
|
||||
|
||||
// go through all visible layers of all cellviews and find a seed shape
|
||||
for (lay::LayerPropertiesConstIterator lprop = view ()->begin_layers (); ! lprop.at_end (); ++lprop) {
|
||||
|
|
@ -483,6 +511,12 @@ NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &sto
|
|||
stop_point = tt.inverted ().trans (stop_search_box.center ());
|
||||
stop_layer = r->layer ();
|
||||
|
||||
// stop if the center stop point is not inside the stop polygon
|
||||
db::Polygon poly;
|
||||
if (r->shape ().polygon (poly) && db::inside_poly (poly.begin_edge (), stop_point) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::NetTracer net_tracer;
|
||||
|
|
@ -1261,6 +1295,7 @@ NetTracerDialog::release_mouse ()
|
|||
m_mouse_state = 0;
|
||||
view ()->message ();
|
||||
ui ()->ungrab_mouse (this);
|
||||
set_cursor (lay::Cursor::none);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ public:
|
|||
NetTracerDialog (lay::Dispatcher *root, lay::LayoutViewBase *view);
|
||||
virtual ~NetTracerDialog ();
|
||||
|
||||
virtual void drag_cancel ();
|
||||
virtual bool claims_message_bar () const;
|
||||
virtual bool mouse_move_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
virtual bool mouse_click_event (const db::DPoint &p, unsigned int buttons, bool prio);
|
||||
virtual void menu_activated (const std::string &symbol);
|
||||
|
|
|
|||
|
|
@ -138,6 +138,21 @@ class _PCellDeclarationHelperMixin:
|
|||
self._finish()
|
||||
return text
|
||||
|
||||
def cell_name(self, parameters):
|
||||
"""
|
||||
Reimplementation of PCellDeclaration.cell_name
|
||||
|
||||
This function delegates the implementation to self.cell_name_impl
|
||||
after configuring the PCellDeclaration object.
|
||||
"""
|
||||
self._start()
|
||||
self._param_values = parameters
|
||||
try:
|
||||
text = self.cell_name_impl()
|
||||
finally:
|
||||
self._finish()
|
||||
return text
|
||||
|
||||
def get_parameters(self):
|
||||
"""
|
||||
Reimplementation of PCellDeclaration.get_parameters
|
||||
|
|
@ -333,6 +348,12 @@ class _PCellDeclarationHelperMixin:
|
|||
"""
|
||||
return ""
|
||||
|
||||
def cell_name_impl(self):
|
||||
"""
|
||||
default implementation
|
||||
"""
|
||||
return self.name()
|
||||
|
||||
def coerce_parameters_impl(self):
|
||||
"""
|
||||
default implementation
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -27,6 +27,10 @@ class BoxPCell(pya.PCellDeclaration):
|
|||
# provide a descriptive text for the cell
|
||||
return "Box(L=" + str(parameters[0]) + ",W=" + ('%.3f' % parameters[1]) + ",H=" + ('%.3f' % parameters[2]) + ")"
|
||||
|
||||
def cell_name(self, parameters):
|
||||
# provide a descriptive text for the cell
|
||||
return "Box_L" + str(parameters[0]).replace("/", "d") + "_W" + ('%.3f' % parameters[1]).replace(".", "p") + "_H" + ('%.3f' % parameters[2]).replace(".", "p")
|
||||
|
||||
def get_parameters(self):
|
||||
|
||||
# prepare a set of parameter declarations
|
||||
|
|
@ -100,6 +104,10 @@ if "PCellDeclarationHelper" in pya.__dict__:
|
|||
# provide a descriptive text for the cell
|
||||
return "Box2(L=" + str(self.layer) + ",W=" + ('%.3f' % self.width) + ",H=" + ('%.3f' % self.height) + ")"
|
||||
|
||||
def cell_name_impl(self):
|
||||
# provide a descriptive text for the cell
|
||||
return "Box2_L" + str(self.layer).replace("/", "d") + "_W" + ('%.3f' % self.width).replace(".", "p") + "_H" + ('%.3f' % self.height).replace(".", "p")
|
||||
|
||||
def wants_lazy_evaluation(self):
|
||||
return True
|
||||
|
||||
|
|
@ -260,6 +268,8 @@ class DBPCellTests(unittest.TestCase):
|
|||
self.assertEqual(pcell_var.is_pcell_variant(), True)
|
||||
self.assertEqual(pcell_var.display_title(), "PCellTestLib.Box(L=1/0,W=1.000,H=1.000)")
|
||||
self.assertEqual(pcell_var.basic_name(), "Box")
|
||||
self.assertEqual(pcell_var.qname(), "PCellTestLib.Box")
|
||||
self.assertEqual(pcell_var.name, "Box_L1d0_W1p000_H1p000")
|
||||
self.assertEqual(pcell_var.pcell_declaration().wants_lazy_evaluation(), False)
|
||||
self.assertEqual(c1.is_pcell_variant(), False)
|
||||
self.assertEqual(c1.is_pcell_variant(pcell_inst), True)
|
||||
|
|
@ -394,6 +404,8 @@ class DBPCellTests(unittest.TestCase):
|
|||
pcell_var = ly.cell(pcell_var_id)
|
||||
pcell_inst = c1.insert(pya.CellInstArray(pcell_var_id, pya.Trans()))
|
||||
self.assertEqual(pcell_var.basic_name(), "Box2")
|
||||
self.assertEqual(pcell_var.name, "Box2_L1d0_W1p000_H1p000")
|
||||
self.assertEqual(pcell_var.qname(), "PCellTestLib2.Box2")
|
||||
self.assertEqual(pcell_var.pcell_parameters().__repr__(), "[<1/0>, 1.0, 1.0]")
|
||||
self.assertEqual(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)")
|
||||
self.assertEqual(nh(pcell_var.pcell_parameters_by_name()), "{'height': 1.0, 'layer': <1/0>, 'width': 1.0}")
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ class BoxPCell < RBA::PCellDeclaration
|
|||
# provide a descriptive text for the cell
|
||||
return "Box(L=#{parameters[0].to_s},W=#{'%.3f' % parameters[1].to_s},H=#{'%.3f' % parameters[2].to_s})"
|
||||
end
|
||||
|
||||
def cell_name(parameters)
|
||||
# provide a cell name for the PCell
|
||||
return "Box_L#{parameters[0].to_s.gsub('/','d')}_W#{('%.3f' % parameters[1]).gsub('.','p')}_H#{('%.3f' % parameters[2]).gsub('.','p')}"
|
||||
end
|
||||
|
||||
def get_parameters
|
||||
|
||||
|
|
@ -129,6 +134,11 @@ if RBA.constants.member?(:PCellDeclarationHelper)
|
|||
return "Box2(L=" + layer.to_s + ",W=" + ('%.3f' % width) + ",H=" + ('%.3f' % height) + ")"
|
||||
end
|
||||
|
||||
def cell_name_impl
|
||||
# provide a cell name for the PCell
|
||||
return "Box2_L" + layer.to_s.gsub('/', 'd') + "_W" + ('%.3f' % width).gsub('.', 'p') + "_H" + ('%.3f' % height).gsub('.', 'p')
|
||||
end
|
||||
|
||||
def produce_impl
|
||||
|
||||
# fetch the parameters
|
||||
|
|
@ -371,6 +381,9 @@ class DBPCell_TestClass < TestBase
|
|||
param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults
|
||||
pcell_var_id = ly.add_pcell_variant(lib, pcell_decl_id, param)
|
||||
pcell_var = ly.cell(pcell_var_id)
|
||||
assert_equal(pcell_var.name, "Box_L1d0_W1p000_H1p000")
|
||||
assert_equal(pcell_var.qname, "PCellTestLib.Box")
|
||||
assert_equal(pcell_var.basic_name, "Box")
|
||||
pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new))
|
||||
assert_equal(pcell_var.layout.inspect, ly.inspect)
|
||||
assert_equal(pcell_var.library.inspect, lib.inspect)
|
||||
|
|
@ -512,6 +525,8 @@ class DBPCell_TestClass < TestBase
|
|||
pcell_var = ly.cell(pcell_var_id)
|
||||
pcell_inst = c1.insert(RBA::CellInstArray::new(pcell_var_id, RBA::Trans::new))
|
||||
assert_equal(pcell_var.basic_name, "Box2")
|
||||
assert_equal(pcell_var.name, "Box2_L1d0_W1p000_H1p000")
|
||||
assert_equal(pcell_var.qname, "PCellTestLib2.Box2")
|
||||
assert_equal(pcell_var.pcell_parameters().inspect, "[<1/0>, 1.0, 1.0, 0]")
|
||||
assert_equal(pcell_var.display_title(), "PCellTestLib2.Box2(L=1/0,W=1.000,H=1.000)")
|
||||
assert_equal(norm_hash(pcell_var.pcell_parameters_by_name()), "{\"height\"=>1.0, \"layer\"=><1/0>, \"secret\"=>0, \"width\"=>1.0}")
|
||||
|
|
@ -908,6 +923,37 @@ class DBPCell_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# convert to static cell
|
||||
def test_13
|
||||
|
||||
if !RBA.constants.member?(:PCellDeclarationHelper)
|
||||
return
|
||||
end
|
||||
|
||||
# instantiate and register the library
|
||||
tl = PCellTestLib2::new
|
||||
|
||||
ly = RBA::Layout::new(true)
|
||||
ly.dbu = 0.01
|
||||
|
||||
ci1 = ly.add_cell("c1")
|
||||
c1 = ly.cell(ci1)
|
||||
|
||||
lib = RBA::Library.library_by_name("PCellTestLib2")
|
||||
assert_equal(lib != nil, true)
|
||||
pcell_decl = lib.layout().pcell_declaration("Box2")
|
||||
|
||||
param = [ RBA::LayerInfo::new(1, 0) ] # rest is filled with defaults
|
||||
pcell_var_id = ly.add_pcell_variant(lib, pcell_decl.id(), param)
|
||||
static_id = ly.convert_cell_to_static(pcell_var_id)
|
||||
static = ly.cell(static_id)
|
||||
assert_equal(static.basic_name, "Box2_L1d0_W1p000_H1p000")
|
||||
assert_equal(static.name, "Box2_L1d0_W1p000_H1p000")
|
||||
assert_equal(static.qname, "Box2_L1d0_W1p000_H1p000")
|
||||
assert_equal(static.is_proxy?, false)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class DBPCellParameterStates_TestClass < TestBase
|
||||
|
|
|
|||
Loading…
Reference in New Issue