mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' of github.com:KLayout/klayout
This commit is contained in:
commit
e3f776a74e
|
|
@ -2198,15 +2198,29 @@ Service::paste ()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<const db::DUserObject *> new_objects;
|
||||
|
||||
for (db::Clipboard::iterator c = db::Clipboard::instance ().begin (); c != db::Clipboard::instance ().end (); ++c) {
|
||||
const db::ClipboardValue<ant::Object> *value = dynamic_cast<const db::ClipboardValue<ant::Object> *> (*c);
|
||||
if (value) {
|
||||
ant::Object *ruler = new ant::Object (value->get ());
|
||||
ruler->id (++idmax);
|
||||
mp_view->annotation_shapes ().insert (db::DUserObject (ruler));
|
||||
new_objects.push_back (&mp_view->annotation_shapes ().insert (db::DUserObject (ruler)));
|
||||
}
|
||||
}
|
||||
|
||||
// make new objects selected
|
||||
|
||||
if (! new_objects.empty ()) {
|
||||
|
||||
for (auto r = new_objects.begin (); r != new_objects.end (); ++r) {
|
||||
m_selected.insert (std::make_pair (mp_view->annotation_shapes ().iterator_from_pointer (*r), 0));
|
||||
}
|
||||
|
||||
selection_to_view ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map
|
|||
if (! var_table) {
|
||||
var_table = &var_table_intern;
|
||||
}
|
||||
tl_assert (var_table->empty ());
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator c = mp_layout->begin_bottom_up (); c != mp_layout->end_bottom_up (); ++c) {
|
||||
|
||||
|
|
@ -311,6 +312,9 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map
|
|||
|
||||
cell.clear_insts ();
|
||||
|
||||
bool original_cell_is_variant = false;
|
||||
db::ICplxTrans original_cell_variant;
|
||||
|
||||
int index = 0;
|
||||
for (auto v = vc->second.begin (); v != vc->second.end (); ++v, ++index) {
|
||||
|
||||
|
|
@ -333,6 +337,8 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map
|
|||
|
||||
} else {
|
||||
ci_var = *c;
|
||||
original_cell_is_variant = true;
|
||||
original_cell_variant = *v;
|
||||
}
|
||||
|
||||
vt.insert (std::make_pair (*v, ci_var));
|
||||
|
|
@ -341,12 +347,14 @@ VariantsCollectorBase::separate_variants (std::map<db::cell_index_type, std::map
|
|||
}
|
||||
|
||||
// correct the first (remaining) entry
|
||||
if (! vt.begin ()->first.is_unity ()) {
|
||||
std::set<db::ICplxTrans> &tv = m_variants [*c];
|
||||
tv.clear ();
|
||||
tv.insert (vt.begin ()->first);
|
||||
} else {
|
||||
m_variants.erase (*c);
|
||||
if (original_cell_is_variant) {
|
||||
if (! original_cell_variant.is_unity ()) {
|
||||
std::set<db::ICplxTrans> &tv = m_variants [*c];
|
||||
tv.clear ();
|
||||
tv.insert (original_cell_variant);
|
||||
} else {
|
||||
m_variants.erase (*c);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -644,6 +644,11 @@ void Circuit::set_pin_ref_for_pin (size_t pin_id, Net::pin_iterator iter)
|
|||
m_pin_refs [pin_id] = iter;
|
||||
}
|
||||
|
||||
bool Circuit::is_empty () const
|
||||
{
|
||||
return m_nets.empty () && m_pins.empty () && m_devices.empty () && m_subcircuits.empty ();
|
||||
}
|
||||
|
||||
void Circuit::blank ()
|
||||
{
|
||||
tl_assert (netlist () != 0);
|
||||
|
|
|
|||
|
|
@ -759,6 +759,11 @@ public:
|
|||
*/
|
||||
void blank ();
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the circuit is empty
|
||||
*/
|
||||
bool is_empty () const;
|
||||
|
||||
/**
|
||||
* @brief Generate memory statistics
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -298,28 +298,57 @@ struct DeepShapeStore::LayoutHolder
|
|||
{
|
||||
public:
|
||||
VariantsCreatedListener (DeepShapeStore::LayoutHolder *lh, db::Layout *ly)
|
||||
: mp_lh (lh)
|
||||
: mp_lh (lh), m_dbu (ly->dbu ())
|
||||
{
|
||||
ly->variants_created_event.add (this, &VariantsCreatedListener::variants_created);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string var_desc (const db::ICplxTrans &t)
|
||||
{
|
||||
std::string s;
|
||||
if (t.is_mirror ()) {
|
||||
s += "m";
|
||||
s += tl::to_string (t.angle () * 0.5);
|
||||
} else {
|
||||
s += "r";
|
||||
s += tl::to_string (t.angle ());
|
||||
}
|
||||
if (t.is_mag ()) {
|
||||
s += tl::sprintf ("*%.9g", t.mag ());
|
||||
}
|
||||
if (t.disp () != db::Vector ()) {
|
||||
s += tl::sprintf ("(%.12g,%.12g)", t.disp ().x () * m_dbu, t.disp ().y () * m_dbu);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void variants_created (const std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > *var_map)
|
||||
{
|
||||
for (std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> >::const_iterator i = var_map->begin (); i != var_map->end (); ++i) {
|
||||
for (std::map<db::ICplxTrans, db::cell_index_type>::const_iterator j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
mp_lh->builder.register_variant (i->first, j->second);
|
||||
if (i->first != j->second) {
|
||||
mp_lh->builder.register_variant (i->first, j->second, var_desc (j->first));
|
||||
}
|
||||
}
|
||||
// NOTE: variant conversion events are registered after variant formation events, so we can
|
||||
// base the formed variants (first pass) on the originals.
|
||||
for (std::map<db::ICplxTrans, db::cell_index_type>::const_iterator j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
if (i->first == j->second) {
|
||||
mp_lh->builder.register_variant (i->first, j->second, var_desc (j->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeepShapeStore::LayoutHolder *mp_lh;
|
||||
double m_dbu;
|
||||
};
|
||||
|
||||
LayoutHolder (const db::ICplxTrans &trans)
|
||||
: refs (0), layout (false), builder (&layout, trans), variants_created (this, &layout)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
layout.set_hierarchy_builder (&builder);
|
||||
}
|
||||
|
||||
void add_layer_ref (unsigned int layer)
|
||||
|
|
|
|||
|
|
@ -98,13 +98,13 @@ bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair) const
|
|||
// EdgePairFilterByArea implementation
|
||||
|
||||
InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double a, bool inverted)
|
||||
: m_inverted (inverted), m_checker (a, true, a, true)
|
||||
: m_checker (a, true, a, true, inverted, false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted)
|
||||
: m_inverted (inverted), m_checker (amin, include_amin, amax, include_amax)
|
||||
: m_checker (amin, include_amin, amax, include_amax, inverted, false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -122,7 +122,7 @@ InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair) const
|
|||
std::swap (d1, d2);
|
||||
}
|
||||
|
||||
return m_checker (d1, d2) != m_inverted;
|
||||
return m_checker (d1, d2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,8 +215,13 @@ EdgeSegmentSelector::process (const db::Edge &edge, std::vector<db::Edge> &res)
|
|||
// -------------------------------------------------------------------------------------------------------------
|
||||
// EdgeAngleChecker implementation
|
||||
|
||||
EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
if (absolute && angle_start < -db::epsilon) {
|
||||
angle_start = 0.0;
|
||||
include_angle_start = true;
|
||||
}
|
||||
|
||||
m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ());
|
||||
m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ());
|
||||
|
||||
|
|
@ -225,6 +230,9 @@ EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start
|
|||
|
||||
m_big_angle = (angle_end - angle_start + db::epsilon) > 180.0;
|
||||
m_all = (angle_end - angle_start - db::epsilon) > 360.0;
|
||||
|
||||
m_absolute = absolute;
|
||||
m_inverse = inverse;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -255,14 +263,14 @@ EdgeAngleChecker::check (const db::Vector &a, const db::Vector &b) const
|
|||
// -------------------------------------------------------------------------------------------------------------
|
||||
// EdgeOrientationFilter implementation
|
||||
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse)
|
||||
: m_inverse (inverse), m_checker (amin, include_amin, amax, include_amax)
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse, bool absolute)
|
||||
: m_checker (amin, include_amin, amax, include_amax, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse)
|
||||
: m_inverse (inverse), m_checker (a, true, a, true)
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse, bool absolute)
|
||||
: m_checker (a, true, a, true, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -273,9 +281,9 @@ EdgeOrientationFilter::selected (const db::Edge &edge) const
|
|||
// NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded).
|
||||
// A horizontal edge has 0 degree, a vertical one has 90 degree.
|
||||
if (edge.dx () < 0 || (edge.dx () == 0 && edge.dy () < 0)) {
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), -edge.d ()) != m_inverse;
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), -edge.d ());
|
||||
} else {
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), edge.d ()) != m_inverse;
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), edge.d ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,20 +297,20 @@ SpecialEdgeOrientationFilter::SpecialEdgeOrientationFilter (FilterType type, boo
|
|||
}
|
||||
|
||||
static EdgeAngleChecker s_ortho_checkers [] = {
|
||||
EdgeAngleChecker (0.0, true, 0.0, true),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true)
|
||||
EdgeAngleChecker (0.0, true, 0.0, true, false, false),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true, false, false)
|
||||
};
|
||||
|
||||
static EdgeAngleChecker s_diagonal_checkers [] = {
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true)
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true, false, false),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true, false, false)
|
||||
};
|
||||
|
||||
static EdgeAngleChecker s_orthodiagonal_checkers [] = {
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true),
|
||||
EdgeAngleChecker (0.0, true, 0.0, true),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true)
|
||||
EdgeAngleChecker (-45.0, true, -45.0, true, false, false),
|
||||
EdgeAngleChecker (0.0, true, 0.0, true, false, false),
|
||||
EdgeAngleChecker (45.0, true, 45.0, true, false, false),
|
||||
EdgeAngleChecker (90.0, true, 90.0, true, false, false)
|
||||
};
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -142,22 +142,23 @@ private:
|
|||
class DB_PUBLIC EdgeAngleChecker
|
||||
{
|
||||
public:
|
||||
EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end);
|
||||
EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute);
|
||||
|
||||
bool operator() (const db::Edge &a, const db::Edge &b) const
|
||||
{
|
||||
return m_all || check (a.d (), b.d ());
|
||||
return (m_all || check (a.d (), b.d ()) || (m_absolute && check (b.d (), a.d ()))) != m_inverse;
|
||||
}
|
||||
|
||||
bool operator() (const db::Vector &a, const db::Vector &b) const
|
||||
{
|
||||
return m_all || check (a, b);
|
||||
return (m_all || check (a, b) || (m_absolute && check (b, a))) != m_inverse;
|
||||
}
|
||||
|
||||
private:
|
||||
db::CplxTrans m_t_start, m_t_end;
|
||||
bool m_include_start, m_include_end;
|
||||
bool m_big_angle, m_all;
|
||||
bool m_inverse, m_absolute;
|
||||
|
||||
bool check (const db::Vector &a, const db::Vector &b) const;
|
||||
};
|
||||
|
|
@ -181,22 +182,24 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
* @param amin The minimum angle (measured against the x axis)
|
||||
* @param amax The maximum angle (measured against the x axis)
|
||||
* @param inverse If set to true, only edges not matching this criterion will be filtered
|
||||
* @param absolute Angles are always positive
|
||||
*
|
||||
* This filter will filter out all edges whose angle against x axis
|
||||
* is larger or equal to amin and less than amax.
|
||||
*/
|
||||
EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse);
|
||||
EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse, bool absolute);
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param a The angle (measured against the x axis)
|
||||
* @param inverse If set to true, only edges not matching this criterion will be filtered
|
||||
* @param absolute Angles are always positive
|
||||
*
|
||||
* This filter will filter out all edges whose angle against x axis
|
||||
* is equal to a.
|
||||
*/
|
||||
EdgeOrientationFilter (double a, bool inverse);
|
||||
EdgeOrientationFilter (double a, bool inverse, bool absolute);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the edge orientation matches the criterion
|
||||
|
|
|
|||
|
|
@ -1216,11 +1216,13 @@ struct cluster_building_receiver
|
|||
db::Connectivity::global_nets_iterator ge = mp_conn->end_global_connections (p.first);
|
||||
for (db::Connectivity::global_nets_iterator g = mp_conn->begin_global_connections (p.first); g != ge; ++g) {
|
||||
|
||||
bool soft = (g->second != 0);
|
||||
|
||||
typename std::map<size_t, typename std::list<cluster_value>::iterator>::iterator icg = m_global_to_clusters.find (g->first);
|
||||
|
||||
if (icg == m_global_to_clusters.end ()) {
|
||||
|
||||
if (g->second != 0) {
|
||||
if (soft) {
|
||||
|
||||
// soft connection to a new global cluster
|
||||
m_clusters.push_back (cluster_value ());
|
||||
|
|
@ -1240,7 +1242,7 @@ struct cluster_building_receiver
|
|||
|
||||
} else if (ic->second != icg->second) {
|
||||
|
||||
if (g->second != 0) {
|
||||
if (soft) {
|
||||
|
||||
register_soft_connection (ic->second, icg->second, g->second);
|
||||
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@ public:
|
|||
typedef db::box_tree<box_type, local_cluster<T>, local_cluster_box_convert<T> > tree_type;
|
||||
typedef typename tree_type::touching_iterator touching_iterator;
|
||||
typedef typename tree_type::const_iterator const_iterator;
|
||||
typedef typename tree_type::iterator iterator;
|
||||
|
||||
/**
|
||||
* @brief Creates an empty collection
|
||||
|
|
@ -566,6 +567,22 @@ public:
|
|||
return m_clusters.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the clusters (begin iterator)
|
||||
*/
|
||||
iterator begin ()
|
||||
{
|
||||
return m_clusters.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the clusters (end iterator)
|
||||
*/
|
||||
iterator end ()
|
||||
{
|
||||
return m_clusters.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the cluster set is empty
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -182,14 +182,24 @@ HierarchyBuilder::reset ()
|
|||
|
||||
m_cells_to_be_filled.clear ();
|
||||
m_cell_map.clear ();
|
||||
m_variants_of_sources_map.clear ();
|
||||
m_cells_seen.clear ();
|
||||
m_cell_stack.clear ();
|
||||
m_cm_entry = null_iterator;
|
||||
m_cm_new_entry = false;
|
||||
}
|
||||
|
||||
const std::pair<db::cell_index_type, std::string> &
|
||||
HierarchyBuilder::variant_of_source (db::cell_index_type target) const
|
||||
{
|
||||
static std::pair<db::cell_index_type, std::string> def (std::numeric_limits<db::cell_index_type>::max (), std::string ());
|
||||
|
||||
auto vs = m_variants_of_sources_map.find (target);
|
||||
return vs != m_variants_of_sources_map.end () ? vs->second : def;
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_type var)
|
||||
HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_type var, const std::string &description)
|
||||
{
|
||||
// non_var (despite its name) may be a variant created previously.
|
||||
variant_to_original_target_map_type::const_iterator v = m_variants_to_original_target_map.find (non_var);
|
||||
|
|
@ -199,11 +209,23 @@ HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_
|
|||
|
||||
m_original_targets_to_variants_map [non_var].push_back (var);
|
||||
m_variants_to_original_target_map.insert (std::make_pair (var, non_var));
|
||||
|
||||
auto vs = m_variants_of_sources_map.find (non_var);
|
||||
if (vs != m_variants_of_sources_map.end ()) {
|
||||
std::string new_description = vs->second.second;
|
||||
if (! new_description.empty ()) {
|
||||
new_description += ";";
|
||||
}
|
||||
new_description += description;
|
||||
m_variants_of_sources_map [var] = std::make_pair (vs->second.first, new_description);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::unregister_variant (db::cell_index_type var)
|
||||
{
|
||||
m_variants_of_sources_map.erase (var);
|
||||
|
||||
variant_to_original_target_map_type::iterator v = m_variants_to_original_target_map.find (var);
|
||||
if (v == m_variants_to_original_target_map.end ()) {
|
||||
return;
|
||||
|
|
@ -257,6 +279,7 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
|
|||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.original_cell));
|
||||
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first;
|
||||
m_variants_of_sources_map.insert (std::make_pair (new_top_index, std::make_pair (key.original_cell, std::string ())));
|
||||
}
|
||||
|
||||
db::Cell &new_top = mp_target->cell (m_cm_entry->second);
|
||||
|
|
@ -324,17 +347,34 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
|
|||
if (m_cm_entry == m_cell_map.end ()) {
|
||||
|
||||
std::string cn = cell_name;
|
||||
std::string description;
|
||||
if (! key.clip_region.empty ()) {
|
||||
cn += "$CLIP_VAR";
|
||||
description += "CLIP";
|
||||
|
||||
}
|
||||
if (key.inactive) {
|
||||
cn += "$DIS";
|
||||
if (! description.empty ()) {
|
||||
description += "/";
|
||||
}
|
||||
description += "DISABLED";
|
||||
}
|
||||
|
||||
new_cell = mp_target->add_cell (cn.c_str ());
|
||||
|
||||
std::string new_name = mp_target->cell_name (new_cell);
|
||||
if (new_name.size () > cn.size ()) {
|
||||
// use cell name extension to uniquify the description
|
||||
description += new_name.c_str () + cn.size ();
|
||||
}
|
||||
|
||||
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
|
||||
m_cm_new_entry = true;
|
||||
m_cells_to_be_filled.insert (new_cell);
|
||||
|
||||
m_variants_of_sources_map.insert (std::make_pair (new_cell, std::make_pair (key.original_cell, description)));
|
||||
|
||||
} else {
|
||||
new_cell = m_cm_entry->second;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ public:
|
|||
* The first cell is either the original, non-variant target cell or itself a variant.
|
||||
* The second cell will be registered as a variant of the first one.
|
||||
*/
|
||||
void register_variant (db::cell_index_type non_var, db::cell_index_type var);
|
||||
void register_variant (db::cell_index_type non_var, db::cell_index_type var, const std::string &description);
|
||||
|
||||
/**
|
||||
* @brief Unregisters a cell as a variant
|
||||
|
|
@ -404,8 +404,23 @@ public:
|
|||
return m_variants_to_original_target_map.find (ci) != m_variants_to_original_target_map.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the information about the target/source + variant relationship
|
||||
*
|
||||
* For a target cell, returns a pointer to a pair with the cell index of the source cell and
|
||||
* a string describing the variant this cell forms of the source cell.
|
||||
*
|
||||
* The description string is empty if the cell is not a variant.
|
||||
*/
|
||||
const std::pair<db::cell_index_type, std::string> &variant_of_source (db::cell_index_type target) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the original target for a variant cell
|
||||
*
|
||||
* The original cell is the first-generation target-space cell that variants have been created for.
|
||||
* This still can mean that the original cell is a clip variant of a source cell.
|
||||
*
|
||||
* Target-to-source variants can be derived with "variant_of_source".
|
||||
*/
|
||||
db::cell_index_type original_target_for_variant (db::cell_index_type ci) const;
|
||||
|
||||
|
|
@ -419,6 +434,7 @@ private:
|
|||
cell_map_type m_cell_map;
|
||||
original_target_to_variants_map_type m_original_targets_to_variants_map;
|
||||
variant_to_original_target_map_type m_variants_to_original_target_map;
|
||||
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::string> > m_variants_of_sources_map;
|
||||
|
||||
std::set<cell_map_type::key_type> m_cells_seen;
|
||||
std::set<db::cell_index_type> m_cells_to_be_filled;
|
||||
|
|
|
|||
|
|
@ -439,6 +439,7 @@ LayoutOrCellContextInfo::has_meta_info () const
|
|||
Layout::Layout (db::Manager *manager)
|
||||
: db::Object (manager),
|
||||
mp_library (0),
|
||||
mp_builder (0),
|
||||
m_cells_size (0),
|
||||
m_invalid (0),
|
||||
m_top_cells (0),
|
||||
|
|
@ -454,6 +455,7 @@ Layout::Layout (db::Manager *manager)
|
|||
Layout::Layout (bool editable, db::Manager *manager)
|
||||
: db::Object (manager),
|
||||
mp_library (0),
|
||||
mp_builder (0),
|
||||
m_cells_size (0),
|
||||
m_invalid (0),
|
||||
m_top_cells (0),
|
||||
|
|
@ -473,6 +475,7 @@ Layout::Layout (const db::Layout &layout)
|
|||
tl::Object (),
|
||||
tl::UniqueId (),
|
||||
mp_library (0),
|
||||
mp_builder (0),
|
||||
m_cells_size (0),
|
||||
m_invalid (0),
|
||||
m_top_cells (0),
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ class Technology;
|
|||
class CellMapping;
|
||||
class LayerMapping;
|
||||
class VariantsCollectorBase;
|
||||
class HierarchyBuilder;
|
||||
|
||||
template <class Coord> class generic_repository;
|
||||
typedef generic_repository<db::Coord> GenericRepository;
|
||||
|
|
@ -2113,6 +2114,24 @@ public:
|
|||
*/
|
||||
const MetaInfo &meta_info (db::cell_index_type ci, meta_info_name_id_type name_id) const;
|
||||
|
||||
/**
|
||||
* @brief Sets the hierarchy builder reference
|
||||
* Used internally
|
||||
*/
|
||||
void set_hierarchy_builder (db::HierarchyBuilder *builder)
|
||||
{
|
||||
mp_builder = builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the hierarchy builder
|
||||
* Used internally
|
||||
*/
|
||||
db::HierarchyBuilder *builder () const
|
||||
{
|
||||
return mp_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This event is triggered when the technology changes
|
||||
*/
|
||||
|
|
@ -2138,6 +2157,7 @@ protected:
|
|||
|
||||
private:
|
||||
db::Library *mp_library;
|
||||
db::HierarchyBuilder *mp_builder;
|
||||
cell_list m_cells;
|
||||
size_t m_cells_size;
|
||||
cell_ptr_vector m_cell_ptrs;
|
||||
|
|
|
|||
|
|
@ -395,12 +395,18 @@ void LayoutToNetlistStandardReader::read_netlist (db::Netlist *netlist, db::Layo
|
|||
throw tl::Exception (tl::to_string (tr ("Duplicate definition of device class: ")) + class_name);
|
||||
}
|
||||
|
||||
db::DeviceClassTemplateBase *dct = db::DeviceClassTemplateBase::template_by_name (templ_name);
|
||||
if (! dct) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid device class template: ")) + templ_name);
|
||||
db::DeviceClass *dc;
|
||||
if (templ_name.empty ()) {
|
||||
// generic device class (issue #1696)
|
||||
dc = new db::DeviceClass ();
|
||||
} else {
|
||||
db::DeviceClassTemplateBase *dct = db::DeviceClassTemplateBase::template_by_name (templ_name);
|
||||
if (! dct) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid device class template: ")) + templ_name);
|
||||
}
|
||||
dc = dct->create ();
|
||||
}
|
||||
|
||||
db::DeviceClass *dc = dct->create ();
|
||||
dc->set_name (class_name);
|
||||
netlist->add_device_class (dc);
|
||||
|
||||
|
|
|
|||
|
|
@ -228,8 +228,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
const db::Cell &cell = mp_layout->cell (*cid);
|
||||
|
||||
const connected_clusters_type &clusters = mp_clusters->clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
connected_clusters_type &per_cell_clusters = mp_clusters->clusters_per_cell (*cid);
|
||||
if (per_cell_clusters.empty ()) {
|
||||
|
||||
bool any_good = false;
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
if (dm) {
|
||||
// This is a device abstract cell:
|
||||
// make the terminal to cluster ID connections for the device abstract from the device cells
|
||||
make_device_abstract_connections (dm, clusters);
|
||||
make_device_abstract_connections (dm, per_cell_clusters);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -284,12 +284,12 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
}
|
||||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
for (connected_clusters_type::all_iterator c = per_cell_clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
const db::local_cluster<db::NetShape> &lc = clusters.cluster_by_id (*c);
|
||||
const connected_clusters_type::connections_type &cc = clusters.connections_for_cluster (*c);
|
||||
const std::set<size_t> &sc_up = clusters.upward_soft_connections (*c);
|
||||
const std::set<size_t> &sc_down = clusters.downward_soft_connections (*c);
|
||||
const db::local_cluster<db::NetShape> &lc = per_cell_clusters.cluster_by_id (*c);
|
||||
const connected_clusters_type::connections_type &cc = per_cell_clusters.connections_for_cluster (*c);
|
||||
const std::set<size_t> &sc_up = per_cell_clusters.upward_soft_connections (*c);
|
||||
const std::set<size_t> &sc_down = per_cell_clusters.downward_soft_connections (*c);
|
||||
if (cc.empty () && sc_up.empty () && sc_down.empty () && lc.empty ()) {
|
||||
// this is an entirely empty cluster so we skip it.
|
||||
// Such clusters are left over when joining clusters.
|
||||
|
|
@ -301,14 +301,14 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
circuit->add_net (net);
|
||||
|
||||
// make subcircuit connections (also make the subcircuits if required) from the connections of the clusters
|
||||
make_and_connect_subcircuits (circuit, clusters, *c, net, subcircuits, circuits, pins_per_cluster_per_cell);
|
||||
make_and_connect_subcircuits (circuit, per_cell_clusters, *c, net, subcircuits, circuits, pins_per_cluster_per_cell);
|
||||
|
||||
// connect devices
|
||||
connect_devices (circuit, clusters, *c, net);
|
||||
connect_devices (circuit, per_cell_clusters, *c, net);
|
||||
|
||||
// collect labels to net names
|
||||
std::set<std::string> net_names;
|
||||
collect_labels (clusters, *c, net_names);
|
||||
collect_labels (per_cell_clusters, *c, net_names);
|
||||
|
||||
// add the global names as second priority
|
||||
if (net_names.empty ()) {
|
||||
|
|
@ -323,7 +323,7 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
// made to satisfy the subcircuit's pin, but not to make a physical connection.
|
||||
// Don't know whether this is a good idea, so this code is disabled for now.
|
||||
|
||||
if (net_names.empty () && clusters.is_dummy (*c) && net->subcircuit_pin_count () == 1) {
|
||||
if (net_names.empty () && per_cell_clusters.is_dummy (*c) && net->subcircuit_pin_count () == 1) {
|
||||
// in the case of a dummy connection (partially connected subcircuits) create a
|
||||
// new name indicating the subcircuit and the subcircuit net name - this makes subcircuit
|
||||
// net names available (the net is pseudo-root inside in the subcircuit)
|
||||
|
|
@ -337,7 +337,7 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
assign_net_names (net, net_names);
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
if (! per_cell_clusters.is_root (*c)) {
|
||||
// a non-root cluster makes a pin
|
||||
size_t pin_id = make_pin (circuit, net);
|
||||
c2p.insert (std::make_pair (*c, pin_id));
|
||||
|
|
@ -364,28 +364,73 @@ NetlistExtractor::assign_net_names (db::Net *net, const std::set<std::string> &n
|
|||
net->set_name (nn);
|
||||
}
|
||||
|
||||
static void
|
||||
collect_soft_connected_clusters (size_t from_id, const NetlistExtractor::connected_clusters_type &clusters, std::set<size_t> &ids)
|
||||
{
|
||||
if (ids.find (from_id) != ids.end ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ids.insert (from_id);
|
||||
|
||||
auto upward = clusters.upward_soft_connections (from_id);
|
||||
for (auto i = upward.begin (); i != upward.end (); ++i) {
|
||||
collect_soft_connected_clusters (*i, clusters, ids);
|
||||
}
|
||||
|
||||
auto downward = clusters.downward_soft_connections (from_id);
|
||||
for (auto i = downward.begin (); i != downward.end (); ++i) {
|
||||
collect_soft_connected_clusters (*i, clusters, ids);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NetlistExtractor::make_device_abstract_connections (db::DeviceAbstract *dm, const connected_clusters_type &clusters)
|
||||
NetlistExtractor::make_device_abstract_connections (db::DeviceAbstract *dm, connected_clusters_type &clusters)
|
||||
{
|
||||
// make the terminal to cluster ID connections for the device abstract from the device cells
|
||||
|
||||
if (m_terminal_annot_name_id.first) {
|
||||
|
||||
for (connected_clusters_type::const_iterator dc = clusters.begin (); dc != clusters.end (); ++dc) {
|
||||
for (connected_clusters_type::iterator dc = clusters.begin (); dc != clusters.end (); ++dc) {
|
||||
|
||||
for (local_cluster_type::attr_iterator a = dc->begin_attr (); a != dc->end_attr (); ++a) {
|
||||
std::set<size_t> ids;
|
||||
collect_soft_connected_clusters (dc->id (), clusters, ids);
|
||||
|
||||
for (auto id = ids.begin (); id != ids.end (); ++id) {
|
||||
|
||||
const local_cluster_type &lc = clusters.cluster_by_id (*id);
|
||||
bool join = false;
|
||||
|
||||
for (local_cluster_type::attr_iterator a = lc.begin_attr (); a != lc.end_attr (); ++a) {
|
||||
|
||||
if (! db::is_prop_id_attr (*a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
|
||||
if (j->first == m_terminal_annot_name_id.second) {
|
||||
|
||||
size_t terminal_id = j->second.to<size_t> ();
|
||||
if (*id != dc->id ()) {
|
||||
tl::warn << tl::sprintf (tl::to_string (tr ("Ignoring soft connection at device terminal %s for device %s")), dm->device_class ()->terminal_definition (terminal_id)->name (), dm->device_class ()->name ());
|
||||
join = true;
|
||||
}
|
||||
|
||||
dm->set_cluster_id_for_terminal (terminal_id, dc->id ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! db::is_prop_id_attr (*a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_terminal_annot_name_id.second) {
|
||||
dm->set_cluster_id_for_terminal (j->second.to<size_t> (), dc->id ());
|
||||
}
|
||||
if (join) {
|
||||
// copy the terminal attributes and shapes so we attach the terminal here in the device connection step
|
||||
clusters.join_cluster_with (dc->id (), *id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ private:
|
|||
/**
|
||||
* @brief Makes the terminal to cluster ID connections of the device abstract
|
||||
*/
|
||||
void make_device_abstract_connections (db::DeviceAbstract *dm, const connected_clusters_type &clusters);
|
||||
void make_device_abstract_connections (db::DeviceAbstract *dm, connected_clusters_type &clusters);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -943,6 +943,12 @@ SpiceNetlistBuilder::circuit_for (const SpiceCachedCircuit *cc, const parameters
|
|||
if (cp == c->second.end ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a null pointer indicates that we are currently defining this circuit
|
||||
if (cp->second == 0) {
|
||||
error (tl::sprintf (tl::to_string (tr ("Subcircuit '%s' called recursively")), cc->name ()));
|
||||
}
|
||||
|
||||
return cp->second;
|
||||
}
|
||||
|
||||
|
|
@ -1055,7 +1061,8 @@ SpiceNetlistBuilder::build_circuit (const SpiceCachedCircuit *cc, const paramete
|
|||
c->set_name (make_circuit_name (cc->name (), pv));
|
||||
}
|
||||
|
||||
register_circuit_for (cc, pv, c, anonymous_top_level);
|
||||
// pre-register the circuit - allows detecting recursive calls
|
||||
register_circuit_for (cc, pv, 0, false);
|
||||
|
||||
std::unique_ptr<std::map<std::string, db::Net *> > n2n (mp_nets_by_name.release ());
|
||||
mp_nets_by_name.reset (0);
|
||||
|
|
@ -1095,6 +1102,14 @@ SpiceNetlistBuilder::build_circuit (const SpiceCachedCircuit *cc, const paramete
|
|||
std::swap (c, mp_netlist_circuit);
|
||||
std::swap (vars, m_variables);
|
||||
|
||||
// final registration if required
|
||||
if (! anonymous_top_level || ! c->is_empty ()) {
|
||||
register_circuit_for (cc, pv, c, anonymous_top_level);
|
||||
} else {
|
||||
mp_netlist->remove_circuit (c);
|
||||
c = 0;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ namespace db
|
|||
// -----------------------------------------------------------------------------------
|
||||
// CornerDetectorCore implementation
|
||||
|
||||
CornerDetectorCore::CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: m_checker (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
CornerDetectorCore::CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
: m_checker (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ private:
|
|||
class DB_PUBLIC CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end);
|
||||
CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute);
|
||||
virtual ~CornerDetectorCore () { }
|
||||
|
||||
void detect_corners (const db::Polygon &poly, const CornerPointDelivery &delivery) const;
|
||||
|
|
@ -130,8 +130,8 @@ class DB_PUBLIC CornersAsRectangles
|
|||
: public db::PolygonProcessorBase, private CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornersAsRectangles (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end), m_dim (dim)
|
||||
CornersAsRectangles (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute, db::Coord dim = 1)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute), m_dim (dim)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -159,8 +159,8 @@ class DB_PUBLIC CornersAsDots
|
|||
: public db::PolygonToEdgeProcessorBase, private CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornersAsDots (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
CornersAsDots (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -184,8 +184,8 @@ class DB_PUBLIC CornersAsEdgePairs
|
|||
: public db::PolygonToEdgePairProcessorBase, private CornerDetectorCore
|
||||
{
|
||||
public:
|
||||
CornersAsEdgePairs (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
CornersAsEdgePairs (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
: CornerDetectorCore (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,22 +214,22 @@ static db::CompoundRegionOperationNode *new_count_filter (db::CompoundRegionOper
|
|||
return new db::CompoundRegionCountFilterNode (input, invert, min_count, max_count);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim = 1)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, db::Coord dim, bool inverse, bool absolute)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim), input, true /*processor is owned*/, dim /*dist adder*/);
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute, dim), input, true /*processor is owned*/, dim /*dist adder*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_corners_as_edge_pairs (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
static db::CompoundRegionOperationNode *new_corners_as_edge_pairs (db::CompoundRegionOperationNode *input, double angle_start, bool include_angle_start, double angle_end, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionToEdgePairProcessingOperationNode (new db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_extents (db::CompoundRegionOperationNode *input, db::Coord e)
|
||||
|
|
@ -341,10 +341,10 @@ static db::CompoundRegionOperationNode *new_edge_length_sum_filter (db::Compound
|
|||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeLengthFilter (lmin, lmax, inverse), input, true /*processor is owned*/, true /*sum*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_edge_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, bool include_amin, double amax, bool include_amax)
|
||||
static db::CompoundRegionOperationNode *new_edge_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, bool include_amin, double amax, bool include_amax, bool absolute_angle)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, include_amin, amax, include_amax, inverse), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, include_amin, amax, include_amax, inverse, absolute_angle), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_polygons (db::CompoundRegionOperationNode *input, db::Coord e)
|
||||
|
|
@ -617,17 +617,21 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
gsi::constructor ("new_count_filter", &new_count_filter, gsi::arg ("inputs"), gsi::arg ("invert", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max ()),
|
||||
"@brief Creates a node selecting results but their shape count.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("dim"),
|
||||
gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("dim"), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief Creates a node turning corners into rectangles.\n"
|
||||
"\n"
|
||||
"'absolute' and 'inverse' arguments have been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"),
|
||||
gsi::constructor ("new_corners_as_dots", &new_corners_as_dots, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief Creates a node turning corners into dots (single-point edges).\n"
|
||||
"\n"
|
||||
"'absolute' and 'inverse' arguments have been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::constructor ("new_corners_as_edge_pairs", &new_corners_as_edge_pairs, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"),
|
||||
gsi::constructor ("new_corners_as_edge_pairs", &new_corners_as_edge_pairs, gsi::arg ("input"), gsi::arg ("angle_min"), gsi::arg ("include_angle_min"), gsi::arg ("angle_max"), gsi::arg ("include_angle_max"), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief Creates a node turning corners into edge pairs containing the two edges adjacent to the corner.\n"
|
||||
"The first edge will be the incoming edge and the second one the outgoing edge.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.27.1.\n"
|
||||
"This feature has been introduced in version 0.27.1. 'absolute' and 'inverse' arguments have been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::constructor ("new_extents", &new_extents, gsi::arg ("input"), gsi::arg ("e", 0),
|
||||
"@brief Creates a node returning the extents of the objects.\n"
|
||||
|
|
@ -759,8 +763,10 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
gsi::constructor ("new_edge_length_sum_filter", &new_edge_length_sum_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits<db::Edge::distance_type>::max (), "max"),
|
||||
"@brief Creates a node filtering edges by their length sum (over the local set).\n"
|
||||
) +
|
||||
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse"), gsi::arg ("amin"), gsi::arg ("include_amin"), gsi::arg ("amax"), gsi::arg ("include_amax"),
|
||||
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse"), gsi::arg ("amin"), gsi::arg ("include_amin"), gsi::arg ("amax"), gsi::arg ("include_amax"), gsi::arg ("absolute_angle", false),
|
||||
"@brief Creates a node filtering edges by their orientation.\n"
|
||||
"\n"
|
||||
"'absolute_angle' has been introduced in version 0.29.1."
|
||||
) +
|
||||
gsi::constructor ("new_polygons", &new_polygons, gsi::arg ("input"), gsi::arg ("e", 0),
|
||||
"@brief Creates a node converting the input to polygons.\n"
|
||||
|
|
|
|||
|
|
@ -432,14 +432,28 @@ static db::EdgePairs with_length_both2 (const db::EdgePairs *r, const tl::Varian
|
|||
|
||||
static db::EdgePairs with_angle1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse);
|
||||
db::EdgeOrientationFilter f (a, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_angle2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
|
@ -453,14 +467,28 @@ static db::EdgePairs with_angle3 (const db::EdgePairs *r, db::SpecialEdgeOrienta
|
|||
|
||||
static db::EdgePairs with_angle_both1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse);
|
||||
db::EdgeOrientationFilter f (a, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_angle_both2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, false);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle_both1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_abs_angle_both2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, true);
|
||||
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
|
||||
return r->filtered (ef);
|
||||
}
|
||||
|
|
@ -967,6 +995,22 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
"\n"
|
||||
"This method has been added in version 0.27.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_angle", with_angle3, gsi::arg ("type"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
|
||||
|
|
@ -1027,6 +1071,21 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
"\n"
|
||||
"This method has been added in version 0.27.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle_both", with_abs_angle_both1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of both of their edges\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle_both, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle_both", with_abs_angle_both2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
|
||||
"\n"
|
||||
"This method behaves like \\with_angle_both, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_angle_both", with_angle_both3, gsi::arg ("type"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edge pairs by orientation of their edges\n"
|
||||
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
|
||||
|
|
|
|||
|
|
@ -440,13 +440,25 @@ static db::Edges with_length2 (const db::Edges *r, const tl::Variant &min, const
|
|||
|
||||
static db::Edges with_angle1 (const db::Edges *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse);
|
||||
db::EdgeOrientationFilter f (a, inverse, false);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Edges with_angle2 (const db::Edges *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, false);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Edges with_abs_angle1 (const db::Edges *r, double a, bool inverse)
|
||||
{
|
||||
db::EdgeOrientationFilter f (a, inverse, true);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Edges with_abs_angle2 (const db::Edges *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse, true);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
|
|
@ -923,7 +935,23 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the "
|
||||
"minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n"
|
||||
"\n"
|
||||
"The two \"include..\" arguments have been added in version 0.27."
|
||||
"The two \"include..\" arguments have been added in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Filter the edges by orientation\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_abs_angle", with_abs_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
|
||||
"@brief Filter the edges by orientation\n"
|
||||
"\n"
|
||||
"This method behaves like \\with_angle, but angles are always positive - i.e. there is no "
|
||||
"differentiation between edges sloping 'down' vs. edges sloping 'up.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("with_angle", with_angle3, gsi::arg ("type"), gsi::arg ("inverse"),
|
||||
"@brief Filters the edges by orientation type\n"
|
||||
|
|
|
|||
|
|
@ -300,19 +300,19 @@ static db::Region *texts_as_boxes2 (const db::Region *r, db::DeepShapeStore &dss
|
|||
return new db::Region (r->texts_as_boxes (pat, pattern, enl, dss));
|
||||
}
|
||||
|
||||
static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end)
|
||||
static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
return r->processed (db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end));
|
||||
return r->processed (db::CornersAsDots (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute));
|
||||
}
|
||||
|
||||
static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim, bool include_angle_start, bool include_angle_end)
|
||||
static db::Region corners_to_boxes (const db::Region *r, double angle_start, double angle_end, db::Coord dim, bool include_angle_start, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
return r->processed (db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, dim));
|
||||
return r->processed (db::CornersAsRectangles (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute, dim));
|
||||
}
|
||||
|
||||
static db::EdgePairs corners_to_edge_pairs (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end)
|
||||
static db::EdgePairs corners_to_edge_pairs (const db::Region *r, double angle_start, double angle_end, bool include_angle_start, bool include_angle_end, bool inverse, bool absolute)
|
||||
{
|
||||
return r->processed (db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end));
|
||||
return r->processed (db::CornersAsEdgePairs (angle_start, include_angle_start, angle_end, include_angle_end, inverse, absolute));
|
||||
}
|
||||
|
||||
static db::Region *new_si (const db::RecursiveShapeIterator &si)
|
||||
|
|
@ -1697,7 +1697,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"@hide\n"
|
||||
"This method is provided for DRC implementation.\n"
|
||||
) +
|
||||
method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_min", -180.0), gsi::arg ("angle_max", 180.0), gsi::arg ("dim", 1), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
method_ext ("corners", &corners_to_boxes, gsi::arg ("angle_min", -180.0), gsi::arg ("angle_max", 180.0), gsi::arg ("dim", 1), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||
"\n"
|
||||
"The angle values specify a range of angles: all corners whose attached edges form an angle "
|
||||
|
|
@ -1706,29 +1706,35 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"If 'include_angle_min' is true, the angle condition is >= min. angle, otherwise it is > min. angle. "
|
||||
"Same for 'include_angle_,ax' and the max. angle.\n"
|
||||
"\n"
|
||||
"The angle is measured "
|
||||
"With 'absolute' set to false (the default), the angle is measured "
|
||||
"between the incoming and the outcoming edge in mathematical sense: a positive value is a turn left "
|
||||
"while a negative value is a turn right. Since polygon contours are oriented clockwise, positive "
|
||||
"angles will report concave corners while negative ones report convex ones.\n"
|
||||
"With the 'absolute' option set to true, there is no such distinction and angle values are always positive.\n"
|
||||
"\n"
|
||||
"With 'inverse' set to true, the method will select corners not meeting the angle criterion.\n"
|
||||
"\n"
|
||||
"A similar function that reports corners as point-like edges is \\corners_dots.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27. "
|
||||
"'inverse' and 'absolute' have been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("corners_dots", &corners_to_dots, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
method_ext ("corners_dots", &corners_to_dots, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||
"\n"
|
||||
"This method is similar to \\corners, but delivers an \\Edges collection with dot-like edges for each corner.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27.\n"
|
||||
"This method has been introduced in version 0.25. 'include_min_angle' and 'include_max_angle' have been added in version 0.27. "
|
||||
"'inverse' and 'absolute' have been added in version 0.29.1.\n"
|
||||
) +
|
||||
method_ext ("corners_edge_pairs", &corners_to_edge_pairs, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true),
|
||||
method_ext ("corners_edge_pairs", &corners_to_edge_pairs, gsi::arg ("angle_start", -180.0), gsi::arg ("angle_end", 180.0), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", true), gsi::arg ("inverse", false), gsi::arg ("absolute", false),
|
||||
"@brief This method will select all corners whose attached edges satisfy the angle condition.\n"
|
||||
"\n"
|
||||
"This method is similar to \\corners, but delivers an \\EdgePairs collection with an edge pairs for each corner.\n"
|
||||
"The first edge is the incoming edge of the corner, the second one the outgoing edge.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.1.\n"
|
||||
"This method has been introduced in version 0.27.1. "
|
||||
"'inverse' and 'absolute' have been added in version 0.29.1.\n"
|
||||
) +
|
||||
method ("merge", (db::Region &(db::Region::*) ()) &db::Region::merge,
|
||||
"@brief Merge the region\n"
|
||||
|
|
|
|||
|
|
@ -1043,13 +1043,13 @@ TEST(21_Processors)
|
|||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true, false, false)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)));
|
||||
db::Region ext;
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), ext);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, false, false, 2000)));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::extents_processor<db::Polygon> (0, 0)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::extents_processor<db::Polygon> (1000, 2000)));
|
||||
|
|
|
|||
|
|
@ -836,10 +836,10 @@ void run_test15 (tl::TestBase *_this, bool deep)
|
|||
|
||||
db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode ();
|
||||
|
||||
db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, true, 180.0, true, 1), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionProcessingOperationNode *corners1 = new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 1), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionCountFilterNode count1 (corners1, false, 5, 10000);
|
||||
|
||||
db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, true, 180.0, true), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionToEdgeProcessingOperationNode *corners2 = new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (-180.0, true, 180.0, true, false, false), primary, true /*processor is owned*/);
|
||||
db::CompoundRegionCountFilterNode count2 (corners2, true, 5, 10000);
|
||||
|
||||
EXPECT_EQ (count1.result_type () == db::CompoundRegionJoinOperationNode::Region, true);
|
||||
|
|
|
|||
|
|
@ -327,8 +327,8 @@ TEST(5_Filters)
|
|||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
|
||||
|
||||
db::EdgeOrientationFilter eof1 (0, true, 1, true, false);
|
||||
db::EdgeOrientationFilter eof2 (0, true, 1, true, true);
|
||||
db::EdgeOrientationFilter eof1 (0, true, 1, true, false, false);
|
||||
db::EdgeOrientationFilter eof2 (0, true, 1, true, true, false);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.filtered (eof1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.filtered (eof2));
|
||||
|
|
|
|||
|
|
@ -1264,13 +1264,13 @@ TEST(21_Processors)
|
|||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1.processed (db::CornersAsDots (-180.0, true, 180.0, true, false, false)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)));
|
||||
db::Region ext;
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
r1.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).extended (ext, 1000, 1000, 2000, 2000);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), ext);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 2000)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, true, 180.0, true, false, false, 2000)));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::extents_processor<db::Polygon> (0, 0)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::extents_processor<db::Polygon> (1000, 2000)));
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ TEST(5_InternalAngleFilter)
|
|||
{
|
||||
db::EdgePair ep0 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (0, 0)));
|
||||
db::EdgePair ep45 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, 100)));
|
||||
db::EdgePair ep45inv (db::Edge (db::Point (0, 0), db::Point (100, 100)), db::Edge (db::Point (0, 0), db::Point (100, 0)));
|
||||
db::EdgePair ep180 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, 0)));
|
||||
db::EdgePair ep90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (0, 100)));
|
||||
db::EdgePair epm90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 100), db::Point (0, 0)));
|
||||
|
|
@ -187,6 +188,7 @@ TEST(5_InternalAngleFilter)
|
|||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (epm90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45inv), true);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep0), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep180), false);
|
||||
|
|
@ -199,4 +201,12 @@ TEST(5_InternalAngleFilter)
|
|||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (epm90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45inv), true);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep0), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep180), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (epm90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45inv), false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,55 +202,63 @@ TEST(4)
|
|||
EXPECT_EQ (db::compare (rr, "(0,0;0,200);(0,200;100,200);(100,200;100,0);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(200,0;250,200);(250,-200;300,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, true);
|
||||
db::EdgeOrientationFilter f1 (-80.0, true, -50.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(250,200;300,0);(200,0;250,-200)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, false, true);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(200,0;250,200);(250,200;300,0);(200,0;250,-200);(250,-200;300,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, false, true, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(0,200;100,200);(100,200;100,0);(100,0;0,0);(250,200;300,0);(300,0;200,0);(200,0;250,-200)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 1.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 1.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, false, false, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, true, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, true, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, true, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, true, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,200;100,200);(100,0;0,0);(300,0;200,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, false, 1.0, true, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, false, 1.0, true, false, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (90.0, false);
|
||||
db::EdgeOrientationFilter f1 (90.0, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(100,200;100,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (90.0, true, 91.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (90.0, true, 91.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(100,200;100,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 91.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 91.0, false, false, false);
|
||||
EXPECT_EQ (db::compare (r.filtered (f1), "(0,0;0,200);(100,200;100,0)"), true);
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 90.0, false, false);
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 90.0, false, false, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -539,3 +539,27 @@ TEST(6_ReaderLog)
|
|||
compare_text_files (path, au_path);
|
||||
}
|
||||
|
||||
// issue #1696
|
||||
TEST(7_CustomDevice)
|
||||
{
|
||||
db::LayoutToNetlist l2n;
|
||||
|
||||
std::string in_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "l2n_reader_7.l2n");
|
||||
tl::InputStream is_in (in_path);
|
||||
|
||||
db::LayoutToNetlistStandardReader reader (is_in);
|
||||
reader.read (&l2n);
|
||||
|
||||
// verify against the input
|
||||
|
||||
std::string path = tmp_file ("tmp.txt");
|
||||
{
|
||||
tl::OutputStream stream (path);
|
||||
db::LayoutToNetlistStandardWriter writer (stream, false);
|
||||
writer.write (&l2n);
|
||||
}
|
||||
|
||||
std::string au_path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "l2n_reader_au_7.l2n");
|
||||
|
||||
compare_text_files (path, au_path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -880,6 +880,40 @@ TEST(23_endl)
|
|||
);
|
||||
}
|
||||
|
||||
TEST(24_recursive_calls)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader24.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
|
||||
try {
|
||||
reader.read (is, nl);
|
||||
EXPECT_EQ (false, true);
|
||||
} catch (tl::Exception &ex) {
|
||||
EXPECT_EQ (ex.msg ().find ("Subcircuit 'C1' called recursively in"), size_t (0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(25_dismiss_top_level)
|
||||
{
|
||||
db::Netlist nl;
|
||||
|
||||
std::string path = tl::combine_path (tl::combine_path (tl::testdata (), "algo"), "nreader25.cir");
|
||||
|
||||
db::NetlistSpiceReader reader;
|
||||
tl::InputStream is (path);
|
||||
reader.read (is, nl);
|
||||
|
||||
EXPECT_EQ (nl.to_string (),
|
||||
"circuit TOP (A=A,B=B);\n"
|
||||
" device NMOS '1' (S=A,G=B,D=A,B=B) (L=100,W=100,AS=0,AD=0,PS=0,PD=0);\n"
|
||||
"end;\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(100_ExpressionParser)
|
||||
{
|
||||
std::map<std::string, tl::Variant> vars;
|
||||
|
|
|
|||
|
|
@ -2574,17 +2574,17 @@ TEST(100_Processors)
|
|||
r.insert (db::Box (db::Point (0, 300), db::Point (200, 400)));
|
||||
r.insert (db::Box (db::Point (100, 300), db::Point (200, 500)));
|
||||
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-180.0, true, 180.0, true)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (0.0, true, 180.0, true)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, true)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, true)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, false)).to_string (), "");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-180.0, true, 180.0, true, false, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, true, false, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,400;100,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, true, false, false)).to_string (), "(100,400;100,400)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsDots (-90.0, true, 90.0, false, false, false)), "(100,0;100,0);(0,0;0,0);(0,200;0,200);(100,200;100,200);(200,300;200,300);(0,300;0,300);(0,400;0,400);(100,500;100,500);(200,500;200,500)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsDots (-90.0, false, 90.0, false, false, false)).to_string (), "");
|
||||
db::Region ext;
|
||||
r.processed (db::CornersAsDots (0.0, true, 180.0, true)).extended (ext, 10, 10, 20, 20);
|
||||
r.processed (db::CornersAsDots (0.0, true, 180.0, true, false, false)).extended (ext, 10, 10, 20, 20);
|
||||
EXPECT_EQ (ext.to_string (), "(90,380;90,420;110,420;110,380)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, 2)), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, true, 180.0, true, 2)).to_string (), "(98,398;98,402;102,402;102,398)");
|
||||
EXPECT_EQ (db::compare (r.processed (db::CornersAsRectangles (-180.0, true, 180.0, true, false, false, 2)), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)"), true);
|
||||
EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, true, 180.0, true, false, false, 2)).to_string (), "(98,398;98,402;102,402;102,398)");
|
||||
|
||||
EXPECT_EQ (db::compare (r.processed (db::extents_processor<db::Polygon> (0, 0)), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)"), true);
|
||||
EXPECT_EQ (db::compare (r.processed (db::extents_processor<db::Polygon> (10, 20)), "(-10,-20;-10,220;110,220;110,-20);(-10,280;-10,520;210,520;210,280)"), true);
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ out = in.drc((width < 0.3).edges - secondary(waive))
|
|||
This operation selects edges by their angle, measured against the horizontal
|
||||
axis in the mathematical sense.
|
||||
</p><p>
|
||||
For this measurement edges are considered without their direction and straight lines.
|
||||
For this measurement edges are considered without their direction.
|
||||
A horizontal edge has an angle of zero degree. A vertical one has
|
||||
an angle of 90 degrees. The angle range is from -90 (exclusive) to 90 degree (inclusive).
|
||||
</p><p>
|
||||
|
|
@ -172,20 +172,28 @@ If the input shapes are not polygons or edge pairs, they are converted to edges
|
|||
before the angle test is made.
|
||||
</p><p>
|
||||
For example, the following code selects all edges from the primary shape which are 45 degree
|
||||
(up) or 135 degree (down). The "+" will join the results:
|
||||
(up) or -45 degree (down). The "+" operator will join the results:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc((angle == 45) + (angle == 135))
|
||||
out = in.drc((primary.angle == 45) + (primary.angle == 135)) # equivalent
|
||||
out = in.drc((angle == 45) + (angle == -45))
|
||||
out = in.drc((primary.angle == 45) + (primary.angle == -45)) # equivalent
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that angle checks usually imply the need to rotation variant formation as cells which
|
||||
You can avoid using both 45 and -45 degree checks with the 'absolute' option.
|
||||
With this option, angles are not signed and the value is the absolute angle
|
||||
the edge encloses with the x axis:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(angle(absolute) == 45)
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that angle checks usually imply the need for rotation variant formation as cells which
|
||||
are placed non-rotated and rotated by 90 degree cannot be considered identical. This imposes
|
||||
a performance penalty in hierarchical mode. If possible, consider using <a href="/about/drc_ref_drc.xml#rectilinear">DRC#rectilinear</a> for
|
||||
example to detect shapes with non-manhattan geometry instead of using angle checks.
|
||||
</p><p>
|
||||
The "angle" method is available as a plain function or as a method on <a href="/about/drc_ref_drc.xml">DRC</a> expressions.
|
||||
The plain function is equivalent to "primary.angle".
|
||||
The plain function is equivalent to the method call "primary.angle".
|
||||
</p>
|
||||
<a name="area"/><h2>"area" - Selects the primary shape if the area is meeting the condition</h2>
|
||||
<keyword name="area"/>
|
||||
|
|
@ -363,8 +371,7 @@ See <a href="/about/drc_ref_layer.xml#centers">layer#centers</a> for details abo
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>expression.corners</tt></li>
|
||||
<li><tt>expression.corners(as_dots)</tt></li>
|
||||
<li><tt>expression.corners(as_boxes)</tt></li>
|
||||
<li><tt>expression.corners([ options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This operation acts on polygons and selects the corners of the polygons.
|
||||
|
|
@ -374,10 +381,20 @@ and negative for the turn to the right. Hence positive angles indicate concave
|
|||
(inner) corners, negative ones indicate convex (outer) corners.
|
||||
Angles take values between -180 and 180 degree.
|
||||
</p><p>
|
||||
When using "as_dots" for the argument, the operation will return single-point edges at
|
||||
When using "as_dots" for an option, the operation will return single-point edges at
|
||||
the selected corners. With "as_boxes" (the default), small (2x2 DBU) rectangles will be
|
||||
produced at each selected corner.
|
||||
</p><p>
|
||||
Another option is "absolute" which selects the corners by absolute angle - i.e left
|
||||
and right turns will both be considered positive angles.
|
||||
</p><p>
|
||||
Examples for use of the options are:
|
||||
</p><p>
|
||||
<pre>
|
||||
corners(as_dots)
|
||||
corners(as_boxes, absolute)
|
||||
</pre>
|
||||
</p><p>
|
||||
The following example selects all corners:
|
||||
</p><p>
|
||||
<pre>
|
||||
|
|
|
|||
|
|
@ -264,8 +264,11 @@ deliver objects that can be converted into polygons. Such objects are of class <
|
|||
<p>
|
||||
This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||
selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||
while negative angles indicate a right turn. Since polygons are oriented clockwise, positive angles
|
||||
while negative angles indicate a right turn.
|
||||
Since polygons are oriented clockwise, positive angles
|
||||
indicate concave (inner) corners while negative ones indicate convex (outer) corners
|
||||
The 'absolute' option allows turning this off and considering both left and right turns
|
||||
positive angles.
|
||||
</p><p>
|
||||
The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
|
||||
</p><p>
|
||||
|
|
@ -276,6 +279,8 @@ The options available are:
|
|||
<li><b>as_dots </b>: with this option, point-like edges will be produced instead of small boxes </li>
|
||||
<li><b>as_edge_pairs </b>: with this option, an edge pair is produced for each corner selected. The first edge
|
||||
is the incoming edge to the corner, the second edge the outgoing edge. </li>
|
||||
<li><b>absolute </b>: with this option, left and right turns will both be considered positive angles </li>
|
||||
<li><b>negative </b>: with this option, all corners <b>not </b>matching the angle criterion are selected </li>
|
||||
</ul>
|
||||
</p><p>
|
||||
The following images show the effect of this method:
|
||||
|
|
@ -3615,13 +3620,13 @@ The following images illustrate the effect of the "without_touching_corners" opt
|
|||
<keyword name="with_angle"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.with_angle(min .. max)</tt></li>
|
||||
<li><tt>layer.with_angle(value)</tt></li>
|
||||
<li><tt>layer.with_angle(min, max)</tt></li>
|
||||
<li><tt>layer.with_angle(min .. max [, absolute])</tt></li>
|
||||
<li><tt>layer.with_angle(value [, absolute])</tt></li>
|
||||
<li><tt>layer.with_angle(min, max [, absolute])</tt></li>
|
||||
<li><tt>layer.with_angle(ortho)</tt></li>
|
||||
<li><tt>layer.with_angle(diagonal)</tt></li>
|
||||
<li><tt>layer.with_angle(diagonal_only)</tt></li>
|
||||
<li><tt>edge_pair_layer.with_angle(... [, both])</tt></li>
|
||||
<li><tt>edge_pair_layer.with_angle(... [, both] [, absolute])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
When called on an edge layer, the method selects edges by their angle,
|
||||
|
|
@ -3641,6 +3646,11 @@ meeting the angle criterion. In this case an additional argument is accepted whi
|
|||
either "both" (plain word) to indicate that both edges have to be within the given interval.
|
||||
Without this argument, it is sufficient for one edge to meet the criterion.
|
||||
</p><p>
|
||||
The "absolute" option is available for edge or edge pair layers.
|
||||
Without the "absolute" option, edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
</p><p>
|
||||
Here are examples for "with_angle" on edge pair layers:
|
||||
</p><p>
|
||||
<pre>
|
||||
|
|
@ -4006,21 +4016,25 @@ This method is available for polygon layers only.
|
|||
<keyword name="without_angle"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.without_angle(min .. max)</tt></li>
|
||||
<li><tt>layer.without_angle(value)</tt></li>
|
||||
<li><tt>layer.without_angle(min, max)</tt></li>
|
||||
<li><tt>layer.without_angle(min .. max [, absolute])</tt></li>
|
||||
<li><tt>layer.without_angle(value [, absolute])</tt></li>
|
||||
<li><tt>layer.without_angle(min, max [, absolute])</tt></li>
|
||||
<li><tt>layer.without_angle(ortho)</tt></li>
|
||||
<li><tt>layer.without_angle(diagonal)</tt></li>
|
||||
<li><tt>layer.without_angle(diagonal_only)</tt></li>
|
||||
<li><tt>edge_pair_layer.without_angle(... [, both])</tt></li>
|
||||
<li><tt>edge_pair_layer.without_angle(... [, both] [, absolute])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method basically is the inverse of <a href="#with_angle">with_angle</a>. It selects all edges
|
||||
of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
|
||||
is not inside the given interval (first and third form) or of the given type (other forms).
|
||||
</p><p>
|
||||
When called on edge pairs, it selects
|
||||
edge pairs by the angles of their edges.
|
||||
When called on edge pairs, it selects edge pairs by the angles of their edges.
|
||||
</p><p>
|
||||
The "absolute" option is available for edge or edge pair layers. Without the "absolute" option,
|
||||
edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
</p><p>
|
||||
A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
||||
both edges need to be "without_angle". For example
|
||||
|
|
|
|||
|
|
@ -282,6 +282,7 @@ var x = 3; x = x + 1; x
|
|||
<tr><td><tt>combine(</tt>x<tt>,</tt>y<tt>)</tt></td><td>String</td><td>String</td><td>Combines the path components x and y using the system specific separator</td></tr>
|
||||
<tr><td><tt>cosh(</tt>x<tt>)</tt></td><td>Numeric</td><td>Numeric</td><td>Hyperbolic cosine function</td></tr>
|
||||
<tr><td><tt>cos(</tt>x<tt>)</tt></td><td>Numeric</td><td>Numeric</td><td>Cosine function</td></tr>
|
||||
<tr><td><tt>downcase(</tt>x<tt>)</tt></td><td>String</td><td>String</td><td>Converts the given string to lower case</td></tr>
|
||||
<tr><td><tt>env(</tt>x<tt>)</tt></td><td>String</td><td>String</td><td>Access an environment variable</td></tr>
|
||||
<tr><td><tt>error(</tt>x<tt>)</tt></td><td>String</td><td></td><td>Raise an error</td></tr>
|
||||
<tr><td><tt>exp(</tt>x<tt>)</tt></td><td>Numeric</td><td>Numeric</td><td>Exponential function</td></tr>
|
||||
|
|
@ -318,6 +319,7 @@ var x = 3; x = x + 1; x
|
|||
<tr><td><tt>to_f(</tt>x<tt>)</tt></td><td>Any</td><td>Numeric</td><td>Convert argument to numeric if possible</td></tr>
|
||||
<tr><td><tt>to_i(</tt>x<tt>)</tt></td><td>Any</td><td>Numeric (integer)</td><td>Convert argument to numeric (32 bit integer)</td></tr>
|
||||
<tr><td><tt>to_s(</tt>x<tt>)</tt></td><td>Any</td><td>String</td><td>Convert argument to string</td></tr>
|
||||
<tr><td><tt>upcase(</tt>x<tt>)</tt></td><td>String</td><td>String</td><td>Converts the given string to upper case</td></tr>
|
||||
</table>
|
||||
|
||||
</doc>
|
||||
|
|
|
|||
|
|
@ -234,6 +234,49 @@ gate.width(min_width).output("gate_width", "Gate width violations")</pre>
|
|||
Hence such files can only be run from the macro IDE.
|
||||
</p>
|
||||
|
||||
<h2>DRC waiving flow</h2>
|
||||
|
||||
<p>
|
||||
DRC waiving is a process of signing off DRC violations that cannot be avoided.
|
||||
Usually DRC waiving is not encouraged, as manufacturability of the device cannot
|
||||
be guaranteed if DRC violations are present. Even worse, giving a non-clean layout
|
||||
into manufacturing may create a contamination risk that manufacturers will try
|
||||
to avoid. Hence, non-DRC-clean layouts are usually rejected.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Still there are some legit reasons for DRC waiving. Sometimes DRC rules do not apply
|
||||
because a specific technology option is not used by the device and corresponding
|
||||
DRC rules do not apply. Or, a certain DRC rule may be a recommended rule, and violating
|
||||
it is not forbidden. In that case, a DRC violation can be waived at your own risk.
|
||||
Waiving is not a formal process. Usually, the manufacturer will ask for a confirmation
|
||||
if DRC violations are present. KLayout can help documenting violations and copying
|
||||
the waivers from one DRC run to the next.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The DRC waiving flow of KLayout is the following:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>In the initial step, a RDB database is created by the DRC run, using the "report" command with a destination file.</li>
|
||||
<li>This report is inspected in the marker browser. You can add comments, set flags and add screenshots. This is
|
||||
also the time to waive DRC violations that you deem necessary to be waived. The marker browser has a "waive"
|
||||
button which sets or resets the waived flag of the selected markers.</li>
|
||||
<li>When finished, save the edited database to a 'waiver DB' using the marker browser's 'Save As Waiver DB' feature from
|
||||
the File menu. Technically, this will write the report database to a second file. This second file is named
|
||||
like the original one, with a ".w" added to the file name.</li>
|
||||
<li>When you run the DRC again, KLayout will find this waiver DB file and apply attributes from the waiver DB
|
||||
to the current report database. These attributes include the flags, images and comments.
|
||||
This will - among the other annotations - apply the waived flag to the report database items.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
In the waiving step, KLayout will apply attributes to items with the same value (i.e. shape), category and cell.
|
||||
This specifically means, that when you rename a cell, waivers will no longer be applied, or - in the worst case -
|
||||
be applied to the wrong cell. Hence, waiving should be done late in the process, when cell names are unlikely to change.
|
||||
</p>
|
||||
|
||||
<h2>Using KLayout as a standalone DRC engine</h2>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -691,7 +691,7 @@ CODE
|
|||
# This operation selects edges by their angle, measured against the horizontal
|
||||
# axis in the mathematical sense.
|
||||
#
|
||||
# For this measurement edges are considered without their direction and straight lines.
|
||||
# For this measurement edges are considered without their direction.
|
||||
# A horizontal edge has an angle of zero degree. A vertical one has
|
||||
# an angle of 90 degrees. The angle range is from -90 (exclusive) to 90 degree (inclusive).
|
||||
#
|
||||
|
|
@ -699,23 +699,43 @@ CODE
|
|||
# before the angle test is made.
|
||||
#
|
||||
# For example, the following code selects all edges from the primary shape which are 45 degree
|
||||
# (up) or 135 degree (down). The "+" will join the results:
|
||||
# (up) or -45 degree (down). The "+" operator will join the results:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc((angle == 45) + (angle == 135))
|
||||
# out = in.drc((primary.angle == 45) + (primary.angle == 135)) # equivalent
|
||||
# out = in.drc((angle == 45) + (angle == -45))
|
||||
# out = in.drc((primary.angle == 45) + (primary.angle == -45)) # equivalent
|
||||
# @/code
|
||||
#
|
||||
# Note that angle checks usually imply the need to rotation variant formation as cells which
|
||||
# You can avoid using both 45 and -45 degree checks with the 'absolute' option.
|
||||
# With this option, angles are not signed and the value is the absolute angle
|
||||
# the edge encloses with the x axis:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(angle(absolute) == 45)
|
||||
# @/code
|
||||
#
|
||||
# Note that angle checks usually imply the need for rotation variant formation as cells which
|
||||
# are placed non-rotated and rotated by 90 degree cannot be considered identical. This imposes
|
||||
# a performance penalty in hierarchical mode. If possible, consider using \DRC#rectilinear for
|
||||
# example to detect shapes with non-manhattan geometry instead of using angle checks.
|
||||
#
|
||||
# The "angle" method is available as a plain function or as a method on \DRC# expressions.
|
||||
# The plain function is equivalent to "primary.angle".
|
||||
# The plain function is equivalent to the method call "primary.angle".
|
||||
|
||||
def angle
|
||||
DRCOpNodeEdgeOrientationFilter::new(@engine, self)
|
||||
def angle(*args)
|
||||
|
||||
filter = DRCOpNodeEdgeOrientationFilter::new(@engine, self)
|
||||
|
||||
args.each do |a|
|
||||
if a.is_a?(DRCAbsoluteMode)
|
||||
filter.absolute = a.value
|
||||
else
|
||||
raise("Invalid argument (#{a.inspect}) for 'angle' method")
|
||||
end
|
||||
end
|
||||
|
||||
filter
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -758,8 +778,7 @@ CODE
|
|||
# @name corners
|
||||
# @brief Selects corners of polygons
|
||||
# @synopsis expression.corners
|
||||
# @synopsis expression.corners(as_dots)
|
||||
# @synopsis expression.corners(as_boxes)
|
||||
# @synopsis expression.corners([ options ])
|
||||
#
|
||||
# This operation acts on polygons and selects the corners of the polygons.
|
||||
# It can be put into a condition to select corners by their angles. The angle of
|
||||
|
|
@ -768,9 +787,19 @@ CODE
|
|||
# (inner) corners, negative ones indicate convex (outer) corners.
|
||||
# Angles take values between -180 and 180 degree.
|
||||
#
|
||||
# When using "as_dots" for the argument, the operation will return single-point edges at
|
||||
# When using "as_dots" for an option, the operation will return single-point edges at
|
||||
# the selected corners. With "as_boxes" (the default), small (2x2 DBU) rectangles will be
|
||||
# produced at each selected corner.
|
||||
#
|
||||
# Another option is "absolute" which selects the corners by absolute angle - i.e left
|
||||
# and right turns will both be considered positive angles.
|
||||
#
|
||||
# Examples for use of the options are:
|
||||
#
|
||||
# @code
|
||||
# corners(as_dots)
|
||||
# corners(as_boxes, absolute)
|
||||
# @/code
|
||||
#
|
||||
# The following example selects all corners:
|
||||
#
|
||||
|
|
@ -789,14 +818,20 @@ CODE
|
|||
# The "corners" method is available as a plain function or as a method on \DRC# expressions.
|
||||
# The plain function is equivalent to "primary.corners".
|
||||
|
||||
def corners(output_mode = DRCOutputMode::new(:dots))
|
||||
def corners(*args)
|
||||
@engine._context("corners") do
|
||||
if output_mode.is_a?(DRCOutputMode)
|
||||
output_mode = output_mode.value
|
||||
else
|
||||
raise("Invalid argument (#{as_dots.inspect}) for 'corners' method")
|
||||
output_mode = :as_boxes
|
||||
absolute = false
|
||||
args.each do |a|
|
||||
if a.is_a?(DRCOutputMode)
|
||||
output_mode = a.value
|
||||
elsif a.is_a?(DRCAbsoluteMode)
|
||||
absolute = a.value
|
||||
else
|
||||
raise("Invalid argument (#{a.inspect}) for 'corners' method")
|
||||
end
|
||||
end
|
||||
DRCOpNodeCornersFilter::new(@engine, output_mode, self)
|
||||
DRCOpNodeCornersFilter::new(@engine, output_mode, absolute, self)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1721,6 +1756,7 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare
|
|||
|
||||
attr_accessor :input
|
||||
attr_accessor :inverse
|
||||
attr_accessor :absolute
|
||||
|
||||
def initialize(engine, input)
|
||||
super(engine)
|
||||
|
|
@ -1748,6 +1784,7 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare
|
|||
args << (self.gt ? false : true)
|
||||
args << (self.lt ? self.lt : (self.le ? self.le + angle_delta : 180.0))
|
||||
args << (self.lt ? false : true)
|
||||
args << self.absolute
|
||||
|
||||
RBA::CompoundRegionOperationNode::new_edge_orientation_filter(*args)
|
||||
|
||||
|
|
@ -2037,12 +2074,16 @@ class DRCOpNodeCornersFilter < DRCOpNodeWithCompare
|
|||
|
||||
attr_accessor :input
|
||||
attr_accessor :output_mode
|
||||
attr_accessor :inverse
|
||||
attr_accessor :absolute
|
||||
|
||||
def initialize(engine, output_mode, input)
|
||||
def initialize(engine, output_mode, absolute, input)
|
||||
super(engine)
|
||||
self.output_mode = output_mode
|
||||
self.input = input
|
||||
self.description = "corners"
|
||||
self.inverse = false
|
||||
self.absolute = absolute
|
||||
end
|
||||
|
||||
def do_create_node(cache)
|
||||
|
|
@ -2052,14 +2093,26 @@ class DRCOpNodeCornersFilter < DRCOpNodeWithCompare
|
|||
args << (self.lt ? self.lt : (self.le ? self.le : 180.0))
|
||||
args << (self.lt ? false : true)
|
||||
if self.output_mode == :dots || self.output_mode == :edges
|
||||
args << self.inverse
|
||||
args << self.absolute
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_dots(*args)
|
||||
elsif self.output_mode == :edge_pairs
|
||||
args << self.inverse
|
||||
args << self.absolute
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_edge_pairs(*args)
|
||||
else
|
||||
args << 2 # dimension is 2x2 DBU
|
||||
args << self.inverse
|
||||
args << self.absolute
|
||||
RBA::CompoundRegionOperationNode::new_corners_as_rectangles(*args)
|
||||
end
|
||||
end
|
||||
|
||||
def inverted
|
||||
res = self.dup
|
||||
res.inverse = !res.inverse
|
||||
return res
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -770,17 +770,7 @@ CODE
|
|||
# \DRC# expressions (see \Layer#drc and \DRC#length for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_length.
|
||||
|
||||
# %DRC%
|
||||
# @name angle
|
||||
# @brief In universal DRC context: selects edges based on their orientation
|
||||
# @synopsis angle (in condition)
|
||||
#
|
||||
# "angle" represents the edge orientation filter on the primary shape edges in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#angle for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_angle.
|
||||
|
||||
%w(
|
||||
angle
|
||||
area
|
||||
holes
|
||||
hulls
|
||||
|
|
@ -798,6 +788,15 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name angle
|
||||
# @brief In universal DRC context: selects edges based on their orientation
|
||||
# @synopsis angle (in condition)
|
||||
#
|
||||
# "angle" represents the edge orientation filter on the primary shape edges in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#angle for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_angle.
|
||||
|
||||
# %DRC%
|
||||
# @name corners
|
||||
# @brief Selects corners of polygons
|
||||
|
|
@ -817,11 +816,6 @@ CODE
|
|||
# The "corners" operator can be put into a condition which means it's
|
||||
# applied to corners meeting a particular angle constraint.
|
||||
|
||||
def _cop_corners(output_mode = DRCOutputMode::new(:boxes))
|
||||
# NOTE: this method is a fallback for the respective global ones which route to DRCLayer or here.
|
||||
return primary.corners(output_mode)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name extent_refs
|
||||
# @brief Returns partial references to the boundings boxes of the polygons
|
||||
|
|
@ -897,6 +891,8 @@ CODE
|
|||
rounded_corners
|
||||
sized
|
||||
smoothed
|
||||
corners
|
||||
angle
|
||||
).each do |f|
|
||||
# NOTE: these methods are fallback for the respective global ones which route to DRCLayer or here.
|
||||
eval <<"CODE"
|
||||
|
|
|
|||
|
|
@ -115,11 +115,29 @@ module DRC
|
|||
end
|
||||
|
||||
def write
|
||||
|
||||
if @file_name
|
||||
|
||||
rdb_file = @engine._make_path(@file_name)
|
||||
|
||||
# Apply waive DB if possible
|
||||
wdb_file = rdb_file + ".w"
|
||||
if File.exists?(wdb_file)
|
||||
begin
|
||||
wdb = RBA::ReportDatabase::new
|
||||
wdb.load(wdb_file)
|
||||
@engine.info("Applying waive database: #{wdb_file} ..")
|
||||
@rdb.apply(wdb)
|
||||
wdb._destroy
|
||||
rescue
|
||||
end
|
||||
end
|
||||
|
||||
@engine.info("Writing report database: #{rdb_file} ..")
|
||||
@rdb.save(rdb_file)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def rdb
|
||||
|
|
@ -551,6 +569,10 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
def absolute
|
||||
DRCAbsoluteMode::new(true)
|
||||
end
|
||||
|
||||
def as_dots
|
||||
DRCOutputMode::new(:dots)
|
||||
end
|
||||
|
|
@ -3226,7 +3248,33 @@ CODE
|
|||
output_rdb = channel.rdb
|
||||
output_cell = channel.cell
|
||||
|
||||
cat = output_rdb.create_category(args[0].to_s)
|
||||
categories = args[0]
|
||||
if !categories.is_a?(Array)
|
||||
categories = [ categories.to_s ]
|
||||
end
|
||||
|
||||
cat = nil
|
||||
categories.each do |c|
|
||||
ccat = nil
|
||||
if cat
|
||||
cat.each_sub_category do |i|
|
||||
if i.name == c
|
||||
ccat = i
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
output_rdb.each_category do |i|
|
||||
if i.name == c
|
||||
ccat = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
cat = ccat ? ccat : output_rdb.create_category(cat, c)
|
||||
end
|
||||
cat ||= output_rdb.create_category("default")
|
||||
|
||||
args[1] && cat.description = args[1]
|
||||
|
||||
cat.scan_collection(output_cell, RBA::CplxTrans::new(self.dbu), data)
|
||||
|
|
@ -3333,7 +3381,7 @@ CODE
|
|||
else
|
||||
output_rdb = RBA::ReportDatabase::new(name)
|
||||
end
|
||||
|
||||
|
||||
cn = cellname && cellname.to_s
|
||||
cn ||= @def_cell && @def_cell.name
|
||||
cn ||= @def_source && @def_source.cell_obj && @def_source.cell_obj.name
|
||||
|
|
@ -3343,7 +3391,8 @@ CODE
|
|||
output_rdb.generator = self._generator
|
||||
output_rdb.top_cell_name = cn
|
||||
output_rdb.description = description
|
||||
|
||||
output_rdb.original_file = @def_path
|
||||
|
||||
RDBOutputChannel::new(self, output_rdb, output_rdb_index, cn, output_rdb_file)
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -861,13 +861,13 @@ CODE
|
|||
# %DRC%
|
||||
# @name with_angle
|
||||
# @brief Selects edges by their angle
|
||||
# @synopsis layer.with_angle(min .. max)
|
||||
# @synopsis layer.with_angle(value)
|
||||
# @synopsis layer.with_angle(min, max)
|
||||
# @synopsis layer.with_angle(min .. max [, absolute])
|
||||
# @synopsis layer.with_angle(value [, absolute])
|
||||
# @synopsis layer.with_angle(min, max [, absolute])
|
||||
# @synopsis layer.with_angle(ortho)
|
||||
# @synopsis layer.with_angle(diagonal)
|
||||
# @synopsis layer.with_angle(diagonal_only)
|
||||
# @synopsis edge_pair_layer.with_angle(... [, both])
|
||||
# @synopsis edge_pair_layer.with_angle(... [, both] [, absolute])
|
||||
#
|
||||
# When called on an edge layer, the method selects edges by their angle,
|
||||
# measured against the horizontal axis in the mathematical sense.
|
||||
|
|
@ -886,6 +886,11 @@ CODE
|
|||
# either "both" (plain word) to indicate that both edges have to be within the given interval.
|
||||
# Without this argument, it is sufficient for one edge to meet the criterion.
|
||||
#
|
||||
# The "absolute" option is available for edge or edge pair layers.
|
||||
# Without the "absolute" option, edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
# a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
# edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
#
|
||||
# Here are examples for "with_angle" on edge pair layers:
|
||||
#
|
||||
# @code
|
||||
|
|
@ -931,21 +936,25 @@ CODE
|
|||
# %DRC%
|
||||
# @name without_angle
|
||||
# @brief Selects edges by the their angle
|
||||
# @synopsis layer.without_angle(min .. max)
|
||||
# @synopsis layer.without_angle(value)
|
||||
# @synopsis layer.without_angle(min, max)
|
||||
# @synopsis layer.without_angle(min .. max [, absolute])
|
||||
# @synopsis layer.without_angle(value [, absolute])
|
||||
# @synopsis layer.without_angle(min, max [, absolute])
|
||||
# @synopsis layer.without_angle(ortho)
|
||||
# @synopsis layer.without_angle(diagonal)
|
||||
# @synopsis layer.without_angle(diagonal_only)
|
||||
# @synopsis edge_pair_layer.without_angle(... [, both])
|
||||
# @synopsis edge_pair_layer.without_angle(... [, both] [, absolute])
|
||||
#
|
||||
# The method basically is the inverse of \with_angle. It selects all edges
|
||||
# of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
|
||||
# is not inside the given interval (first and third form) or of the given type (other forms).
|
||||
#
|
||||
# When called on edge pairs, it selects
|
||||
# edge pairs by the angles of their edges.
|
||||
# When called on edge pairs, it selects edge pairs by the angles of their edges.
|
||||
#
|
||||
# The "absolute" option is available for edge or edge pair layers. Without the "absolute" option,
|
||||
# edges sloping down are assigned a negative angle while edges sloping up are assigned
|
||||
# a positive angle (vertical edges are always 90 degree). With the "absolute" option,
|
||||
# edges sloping down also have a positive angle which is the one enclosed with the horizontal axis.
|
||||
#
|
||||
# A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
||||
# both edges need to be "without_angle". For example
|
||||
#
|
||||
|
|
@ -989,57 +998,101 @@ CODE
|
|||
# The method basically is the inverse of \with_internal_angle. It selects all
|
||||
# edge pairs by the angle enclosed by their edges, applying the opposite criterion than \with_internal_angle.
|
||||
|
||||
%w(angle internal_angle).each do |f|
|
||||
[true, false].each do |inv|
|
||||
mn = (inv ? "without" : "with") + "_" + f
|
||||
eval <<"CODE"
|
||||
def #{mn}(*args)
|
||||
[true, false].each do |inv|
|
||||
mn = (inv ? "without" : "with") + "_angle"
|
||||
eval <<"CODE"
|
||||
def #{mn}(*args)
|
||||
|
||||
@engine._context("#{mn}") do
|
||||
@engine._context("#{mn}") do
|
||||
|
||||
f = :with_#{f}
|
||||
self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::EdgePairs) || raise("Requires an edge, edge pair or polygon layer")
|
||||
|
||||
if "#{f}" == "angle"
|
||||
self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::EdgePairs) || raise("Requires an edge, edge pair or polygon layer")
|
||||
args = args.select do |a|
|
||||
if a.is_a?(DRCBothEdges)
|
||||
if !self.data.is_a?(RBA::EdgePairs)
|
||||
raise("'both' keyword is only available for edge pair layers")
|
||||
end
|
||||
f = :with_#{f}_both
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
absolute = false
|
||||
both = false
|
||||
|
||||
args = args.select do |a|
|
||||
if a.is_a?(DRCBothEdges)
|
||||
if !self.data.is_a?(RBA::EdgePairs)
|
||||
raise("'both' keyword is only available for edge pair layers")
|
||||
end
|
||||
else
|
||||
requires_edge_pairs
|
||||
end
|
||||
|
||||
result_class = self.data.is_a?(RBA::Edges) ? RBA::Edges : RBA::EdgePairs
|
||||
if args.size == 1
|
||||
a = args[0]
|
||||
if a.is_a?(Range)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
|
||||
elsif a.is_a?(DRCOrthoEdges) || a.is_a?(DRCDiagonalOnlyEdges) || a.is_a?(DRCDiagonalEdges)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'ortho', 'diagonal' or 'diagonal_only' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.value, #{inv.inspect}))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a, #{inv.inspect}))
|
||||
both = true
|
||||
false
|
||||
elsif a.is_a?(DRCAbsoluteMode)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'absolute' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
elsif args.size == 2
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, args[0], args[1], #{inv.inspect}))
|
||||
absolute = a.value
|
||||
false
|
||||
else
|
||||
raise("Invalid number of range arguments (1 or 2 expected)")
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
if both
|
||||
f = absolute ? :with_abs_angle_both : :with_angle_both
|
||||
else
|
||||
f = absolute ? :with_abs_angle : :with_angle
|
||||
end
|
||||
|
||||
result_class = self.data.is_a?(RBA::Edges) ? RBA::Edges : RBA::EdgePairs
|
||||
if args.size == 1
|
||||
a = args[0]
|
||||
if a.is_a?(Range)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
|
||||
elsif a.is_a?(DRCOrthoEdges) || a.is_a?(DRCDiagonalOnlyEdges) || a.is_a?(DRCDiagonalEdges)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'ortho', 'diagonal' or 'diagonal_only' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.value, #{inv.inspect}))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(a), #{inv.inspect}))
|
||||
end
|
||||
elsif args.size == 2
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(args[0]), @engine._make_numeric_value(args[1]), #{inv.inspect}))
|
||||
else
|
||||
raise("Invalid number of range arguments (1 or 2 expected)")
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
[true, false].each do |inv|
|
||||
mn = (inv ? "without" : "with") + "_internal_angle"
|
||||
eval <<"CODE"
|
||||
def #{mn}(*args)
|
||||
|
||||
@engine._context("#{mn}") do
|
||||
|
||||
f = :with_internal_angle
|
||||
|
||||
requires_edge_pairs
|
||||
|
||||
result_class = self.data.is_a?(RBA::Edges) ? RBA::Edges : RBA::EdgePairs
|
||||
if args.size == 1
|
||||
a = args[0]
|
||||
if a.is_a?(Range)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
|
||||
elsif a.is_a?(DRCOrthoEdges) || a.is_a?(DRCDiagonalOnlyEdges) || a.is_a?(DRCDiagonalEdges)
|
||||
if self.data.is_a?(RBA::Region)
|
||||
raise("'ortho', 'diagonal' or 'diagonal_only' keyword is only available for edge or edge pair layers")
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.value, #{inv.inspect}))
|
||||
else
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(a), #{inv.inspect}))
|
||||
end
|
||||
elsif args.size == 2
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, @engine._make_numeric_value(args[0]), @engine._make_numeric_value(args[1]), #{inv.inspect}))
|
||||
else
|
||||
raise("Invalid number of range arguments (1 or 2 expected)")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -1231,8 +1284,11 @@ CODE
|
|||
#
|
||||
# This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||
# selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||
# while negative angles indicate a right turn. Since polygons are oriented clockwise, positive angles
|
||||
# while negative angles indicate a right turn.
|
||||
# Since polygons are oriented clockwise, positive angles
|
||||
# indicate concave (inner) corners while negative ones indicate convex (outer) corners
|
||||
# The 'absolute' option allows turning this off and considering both left and right turns
|
||||
# positive angles.
|
||||
#
|
||||
# The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
|
||||
#
|
||||
|
|
@ -1243,6 +1299,8 @@ CODE
|
|||
# @li @b as_dots @/b: with this option, point-like edges will be produced instead of small boxes @/li
|
||||
# @li @b as_edge_pairs @/b: with this option, an edge pair is produced for each corner selected. The first edge
|
||||
# is the incoming edge to the corner, the second edge the outgoing edge. @/li
|
||||
# @li @b absolute @/b: with this option, left and right turns will both be considered positive angles @/li
|
||||
# @li @b negative @/b: with this option, all corners @b not @/b matching the angle criterion are selected @/li
|
||||
# @/ul
|
||||
#
|
||||
# The following images show the effect of this method:
|
||||
|
|
@ -1264,6 +1322,8 @@ CODE
|
|||
output_mode = :boxes
|
||||
amin = -180.0
|
||||
amax = 180.0
|
||||
absolute = false
|
||||
inverse = false
|
||||
|
||||
args.each do |a|
|
||||
if a.is_a?(Range)
|
||||
|
|
@ -1277,21 +1337,35 @@ CODE
|
|||
amax = a.to_f
|
||||
elsif a.is_a?(DRCOutputMode)
|
||||
output_mode = a.value
|
||||
elsif a.is_a?(DRCAbsoluteMode)
|
||||
absolute = a.value
|
||||
elsif a.is_a?(DRCNegative)
|
||||
inverse = true
|
||||
else
|
||||
raise("Invalid argument #{a.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
f = :corners
|
||||
cls = RBA::Region
|
||||
args = [ amin, amax ]
|
||||
|
||||
if output_mode == :edges || output_mode == :dots
|
||||
f = :corners_dots
|
||||
cls = RBA::Edges
|
||||
elsif output_mode == :edge_pairs
|
||||
f = :corners_edge_pairs
|
||||
cls = RBA::EdgePairs
|
||||
else
|
||||
f = :corners
|
||||
cls = RBA::Region
|
||||
args << 1 # 2x2 DBU boxes
|
||||
end
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, cls, f, amin, amax))
|
||||
|
||||
args << true # include amin
|
||||
args << true # include amax
|
||||
args << inverse
|
||||
args << absolute
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, cls, f, *args))
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -5111,7 +5185,11 @@ CODE
|
|||
# This method will copy the content of the layer to the specified output.
|
||||
#
|
||||
# If a report database is selected for the output, the specification has to include a
|
||||
# category name and optionally a category description.
|
||||
# category name and optionally a category description. The category name can be an
|
||||
# array of strings - in that case, a hierarchy of categories is created
|
||||
# with the first array item being the top level category name.
|
||||
# Shapes are added to an existing category, if a category with the given
|
||||
# name already exists.
|
||||
#
|
||||
# If the layout is selected for the output, the specification can consist of
|
||||
# one to three parameters: a layer number, a data type (optional, default is 0)
|
||||
|
|
|
|||
|
|
@ -123,6 +123,16 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
# A wrapper for the "absolute" flag for
|
||||
# some DRC functions. The purpose of this class
|
||||
# is to identify the value by the class.
|
||||
class DRCAbsoluteMode
|
||||
attr_accessor :value
|
||||
def initialize(v)
|
||||
self.value = v
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for a rectangle error filter mode
|
||||
# The purpose of this wrapper is to identify the error filter mode
|
||||
class DRCRectangleErrorFilter
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbTestSupport.h"
|
||||
#include "dbNetlist.h"
|
||||
#include "dbNetlistSpiceReader.h"
|
||||
#include "rdb.h"
|
||||
#include "lymMacro.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
|
|
@ -1673,6 +1674,16 @@ TEST(92_issue1594_dual_top)
|
|||
compare_netlists (_this, output, au);
|
||||
}
|
||||
|
||||
TEST(93_withAngle)
|
||||
{
|
||||
run_test (_this, "93", false);
|
||||
}
|
||||
|
||||
TEST(93d_withAngle)
|
||||
{
|
||||
run_test (_this, "93", true);
|
||||
}
|
||||
|
||||
TEST(100_edge_interaction_with_count)
|
||||
{
|
||||
run_test (_this, "100", false);
|
||||
|
|
@ -1702,3 +1713,117 @@ TEST(102d_edge_modes)
|
|||
{
|
||||
run_test (_this, "102", true);
|
||||
}
|
||||
|
||||
TEST(110_RDBVariantAssignment)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcSimpleTests_110.drc";
|
||||
|
||||
// apart from that it's a variant of 14b ...
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcSimpleTests_110.gds";
|
||||
|
||||
std::string au_report = tl::testdata ();
|
||||
au_report += "/drc/drcSimpleTests_au110.lyrdb";
|
||||
|
||||
std::string report = this->tmp_file ("tmp.lydrc");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_force_gc = true\n"
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_report = '%s'\n"
|
||||
, input, report)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
compare_text_files (report, au_report);
|
||||
}
|
||||
|
||||
TEST(111_RDBCategoryHierarchy)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcSimpleTests_111.drc";
|
||||
|
||||
// apart from that it's a variant of 14b ...
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcSimpleTests_111.gds";
|
||||
|
||||
std::string au_report = tl::testdata ();
|
||||
au_report += "/drc/drcSimpleTests_au111.lyrdb";
|
||||
|
||||
std::string report = this->tmp_file ("tmp.lydrc");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_force_gc = true\n"
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_report = '%s'\n"
|
||||
, input, report)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
compare_text_files (report, au_report);
|
||||
}
|
||||
|
||||
TEST(112_Waiving)
|
||||
{
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcSimpleTests_112.drc";
|
||||
|
||||
// apart from that it's a variant of 14b ...
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcSimpleTests_112.gds";
|
||||
|
||||
std::string au_report = tl::testdata ();
|
||||
au_report += "/drc/drcSimpleTests_au112.lyrdb";
|
||||
|
||||
std::string report = this->tmp_file ("tmp.lydrc");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_force_gc = true\n"
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_report = '%s'\n"
|
||||
, input, report)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
// prepare a waiver db
|
||||
{
|
||||
std::string report_w = this->tmp_file ("tmp.lydrc.w");
|
||||
rdb::Database rdb_w;
|
||||
rdb_w.load (au_report + ".w");
|
||||
rdb_w.write (report_w);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
compare_text_files (report, au_report);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -292,6 +292,98 @@ to load a marker database</string>
|
|||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="open_action">
|
||||
<property name="text">
|
||||
<string>Open</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="saveas_action">
|
||||
<property name="text">
|
||||
<string>Save As</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="reload_action">
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F5</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="save_action">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="export_action">
|
||||
<property name="text">
|
||||
<string>Export To Layout</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="unload_action">
|
||||
<property name="text">
|
||||
<string>Unload</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="unload_all_action">
|
||||
<property name="text">
|
||||
<string>Unload All</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Unload All</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="info_action">
|
||||
<property name="text">
|
||||
<string>Info</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="saveas_waiver_db_action">
|
||||
<property name="text">
|
||||
<string>Save As Waiver DB</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="apply_waiver_db_action">
|
||||
<property name="text">
|
||||
<string>Apply Waiver DB</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
|||
|
|
@ -480,51 +480,7 @@
|
|||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="waive_pb">
|
||||
<property name="toolTip">
|
||||
<string>Waive</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>W</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/waived_16px.png</normaloff>:/waived_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<widget class="QToolButton" name="nophoto_pb">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'DejaVu Sans'; font-size:10pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Remove snapshot</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/nophoto_16px.png</normaloff>:/nophoto_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="flags_pb">
|
||||
<property name="toolTip">
|
||||
<string>Set or reset flag</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Flag</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::MenuButtonPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6">
|
||||
<item row="2" column="7">
|
||||
<widget class="QToolButton" name="photo_pb">
|
||||
<property name="toolTip">
|
||||
<string>Add snapshot</string>
|
||||
|
|
@ -538,28 +494,24 @@ p, li { white-space: pre-wrap; }
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QToolButton" name="important_pb">
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="waive_pb">
|
||||
<property name="toolTip">
|
||||
<string>Important</string>
|
||||
<string>Waive</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Imp</string>
|
||||
<string>W</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/important_16px.png</normaloff>:/important_16px.png</iconset>
|
||||
<normaloff>:/waived_16px.png</normaloff>:/waived_16px.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+W</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="info_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="7">
|
||||
<item row="1" column="0" colspan="8">
|
||||
<widget class="QFrame" name="frame_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
|
|
@ -605,7 +557,38 @@ p, li { white-space: pre-wrap; }
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="7">
|
||||
<item row="2" column="5">
|
||||
<widget class="QToolButton" name="important_pb">
|
||||
<property name="toolTip">
|
||||
<string>Important</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Imp</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/important_16px.png</normaloff>:/important_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="6">
|
||||
<widget class="QToolButton" name="nophoto_pb">
|
||||
<property name="toolTip">
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'DejaVu Sans'; font-size:10pt; font-weight:400; font-style:normal; text-decoration:none;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Remove snapshot</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/nophoto_16px.png</normaloff>:/nophoto_16px.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="8">
|
||||
<widget class="QFrame" name="frame_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
|
|
@ -662,6 +645,43 @@ p, li { white-space: pre-wrap; }
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="info_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="flags_pb">
|
||||
<property name="toolTip">
|
||||
<string>Set or reset flag</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Flag</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::MenuButtonPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QToolButton" name="edit_pb">
|
||||
<property name="toolTip">
|
||||
<string>Edit Comment</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../icons/icons.qrc">
|
||||
<normaloff>:/edit_16px.png</normaloff>:/edit_16px.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <QDialog>
|
||||
#include <QApplication>
|
||||
#include <QCloseEvent>
|
||||
|
||||
#include "layBrowser.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
|
@ -81,7 +82,7 @@ Browser::closeEvent (QCloseEvent *event)
|
|||
if (active ()) {
|
||||
m_active = false;
|
||||
deactivated ();
|
||||
QDialog::closeEvent (event);
|
||||
event->accept ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@
|
|||
#include "layConverters.h"
|
||||
#include "layQtTools.h"
|
||||
#include "layConfigurationDialog.h"
|
||||
#include "layBrowserDialog.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
#include "ui_MarkerBrowserDialog.h"
|
||||
|
||||
|
|
@ -84,34 +86,35 @@ MarkerBrowserDialog::MarkerBrowserDialog (lay::Dispatcher *root, lay::LayoutView
|
|||
view ()->rdb_list_changed_event.add (this, &MarkerBrowserDialog::rdbs_changed);
|
||||
}
|
||||
|
||||
m_open_action = new QAction (QObject::tr ("Open"), mp_ui->file_menu);
|
||||
m_saveas_action = new QAction (QObject::tr ("Save As"), mp_ui->file_menu);
|
||||
m_export_action = new QAction (QObject::tr ("Export To Layout"), mp_ui->file_menu);
|
||||
m_reload_action = new QAction (QObject::tr ("Reload"), mp_ui->file_menu);
|
||||
m_unload_action = new QAction (QObject::tr ("Unload"), mp_ui->file_menu);
|
||||
m_unload_all_action = new QAction (QObject::tr ("Unload All"), mp_ui->file_menu);
|
||||
connect (mp_ui->open_action, SIGNAL (triggered ()), this, SLOT (open_clicked ()));
|
||||
connect (mp_ui->save_action, SIGNAL (triggered ()), this, SLOT (save_clicked ()));
|
||||
connect (mp_ui->saveas_action, SIGNAL (triggered ()), this, SLOT (saveas_clicked ()));
|
||||
connect (mp_ui->saveas_waiver_db_action, SIGNAL (triggered ()), this, SLOT (saveas_waiver_db_clicked ()));
|
||||
connect (mp_ui->apply_waiver_db_action, SIGNAL (triggered ()), this, SLOT (apply_waiver_db_clicked ()));
|
||||
connect (mp_ui->export_action, SIGNAL (triggered ()), this, SLOT (export_clicked ()));
|
||||
connect (mp_ui->reload_action, SIGNAL (triggered ()), this, SLOT (reload_clicked ()));
|
||||
connect (mp_ui->info_action, SIGNAL (triggered ()), this, SLOT (info_clicked ()));
|
||||
connect (mp_ui->unload_action, SIGNAL (triggered ()), this, SLOT (unload_clicked ()));
|
||||
connect (mp_ui->unload_all_action, SIGNAL (triggered ()), this, SLOT (unload_all_clicked ()));
|
||||
|
||||
connect (m_open_action, SIGNAL (triggered ()), this, SLOT (open_clicked ()));
|
||||
connect (m_saveas_action, SIGNAL (triggered ()), this, SLOT (saveas_clicked ()));
|
||||
connect (m_export_action, SIGNAL (triggered ()), this, SLOT (export_clicked ()));
|
||||
connect (m_reload_action, SIGNAL (triggered ()), this, SLOT (reload_clicked ()));
|
||||
connect (m_unload_action, SIGNAL (triggered ()), this, SLOT (unload_clicked ()));
|
||||
connect (m_unload_all_action, SIGNAL (triggered ()), this, SLOT (unload_all_clicked ()));
|
||||
|
||||
mp_ui->file_menu->addAction (m_open_action);
|
||||
mp_ui->file_menu->addAction (m_saveas_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->open_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->save_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->saveas_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->saveas_waiver_db_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->apply_waiver_db_action);
|
||||
QAction *sep0 = new QAction (mp_ui->file_menu);
|
||||
sep0->setSeparator (true);
|
||||
mp_ui->file_menu->addAction (m_export_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->export_action);
|
||||
QAction *sep1 = new QAction (mp_ui->file_menu);
|
||||
sep1->setSeparator (true);
|
||||
mp_ui->file_menu->addAction (sep1);
|
||||
mp_ui->file_menu->addAction (m_reload_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->reload_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->info_action);
|
||||
QAction *sep2 = new QAction (mp_ui->file_menu);
|
||||
sep2->setSeparator (true);
|
||||
mp_ui->file_menu->addAction (sep2);
|
||||
mp_ui->file_menu->addAction (m_unload_action);
|
||||
mp_ui->file_menu->addAction (m_unload_all_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->unload_action);
|
||||
mp_ui->file_menu->addAction (mp_ui->unload_all_action);
|
||||
|
||||
connect (mp_ui->layout_cb, SIGNAL (activated (int)), this, SLOT (cv_index_changed (int)));
|
||||
connect (mp_ui->rdb_cb, SIGNAL (activated (int)), this, SLOT (rdb_index_changed (int)));
|
||||
|
|
@ -367,6 +370,99 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserDialog::save_clicked ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
if (m_rdb_index < int (view ()->num_rdbs ()) && m_rdb_index >= 0) {
|
||||
|
||||
rdb::Database *rdb = view ()->get_rdb (m_rdb_index);
|
||||
if (rdb) {
|
||||
|
||||
if (rdb->filename ().empty ()) {
|
||||
|
||||
saveas_clicked ();
|
||||
|
||||
} else {
|
||||
|
||||
rdb->save (rdb->filename ());
|
||||
rdb->reset_modified ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserDialog::apply_waiver_db_clicked ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
rdb::Database *rdb = 0;
|
||||
if (m_rdb_index < int (view ()->num_rdbs ()) && m_rdb_index >= 0) {
|
||||
rdb = view ()->get_rdb (m_rdb_index);
|
||||
}
|
||||
if (! rdb) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string wdb_filename;
|
||||
if (! rdb->filename ().empty () && tl::file_exists (rdb->filename () + ".w")) {
|
||||
|
||||
wdb_filename = rdb->filename () + ".w";
|
||||
|
||||
} else {
|
||||
|
||||
// prepare and open the file dialog
|
||||
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Apply Waiver DB File")), "Waiver DB files (*.w)");
|
||||
|
||||
if (! rdb->filename ().empty ()) {
|
||||
wdb_filename = rdb->filename () + ".w";
|
||||
}
|
||||
|
||||
if (! open_dialog.get_open (wdb_filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rdb::Database wdb;
|
||||
wdb.load (wdb_filename);
|
||||
|
||||
mp_ui->browser_frame->set_rdb (0);
|
||||
rdb->apply (wdb);
|
||||
mp_ui->browser_frame->set_rdb (rdb);
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserDialog::saveas_waiver_db_clicked ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
rdb::Database *rdb = 0;
|
||||
if (m_rdb_index < int (view ()->num_rdbs ()) && m_rdb_index >= 0) {
|
||||
rdb = view ()->get_rdb (m_rdb_index);
|
||||
}
|
||||
if (! rdb) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rdb->filename ().empty ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("The current report database is not saved.\nSave it to some file with 'Save As', before saving it as waiver DB.")));
|
||||
}
|
||||
|
||||
rdb->write (rdb->filename () + ".w");
|
||||
|
||||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserDialog::saveas_clicked ()
|
||||
{
|
||||
|
|
@ -385,6 +481,9 @@ BEGIN_PROTECTED
|
|||
rdb->save (fn);
|
||||
rdb->reset_modified ();
|
||||
|
||||
// update the RDB title strings
|
||||
rdbs_changed ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -394,6 +493,42 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserDialog::info_clicked ()
|
||||
{
|
||||
rdb::Database *rdb = 0;
|
||||
if (m_rdb_index < int (view ()->num_rdbs ()) && m_rdb_index >= 0) {
|
||||
rdb = view ()->get_rdb (m_rdb_index);
|
||||
}
|
||||
if (! rdb) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string html;
|
||||
html = "<html><body>\n";
|
||||
html += "<h2>" + tl::escaped_to_html (rdb->name ()) + "</h2>\n";
|
||||
if (! rdb->description ().empty ()) {
|
||||
html += "<b>" + tl::to_string (tr ("Description: ")) + "</b>" + tl::escaped_to_html (tl::escape_string (rdb->description ())) + "<br/>\n";
|
||||
}
|
||||
if (! rdb->filename ().empty ()) {
|
||||
html += "<b>" + tl::to_string (tr ("File: ")) + "</b>" + tl::escaped_to_html (rdb->filename ()) + "<br/>\n";
|
||||
}
|
||||
if (! rdb->original_file ().empty ()) {
|
||||
html += "<b>" + tl::to_string (tr ("Original File: ")) + "</b>" + tl::escaped_to_html (rdb->original_file ()) + "<br/>\n";
|
||||
}
|
||||
if (! rdb->top_cell_name ().empty ()) {
|
||||
html += "<b>" + tl::to_string (tr ("Top Cell: ")) + "</b>" + tl::escaped_to_html (rdb->top_cell_name ()) + "<br/>\n";
|
||||
}
|
||||
if (! rdb->generator ().empty ()) {
|
||||
html += "<b>" + tl::to_string (tr ("Generator: ")) + "</b>" + tl::escaped_to_html (rdb->generator ()) + "<br/>\n";
|
||||
}
|
||||
html += "</body></html>";
|
||||
|
||||
std::unique_ptr<lay::BrowserDialog> info_dialog (new lay::BrowserDialog (this, html));
|
||||
info_dialog->setWindowTitle (QObject::tr ("Marker Database Info"));
|
||||
info_dialog->exec ();
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserDialog::reload_clicked ()
|
||||
{
|
||||
|
|
@ -439,6 +574,7 @@ BEGIN_PROTECTED
|
|||
|
||||
int rdb_index = view ()->add_rdb (db.release ());
|
||||
mp_ui->rdb_cb->setCurrentIndex (rdb_index);
|
||||
|
||||
// it looks like the setCurrentIndex does not issue this signal:
|
||||
rdb_index_changed (rdb_index);
|
||||
|
||||
|
|
@ -592,9 +728,13 @@ MarkerBrowserDialog::rdbs_changed ()
|
|||
std::string text = rdb->name ();
|
||||
if (! rdb->description ().empty ()) {
|
||||
text += " (";
|
||||
text += rdb->description ();
|
||||
text += tl::escape_string (rdb->description ());
|
||||
text += ")";
|
||||
}
|
||||
if (! rdb->filename ().empty () && rdb->name () != rdb->filename ()) {
|
||||
text += " - ";
|
||||
text += rdb->filename ();
|
||||
}
|
||||
mp_ui->rdb_cb->addItem (tl::to_qstring (text));
|
||||
if (rdb->name () == m_rdb_name) {
|
||||
rdb_index = i;
|
||||
|
|
@ -688,11 +828,15 @@ MarkerBrowserDialog::update_content ()
|
|||
mp_ui->central_stack->setCurrentIndex (1);
|
||||
}
|
||||
|
||||
m_saveas_action->setEnabled (rdb != 0);
|
||||
m_export_action->setEnabled (rdb != 0);
|
||||
m_unload_action->setEnabled (rdb != 0);
|
||||
m_unload_all_action->setEnabled (rdb != 0);
|
||||
m_reload_action->setEnabled (rdb != 0);
|
||||
mp_ui->save_action->setEnabled (rdb != 0);
|
||||
mp_ui->saveas_action->setEnabled (rdb != 0);
|
||||
mp_ui->saveas_waiver_db_action->setEnabled (rdb != 0);
|
||||
mp_ui->apply_waiver_db_action->setEnabled (rdb != 0);
|
||||
mp_ui->export_action->setEnabled (rdb != 0);
|
||||
mp_ui->unload_action->setEnabled (rdb != 0);
|
||||
mp_ui->unload_all_action->setEnabled (rdb != 0);
|
||||
mp_ui->reload_action->setEnabled (rdb != 0);
|
||||
mp_ui->info_action->setEnabled (rdb != 0);
|
||||
|
||||
mp_ui->browser_frame->enable_updates (false); // Avoid building the internal lists several times ...
|
||||
mp_ui->browser_frame->set_rdb (0); // force update
|
||||
|
|
|
|||
|
|
@ -74,7 +74,11 @@ private:
|
|||
public slots:
|
||||
void cv_index_changed (int);
|
||||
void rdb_index_changed (int);
|
||||
void info_clicked ();
|
||||
void save_clicked ();
|
||||
void saveas_clicked ();
|
||||
void saveas_waiver_db_clicked ();
|
||||
void apply_waiver_db_clicked ();
|
||||
void export_clicked ();
|
||||
void reload_clicked ();
|
||||
void open_clicked ();
|
||||
|
|
@ -98,12 +102,6 @@ private:
|
|||
std::string m_rdb_name;
|
||||
int m_rdb_index;
|
||||
std::string m_open_filename;
|
||||
QAction *m_open_action;
|
||||
QAction *m_saveas_action;
|
||||
QAction *m_export_action;
|
||||
QAction *m_unload_action;
|
||||
QAction *m_unload_all_action;
|
||||
QAction *m_reload_action;
|
||||
|
||||
void update_content ();
|
||||
void scan_layer ();
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <QMessageBox>
|
||||
#include <QHeaderView>
|
||||
#include <QKeyEvent>
|
||||
#include <QInputDialog>
|
||||
|
||||
namespace rdb
|
||||
{
|
||||
|
|
@ -103,13 +104,13 @@ class MarkerBrowserTreeViewModelCacheEntry
|
|||
{
|
||||
public:
|
||||
MarkerBrowserTreeViewModelCacheEntry ()
|
||||
: mp_parent (0), m_id (0), m_row (0), m_count (0)
|
||||
: mp_parent (0), m_id (0), m_row (0), m_count (0), m_waived_count (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry (rdb::id_type id, unsigned int branch)
|
||||
: mp_parent (0), m_id ((id << 3) + (branch << 1)), m_row (0), m_count (0)
|
||||
: mp_parent (0), m_id ((id << 3) + (branch << 1)), m_row (0), m_count (0), m_waived_count (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -233,6 +234,25 @@ public:
|
|||
m_count = c;
|
||||
}
|
||||
|
||||
size_t waived_count () const
|
||||
{
|
||||
return m_waived_count;
|
||||
}
|
||||
|
||||
void set_waived_count (size_t c)
|
||||
{
|
||||
m_waived_count = c;
|
||||
}
|
||||
|
||||
void waive_or_unwaive (bool w)
|
||||
{
|
||||
if (w) {
|
||||
++m_waived_count;
|
||||
} else {
|
||||
--m_waived_count;
|
||||
}
|
||||
}
|
||||
|
||||
void sort_by_key_name (bool ascending, const rdb::Database *database)
|
||||
{
|
||||
std::sort (m_ids.begin (), m_ids.end (), SortByKeyCompareFunc (ascending, database));
|
||||
|
|
@ -257,7 +277,7 @@ private:
|
|||
MarkerBrowserTreeViewModelCacheEntry *mp_parent;
|
||||
rdb::id_type m_id;
|
||||
unsigned int m_row;
|
||||
size_t m_count;
|
||||
size_t m_count, m_waived_count;
|
||||
std::vector<MarkerBrowserTreeViewModelCacheEntry *> m_ids;
|
||||
};
|
||||
|
||||
|
|
@ -267,7 +287,7 @@ SortByKeyCompareFunc::operator() (MarkerBrowserTreeViewModelCacheEntry *a, Marke
|
|||
const rdb::Cell *ca = mp_rdb->cell_by_id (a->id ());
|
||||
const rdb::Cell *cb = mp_rdb->cell_by_id (b->id ());
|
||||
if (ca && cb) {
|
||||
return m_ascending ? ca->name () < cb->name () : cb->name () < ca->name ();
|
||||
return m_ascending ? ca->qname () < cb->qname () : cb->qname () < ca->qname ();
|
||||
}
|
||||
|
||||
const rdb::Category *xa = mp_rdb->category_by_id (a->id ());
|
||||
|
|
@ -338,14 +358,16 @@ public:
|
|||
};
|
||||
|
||||
MarkerBrowserTreeViewModel ()
|
||||
: mp_database (0), m_show_empty_ones (true)
|
||||
: mp_database (0), m_show_empty_ones (true), m_waived_tag_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void set_database (const rdb::Database *db)
|
||||
{
|
||||
mp_database = db;
|
||||
m_waived_tag_id = mp_database ? mp_database->tags ().tag ("waived").id () : 0;
|
||||
|
||||
invalidate ();
|
||||
}
|
||||
|
||||
|
|
@ -384,6 +406,23 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void waived_changed (const rdb::Item *item, bool waived)
|
||||
{
|
||||
const rdb::Category *cat = mp_database->category_by_id (item->category_id ());
|
||||
while (cat) {
|
||||
waive_or_unwaive (0, cat->id (), waived);
|
||||
if (item->cell_id () != 0) {
|
||||
waive_or_unwaive (item->cell_id (), cat->id (), waived);
|
||||
}
|
||||
cat = cat->parent ();
|
||||
}
|
||||
|
||||
waive_or_unwaive (0, 0, waived);
|
||||
if (item->cell_id () != 0) {
|
||||
waive_or_unwaive (item->cell_id (), 0, waived);
|
||||
}
|
||||
}
|
||||
|
||||
int columnCount (const QModelIndex & /*parent*/) const
|
||||
{
|
||||
return 2;
|
||||
|
|
@ -395,7 +434,7 @@ public:
|
|||
if (section == 0) {
|
||||
return QVariant (QObject::tr ("Cell / Category"));
|
||||
} else if (section == 1) {
|
||||
return QVariant (QObject::tr ("Count (Not Visited)"));
|
||||
return QVariant (QObject::tr ("Count (Not Visited) - Waived"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -436,13 +475,14 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool no_errors (const QModelIndex &index) const
|
||||
bool no_errors (const QModelIndex &index, bool include_waived = false) const
|
||||
{
|
||||
MarkerBrowserTreeViewModelCacheEntry *node = (MarkerBrowserTreeViewModelCacheEntry *)(index.internalPointer ());
|
||||
if (node && mp_database) {
|
||||
|
||||
rdb::id_type id = node->id ();
|
||||
bool none = false;
|
||||
size_t thr = include_waived ? node->waived_count () : 0;
|
||||
|
||||
const rdb::Cell *cell = mp_database->cell_by_id (id);
|
||||
const rdb::Category *category = mp_database->category_by_id (id);
|
||||
|
|
@ -464,13 +504,13 @@ public:
|
|||
}
|
||||
|
||||
if (cell == 0 && category == 0) {
|
||||
none = (mp_database->num_items () == 0);
|
||||
none = (mp_database->num_items () <= thr);
|
||||
} else if (category == 0) {
|
||||
none = (cell->num_items () == 0);
|
||||
none = (cell->num_items () <= thr);
|
||||
} else if (cell == 0) {
|
||||
none = (category->num_items () == 0);
|
||||
none = (category->num_items () <= thr);
|
||||
} else {
|
||||
none = (mp_database->num_items (cell->id (), category->id ()) == 0);
|
||||
none = (mp_database->num_items (cell->id (), category->id ()) <= thr);
|
||||
}
|
||||
|
||||
return none;
|
||||
|
|
@ -494,17 +534,31 @@ public:
|
|||
|
||||
if (index.column () == 1) {
|
||||
|
||||
std::string s;
|
||||
|
||||
if (node->count () > 0) {
|
||||
|
||||
size_t visited = node->visited_count (mp_database);
|
||||
size_t waived = node->waived_count ();
|
||||
|
||||
if (visited < node->count ()) {
|
||||
return QVariant (tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("%lu (%lu)")), node->count (), node->count () - visited)));
|
||||
s = tl::sprintf (tl::to_string (tr ("%lu (%lu)")), node->count (), node->count () - visited);
|
||||
} else {
|
||||
return QVariant ((unsigned int) node->count ());
|
||||
s = tl::sprintf (tl::to_string (tr ("%lu")), node->count ());
|
||||
}
|
||||
} else {
|
||||
return QVariant (QString::fromUtf8 (""));
|
||||
|
||||
if (waived > 0) {
|
||||
if (waived == node->count ()) {
|
||||
s += tl::to_string (tr (" - all waived"));
|
||||
} else {
|
||||
s += tl::sprintf (tl::to_string (tr (" - %lu")), waived);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return QVariant (tl::to_qstring (s));
|
||||
|
||||
} else if (index.column () == 0) {
|
||||
|
||||
rdb::id_type id = node->id ();
|
||||
|
|
@ -529,7 +583,7 @@ public:
|
|||
if (cell->name ().empty ()) {
|
||||
return QObject::tr ("All Cells");
|
||||
} else {
|
||||
return QVariant (QString::fromUtf8 ("[") + tl::to_qstring (cell->name ()) + QString::fromUtf8 ("]"));
|
||||
return QVariant (QString::fromUtf8 ("[") + tl::to_qstring (cell->qname ()) + QString::fromUtf8 ("]"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -567,7 +621,7 @@ public:
|
|||
}
|
||||
|
||||
// Green color if no errors are present
|
||||
if (no_errors (index)) {
|
||||
if (no_errors (index, true)) {
|
||||
return QVariant (QColor (0, 192, 0));
|
||||
}
|
||||
|
||||
|
|
@ -725,22 +779,103 @@ public:
|
|||
private:
|
||||
const rdb::Database *mp_database;
|
||||
mutable MarkerBrowserTreeViewModelCacheEntry m_cache;
|
||||
mutable std::multimap<std::pair<rdb::id_type, rdb::id_type>, MarkerBrowserTreeViewModelCacheEntry *> m_cache_by_ids;
|
||||
bool m_show_empty_ones;
|
||||
id_type m_waived_tag_id;
|
||||
|
||||
void waive_or_unwaive (rdb::id_type cell_id, rdb::id_type cat_id, bool waived)
|
||||
{
|
||||
auto k = std::make_pair (cell_id, cat_id);
|
||||
auto c = m_cache_by_ids.find (k);
|
||||
while (c != m_cache_by_ids.end () && c->first == k) {
|
||||
c->second->waive_or_unwaive (waived);
|
||||
++c;
|
||||
}
|
||||
}
|
||||
|
||||
size_t num_waived () const
|
||||
{
|
||||
size_t n = 0;
|
||||
for (auto i = mp_database->items ().begin (); i != mp_database->items ().end (); ++i) {
|
||||
if (i->has_tag (m_waived_tag_id)) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t num_waived_per_cat (id_type cat_id) const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
auto ii = mp_database->items_by_category (cat_id);
|
||||
for (auto i = ii.first; i != ii.second; ++i) {
|
||||
if ((*i)->has_tag (m_waived_tag_id)) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
// include sub-categories
|
||||
const rdb::Category *cat = mp_database->category_by_id (cat_id);
|
||||
tl_assert (cat != 0);
|
||||
for (auto c = cat->sub_categories ().begin (); c != cat->sub_categories ().end (); ++c) {
|
||||
n += num_waived_per_cat (c->id ());
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t num_waived_per_cell_and_cat (id_type cell_id, id_type cat_id) const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
auto ii = mp_database->items_by_cell_and_category (cell_id, cat_id);
|
||||
for (auto i = ii.first; i != ii.second; ++i) {
|
||||
if ((*i)->has_tag (m_waived_tag_id)) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
// include sub-categories
|
||||
const rdb::Category *cat = mp_database->category_by_id (cat_id);
|
||||
tl_assert (cat != 0);
|
||||
for (auto c = cat->sub_categories ().begin (); c != cat->sub_categories ().end (); ++c) {
|
||||
n += num_waived_per_cell_and_cat (cell_id, c->id ());
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t num_waived_per_cell (id_type cell_id) const
|
||||
{
|
||||
auto ii = mp_database->items_by_cell (cell_id);
|
||||
size_t n = 0;
|
||||
for (auto i = ii.first; i != ii.second; ++i) {
|
||||
if ((*i)->has_tag (m_waived_tag_id)) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void invalidate ()
|
||||
{
|
||||
beginResetModel ();
|
||||
|
||||
m_cache.clear ();
|
||||
m_cache_by_ids.clear ();
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry *by_cell_node = new MarkerBrowserTreeViewModelCacheEntry(0, 0);
|
||||
m_cache.add_child (by_cell_node);
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (rdb::id_type (0), rdb::id_type (0)), by_cell_node));
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry *by_category_node = new MarkerBrowserTreeViewModelCacheEntry(0, 1);
|
||||
m_cache.add_child (by_category_node);
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (rdb::id_type (0), rdb::id_type (0)), by_category_node));
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry *all_node = new MarkerBrowserTreeViewModelCacheEntry(0, 2);
|
||||
m_cache.add_child (all_node);
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (rdb::id_type (0), rdb::id_type (0)), all_node));
|
||||
|
||||
m_cache.set_cache_valid (true);
|
||||
|
||||
|
|
@ -760,18 +895,22 @@ private:
|
|||
{
|
||||
const rdb::Category *category = mp_database->category_by_id (node->id ());
|
||||
if (category) {
|
||||
|
||||
for (rdb::Categories::const_iterator c = category->sub_categories ().begin (); c != category->sub_categories ().end (); ++c) {
|
||||
|
||||
node->set_cache_valid (true);
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry *child = new MarkerBrowserTreeViewModelCacheEntry (c->id (), node->branch ());
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (rdb::id_type (0), c->id ()), child));
|
||||
node->add_child (child);
|
||||
|
||||
child->set_count (mp_database->category_by_id (c->id ())->num_items ());
|
||||
child->set_waived_count (num_waived_per_cat (c->id ()));
|
||||
|
||||
add_sub_categories (child);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -781,19 +920,24 @@ private:
|
|||
|
||||
const rdb::Category *category = mp_database->category_by_id (node->id ());
|
||||
if (category) {
|
||||
|
||||
for (rdb::Categories::const_iterator c = category->sub_categories ().begin (); c != category->sub_categories ().end (); ++c) {
|
||||
|
||||
if (partial_tree.find (c->id ()) != partial_tree.end ()) {
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry *child = new MarkerBrowserTreeViewModelCacheEntry (c->id (), node->branch ());
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (cell_id, c->id ()), child));
|
||||
node->add_child (child);
|
||||
|
||||
size_t n = mp_database->num_items (cell_id, c->id ());
|
||||
child->set_count (n);
|
||||
child->set_count (mp_database->num_items (cell_id, c->id ()));
|
||||
child->set_waived_count (num_waived_per_cell_and_cat (cell_id, c->id ()));
|
||||
|
||||
add_sub_categories (cell_id, child, partial_tree);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -813,27 +957,44 @@ private:
|
|||
if (branch == 0) {
|
||||
|
||||
for (rdb::Database::const_cell_iterator c = mp_database->cells ().begin (); c != mp_database->cells ().end (); ++c) {
|
||||
|
||||
if (mp_database->cell_by_id (c->id ()) && (m_show_empty_ones || mp_database->cell_by_id (c->id ())->num_items () != 0)) {
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry *child = new MarkerBrowserTreeViewModelCacheEntry (c->id (), branch);
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (c->id (), rdb::id_type (0)), child));
|
||||
|
||||
child->set_count (mp_database->cell_by_id (c->id ())->num_items ());
|
||||
child->set_waived_count (num_waived_per_cell (c->id ()));
|
||||
|
||||
node->add_child (child);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (branch == 1) {
|
||||
|
||||
for (rdb::Categories::const_iterator c = mp_database->categories ().begin (); c != mp_database->categories ().end (); ++c) {
|
||||
|
||||
if (mp_database->category_by_id (c->id ()) && (m_show_empty_ones || mp_database->category_by_id (c->id ())->num_items () != 0)) {
|
||||
|
||||
MarkerBrowserTreeViewModelCacheEntry *child = new MarkerBrowserTreeViewModelCacheEntry (c->id (), branch);
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (rdb::id_type (0), c->id ()), child));
|
||||
|
||||
child->set_count (mp_database->category_by_id (c->id ())->num_items ());
|
||||
child->set_waived_count (num_waived_per_cat (c->id ()));
|
||||
|
||||
node->add_child (child);
|
||||
add_sub_categories (child);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
node->set_count (mp_database->num_items ());
|
||||
node->set_waived_count (num_waived ());
|
||||
|
||||
} else if (branch == 0) {
|
||||
|
||||
|
|
@ -869,9 +1030,14 @@ private:
|
|||
MarkerBrowserTreeViewModelCacheEntry *child = new MarkerBrowserTreeViewModelCacheEntry (c->id (), branch);
|
||||
|
||||
size_t n = mp_database->num_items (id, c->id ());
|
||||
|
||||
if (m_show_empty_ones || n != 0) {
|
||||
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (id, c->id ()), child));
|
||||
|
||||
child->set_count (n);
|
||||
child->set_waived_count (num_waived_per_cell_and_cat (id, c->id ()));
|
||||
|
||||
node->add_child (child);
|
||||
|
||||
add_sub_categories (id, child, category_ids);
|
||||
|
|
@ -903,8 +1069,14 @@ private:
|
|||
size_t n = mp_database->num_items (*c, id);
|
||||
|
||||
if (m_show_empty_ones || n != 0) {
|
||||
|
||||
m_cache_by_ids.insert (std::make_pair (std::make_pair (*c, id), child));
|
||||
|
||||
child->set_count (n);
|
||||
child->set_waived_count (num_waived_per_cell_and_cat (*c, id));
|
||||
|
||||
node->add_child (child);
|
||||
|
||||
} else {
|
||||
delete child;
|
||||
}
|
||||
|
|
@ -996,6 +1168,16 @@ public:
|
|||
m_sorting_order = sorting_order;
|
||||
}
|
||||
|
||||
int sorting () const
|
||||
{
|
||||
return m_sorting;
|
||||
}
|
||||
|
||||
bool sorting_order () const
|
||||
{
|
||||
return m_sorting_order;
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
bool set_items (const std::vector <std::pair<Iter, Iter> > &be_vector, size_t max_marker_count)
|
||||
{
|
||||
|
|
@ -1528,6 +1710,7 @@ MarkerBrowserPage::MarkerBrowserPage (QWidget * /*parent*/)
|
|||
connect (list_down_pb, SIGNAL (clicked ()), this, SLOT (list_down_clicked ()));
|
||||
connect (flags_pb, SIGNAL (clicked ()), this, SLOT (flag_button_clicked ()));
|
||||
connect (important_pb, SIGNAL (clicked ()), this, SLOT (important_button_clicked ()));
|
||||
connect (edit_pb, SIGNAL (clicked ()), this, SLOT (edit_button_clicked ()));
|
||||
connect (waive_pb, SIGNAL (clicked ()), this, SLOT (waived_button_clicked ()));
|
||||
connect (photo_pb, SIGNAL (clicked ()), this, SLOT (snapshot_button_clicked ()));
|
||||
connect (nophoto_pb, SIGNAL (clicked ()), this, SLOT (remove_snapshot_button_clicked ()));
|
||||
|
|
@ -1724,6 +1907,16 @@ MarkerBrowserPage::set_rdb (rdb::Database *database)
|
|||
rerun_button->setToolTip (QString ());
|
||||
}
|
||||
|
||||
// mark items visited that carry the waived flag
|
||||
if (mp_database) {
|
||||
id_type waived_tag_id = mp_database->tags ().tag ("waived").id ();
|
||||
for (auto i = mp_database->items ().begin (); i != mp_database->items ().end (); ++i) {
|
||||
if (i->has_tag (waived_tag_id)) {
|
||||
mp_database->set_item_visited (i.operator-> (), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QAbstractItemModel *tree_model = directory_tree->model ();
|
||||
|
||||
MarkerBrowserTreeViewModel *new_model = new MarkerBrowserTreeViewModel ();
|
||||
|
|
@ -1745,6 +1938,9 @@ MarkerBrowserPage::set_rdb (rdb::Database *database)
|
|||
QAbstractItemModel *list_model = markers_list->model ();
|
||||
|
||||
MarkerBrowserListViewModel *new_list_model = new MarkerBrowserListViewModel ();
|
||||
// default sorting is by waived flag
|
||||
new_list_model->set_sorting (2, true);
|
||||
markers_list->header ()->setSortIndicator (new_list_model->sorting (), new_list_model->sorting_order () ? Qt::AscendingOrder : Qt::DescendingOrder);
|
||||
new_list_model->set_database (database);
|
||||
markers_list->setModel (new_list_model);
|
||||
connect (markers_list->selectionModel (), SIGNAL (selectionChanged (const QItemSelection &, const QItemSelection &)), this, SLOT (markers_selection_changed (const QItemSelection &, const QItemSelection &)));
|
||||
|
|
@ -1939,6 +2135,8 @@ MarkerBrowserPage::update_info_text ()
|
|||
size_t n_category = 0;
|
||||
const rdb::Item *item = 0;
|
||||
size_t n_item = 0;
|
||||
std::string comment;
|
||||
size_t n_comment = 0;
|
||||
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
|
||||
|
|
@ -1950,6 +2148,11 @@ MarkerBrowserPage::update_info_text ()
|
|||
item = i;
|
||||
++n_item;
|
||||
|
||||
if (! item->comment ().empty () && item->comment () != comment) {
|
||||
comment = item->comment ();
|
||||
++n_comment;
|
||||
}
|
||||
|
||||
const rdb::Cell *c = mp_database->cell_by_id (item->cell_id ());
|
||||
if (c && c != cell) {
|
||||
cell = c;
|
||||
|
|
@ -1976,11 +2179,11 @@ MarkerBrowserPage::update_info_text ()
|
|||
info += "<h3>";
|
||||
|
||||
if (category && n_category == 1) {
|
||||
info += category->name ();
|
||||
tl::escape_to_html (info, category->name ());
|
||||
}
|
||||
|
||||
if (cell && n_cell == 1 && ! cell->name ().empty ()) {
|
||||
info += " [" + cell->name () + "]";
|
||||
tl::escape_to_html (info, std::string (" [") + cell->name () + "]");
|
||||
}
|
||||
|
||||
info += "</h3>";
|
||||
|
|
@ -1997,6 +2200,12 @@ MarkerBrowserPage::update_info_text ()
|
|||
info += "</p>";
|
||||
}
|
||||
|
||||
if (! comment.empty () && n_comment == 1) {
|
||||
info += "<p style=\"color:gray\">";
|
||||
tl::escape_to_html (info, comment);
|
||||
info += "</p>";
|
||||
}
|
||||
|
||||
info += "<p/>";
|
||||
|
||||
if (item && n_item == 1) {
|
||||
|
|
@ -2085,8 +2294,6 @@ MarkerBrowserPage::do_update_markers ()
|
|||
item_index = size_t (selected_item->row ());
|
||||
++n_item;
|
||||
|
||||
std::string info;
|
||||
|
||||
const rdb::Cell *c = mp_database->cell_by_id (item->cell_id ());
|
||||
if (c && c != cell) {
|
||||
cell = c;
|
||||
|
|
@ -2736,7 +2943,61 @@ MarkerBrowserPage::flag_menu_selected ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MarkerBrowserPage::edit_button_clicked ()
|
||||
{
|
||||
if (! mp_database) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarkerBrowserListViewModel *list_model = dynamic_cast<MarkerBrowserListViewModel *> (markers_list->model ());
|
||||
if (! list_model) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string str;
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (! i->comment ().empty ()) {
|
||||
if (str.empty ()) {
|
||||
str = i->comment ();
|
||||
} else if (str != i->comment ()) {
|
||||
str.clear ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
|
||||
#if QT_VERSION >= 0x50200
|
||||
QString new_text = QInputDialog::getMultiLineText (this, QObject::tr ("Edit Marker Comment"), QObject::tr ("Comment"), tl::to_qstring (str), &ok);
|
||||
str = tl::to_string (new_text);
|
||||
#else
|
||||
QString new_text = QInputDialog::getText (this, QObject::tr ("Edit Marker Comment"), QObject::tr ("Comment"), QLineEdit::Normal, tl::to_qstring (tl::escape_string (str)), &ok);
|
||||
str = tl::unescape_string (tl::to_string (new_text));
|
||||
#endif
|
||||
|
||||
if (ok) {
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
mp_database->set_item_comment (i, str);
|
||||
}
|
||||
}
|
||||
|
||||
update_info_text ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserPage::waived_button_clicked ()
|
||||
{
|
||||
if (! mp_database) {
|
||||
|
|
@ -2754,7 +3015,7 @@ MarkerBrowserPage::waived_button_clicked ()
|
|||
size_t nno = 0;
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
|
|
@ -2792,7 +3053,7 @@ MarkerBrowserPage::important_button_clicked ()
|
|||
size_t nno = 0;
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
|
|
@ -2831,7 +3092,7 @@ MarkerBrowserPage::remove_snapshot_button_clicked ()
|
|||
if (msgbox.exec () == QMessageBox::Yes) {
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
|
|
@ -2858,7 +3119,7 @@ MarkerBrowserPage::snapshot_button_clicked ()
|
|||
}
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
|
|
@ -2903,7 +3164,12 @@ MarkerBrowserPage::unwaive_all ()
|
|||
return;
|
||||
}
|
||||
|
||||
QMessageBox msgbox (QMessageBox::Question,
|
||||
MarkerBrowserTreeViewModel *tree_model = dynamic_cast<MarkerBrowserTreeViewModel *> (directory_tree->model ());
|
||||
if (! tree_model) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMessageBox msgbox (QMessageBox::Question,
|
||||
QObject::tr ("Remove All Waived"),
|
||||
QObject::tr ("Are you sure to remove the waived flags from all markers?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
|
@ -2912,7 +3178,10 @@ MarkerBrowserPage::unwaive_all ()
|
|||
id_type waived_tag_id = mp_database->tags ().tag ("waived").id ();
|
||||
|
||||
for (Items::const_iterator i = mp_database->items ().begin (); i != mp_database->items ().end (); ++i) {
|
||||
mp_database->remove_item_tag (&*i, waived_tag_id);
|
||||
if (i->has_tag (waived_tag_id)) {
|
||||
mp_database->remove_item_tag (i.operator-> (), waived_tag_id);
|
||||
tree_model->waived_changed (i.operator-> (), false);
|
||||
}
|
||||
}
|
||||
|
||||
list_model->mark_data_changed ();
|
||||
|
|
@ -2933,7 +3202,7 @@ MarkerBrowserPage::revisit_all ()
|
|||
}
|
||||
|
||||
for (Items::const_iterator i = mp_database->items ().begin (); i != mp_database->items ().end (); ++i) {
|
||||
mp_database->set_item_visited (&*i, false);
|
||||
mp_database->set_item_visited (i.operator-> (), false);
|
||||
}
|
||||
|
||||
list_model->mark_data_changed ();
|
||||
|
|
@ -2960,7 +3229,7 @@ MarkerBrowserPage::revisit_non_waived ()
|
|||
|
||||
for (Items::const_iterator i = mp_database->items ().begin (); i != mp_database->items ().end (); ++i) {
|
||||
if (! i->has_tag (waived_tag_id)) {
|
||||
mp_database->set_item_visited (&*i, false);
|
||||
mp_database->set_item_visited (i.operator-> (), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2988,7 +3257,7 @@ MarkerBrowserPage::revisit_important ()
|
|||
|
||||
for (Items::const_iterator i = mp_database->items ().begin (); i != mp_database->items ().end (); ++i) {
|
||||
if (i->has_tag (important_tag_id)) {
|
||||
mp_database->set_item_visited (&*i, false);
|
||||
mp_database->set_item_visited (i.operator-> (), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3015,7 +3284,7 @@ MarkerBrowserPage::mark_important ()
|
|||
id_type important_tag_id = mp_database->tags ().tag ("important").id ();
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
|
|
@ -3042,7 +3311,7 @@ MarkerBrowserPage::mark_unimportant ()
|
|||
id_type important_tag_id = mp_database->tags ().tag ("important").id ();
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
|
|
@ -3079,7 +3348,7 @@ MarkerBrowserPage::mark_visited (bool f)
|
|||
}
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
|
|
@ -3099,32 +3368,17 @@ MarkerBrowserPage::mark_visited (bool f)
|
|||
void
|
||||
MarkerBrowserPage::waive ()
|
||||
{
|
||||
if (! mp_database) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarkerBrowserListViewModel *list_model = dynamic_cast<MarkerBrowserListViewModel *> (markers_list->model ());
|
||||
if (! list_model) {
|
||||
return;
|
||||
}
|
||||
|
||||
id_type waived_tag_id = mp_database->tags ().tag ("waived").id ();
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
mp_database->add_item_tag (i, waived_tag_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_model->mark_data_changed ();
|
||||
waive_or_unwaive (true);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MarkerBrowserPage::unwaive ()
|
||||
{
|
||||
waive_or_unwaive (false);
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserPage::waive_or_unwaive (bool w)
|
||||
{
|
||||
if (! mp_database) {
|
||||
return;
|
||||
|
|
@ -3135,19 +3389,38 @@ MarkerBrowserPage::unwaive ()
|
|||
return;
|
||||
}
|
||||
|
||||
MarkerBrowserTreeViewModel *tree_model = dynamic_cast<MarkerBrowserTreeViewModel *> (directory_tree->model ());
|
||||
if (! tree_model) {
|
||||
return;
|
||||
}
|
||||
|
||||
id_type waived_tag_id = mp_database->tags ().tag ("waived").id ();
|
||||
|
||||
QModelIndexList selected = markers_list->selectionModel ()->selectedIndexes ();
|
||||
for (QModelIndexList::const_iterator selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
for (auto selected_item = selected.begin (); selected_item != selected.end (); ++selected_item) {
|
||||
if (selected_item->column () == 0) {
|
||||
const rdb::Item *i = list_model->item (selected_item->row ());
|
||||
if (i) {
|
||||
mp_database->remove_item_tag (i, waived_tag_id);
|
||||
bool was_waived = i->has_tag (waived_tag_id);
|
||||
if (w != was_waived) {
|
||||
if (w) {
|
||||
mp_database->add_item_tag (i, waived_tag_id);
|
||||
} else {
|
||||
mp_database->remove_item_tag (i, waived_tag_id);
|
||||
}
|
||||
if (w) {
|
||||
// waiving an item makes it visited (rationale: once waived, an item is no
|
||||
// longer of interest)
|
||||
mp_database->set_item_visited (i, true);
|
||||
}
|
||||
tree_model->waived_changed (i, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_model->mark_data_changed ();
|
||||
tree_model->mark_data_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ public slots:
|
|||
void flag_menu_selected ();
|
||||
void important_button_clicked ();
|
||||
void waived_button_clicked ();
|
||||
void edit_button_clicked ();
|
||||
void snapshot_button_clicked ();
|
||||
void remove_snapshot_button_clicked ();
|
||||
void revisit_non_waived ();
|
||||
|
|
@ -238,6 +239,7 @@ private:
|
|||
void do_update_markers ();
|
||||
void update_info_text ();
|
||||
void rerun_macro ();
|
||||
void waive_or_unwaive (bool w);
|
||||
};
|
||||
|
||||
} // namespace rdb
|
||||
|
|
|
|||
|
|
@ -305,6 +305,8 @@ TEST(40_DeviceExtractorErrors)
|
|||
TEST(50_BasicSoftConnection)
|
||||
{
|
||||
run_test (_this, "soft_connect1", "soft_connect1.gds", true, false /*no LVS*/);
|
||||
// issue #1691
|
||||
run_test (_this, "soft_connect1a", "soft_connect1.gds", true, false /*no LVS*/);
|
||||
}
|
||||
|
||||
// No errors
|
||||
|
|
|
|||
|
|
@ -265,17 +265,25 @@ Class<rdb::Cell> decl_RdbCell ("rdb", "RdbCell",
|
|||
"The cell name is an string that identifies the category in the database. "
|
||||
"Additionally, a cell may carry a variant identifier which is a string that uniquely identifies a cell "
|
||||
"in the context of its variants. The \"qualified name\" contains both the cell name and the variant name. "
|
||||
"Cell names are also used to identify report database cell's with layout cells. "
|
||||
"Cell names are also used to identify report database cells with layout cells. For variants, the layout cell name "
|
||||
"can be specified explicitly with the \\layout_name attribute (see \\RdbDatabase#create_cell). The latter is available "
|
||||
"since version 0.29.1.\n"
|
||||
"@return The cell name\n"
|
||||
) +
|
||||
gsi::method ("variant", &rdb::Cell::variant,
|
||||
"@brief Gets the cell variant name\n"
|
||||
"A variant name additionally identifies the cell when multiple cells with the same name are present. "
|
||||
"A variant name is either assigned automatically or set when creating a cell. "
|
||||
"A variant name is either assigned automatically or set when creating a cell.\n"
|
||||
"@return The cell variant name\n"
|
||||
) +
|
||||
gsi::method ("qname", &rdb::Cell::qname,
|
||||
"@brief Gets the cell's qualified name\n"
|
||||
gsi::method ("layout_name", &rdb::Cell::layout_name,
|
||||
"@brief Gets the name of the layout cell\n"
|
||||
"For variants, this string is the name of the actual layout cell. If empty, the cell is assume to be called 'name'.\n"
|
||||
"@return The layout cell name\n"
|
||||
"This read-only attribute has been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::method ("qname", &rdb::Cell::qname,
|
||||
"@brief Gets the qualified name of the cell\n"
|
||||
"The qualified name is a combination of the cell name and optionally the variant name. "
|
||||
"It is used to identify the cell by name in a unique way.\n"
|
||||
"@return The qualified name\n"
|
||||
|
|
@ -911,6 +919,10 @@ Class<rdb::Item> decl_RdbItem ("rdb", "RdbItem",
|
|||
"@brief Remove the tag with the given id from the item\n"
|
||||
"If a tag with that ID does not exists on this item, this method does nothing."
|
||||
) +
|
||||
gsi::method ("remove_tags", &rdb::Item::remove_tags,
|
||||
"@brief Removes all tags from the item\n"
|
||||
"This method has been introduced in version 0.29.1."
|
||||
) +
|
||||
gsi::method ("has_tag?", &rdb::Item::has_tag, gsi::arg ("tag_id"),
|
||||
"@brief Returns a value indicating whether the item has a tag with the given ID\n"
|
||||
"@return True, if the item has a tag with the given ID\n"
|
||||
|
|
@ -928,6 +940,19 @@ Class<rdb::Item> decl_RdbItem ("rdb", "RdbItem",
|
|||
"See \\image_str how to obtain the image.\n\n"
|
||||
"This method has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::method ("comment", &rdb::Item::comment,
|
||||
"@brief Gets the common associated with this item as a string\n"
|
||||
"@return The comment string\n"
|
||||
"The comment string is an arbitrary string added by the user to the item.\n"
|
||||
"\n"
|
||||
"This attribute has been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::method ("comment=", &rdb::Item::set_comment, gsi::arg ("comment"),
|
||||
"@brief Sets the common associated with this item as a string\n"
|
||||
"See \\comment for a description of that attribute.\n"
|
||||
"\n"
|
||||
"This attribute has been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::method ("image_str", &rdb::Item::image_str,
|
||||
"@brief Gets the image associated with this item as a string\n"
|
||||
"@return A base64-encoded image file (in PNG format)\n"
|
||||
|
|
@ -1317,6 +1342,7 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
|
|||
"@brief Creates a new sub-category\n"
|
||||
"@param parent The category under which the category should be created\n"
|
||||
"@param name The name of the category\n"
|
||||
"Since version 0.29.1, 'parent' can be nil. In that case, a top-level category is created."
|
||||
) +
|
||||
gsi::method ("category_by_path", &rdb::Database::category_by_name, gsi::arg ("path"),
|
||||
"@brief Gets a category by path\n"
|
||||
|
|
@ -1344,10 +1370,12 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
|
|||
"@brief Creates a new cell\n"
|
||||
"@param name The name of the cell\n"
|
||||
) +
|
||||
gsi::method ("create_cell", (rdb::Cell *(rdb::Database::*) (const std::string &, const std::string &)) &rdb::Database::create_cell, gsi::arg ("name"), gsi::arg ("variant"),
|
||||
gsi::method ("create_cell", (rdb::Cell *(rdb::Database::*) (const std::string &, const std::string &, const std::string &)) &rdb::Database::create_cell, gsi::arg ("name"), gsi::arg ("variant"), gsi::arg ("layout_name", std::string ()),
|
||||
"@brief Creates a new cell, potentially as a variant for a cell with the same name\n"
|
||||
"@param name The name of the cell\n"
|
||||
"@param variant The variant name of the cell\n"
|
||||
"@param layout_name For variants, this is the name of the layout cell. If empty, 'name' is used for the layout cell name.\n"
|
||||
"The 'layout_name' argument has been added in version 0.29.1.\n"
|
||||
) +
|
||||
gsi::method ("variants", &rdb::Database::variants, gsi::arg ("name"),
|
||||
"@brief Gets the variants for a given cell name\n"
|
||||
|
|
@ -1562,6 +1590,36 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
|
|||
"@param trans The transformation to apply\n"
|
||||
"@param edge_pairs The list of edge_pairs for which the items are created\n"
|
||||
) +
|
||||
gsi::method ("apply", &rdb::Database::apply, gsi::arg ("other"),
|
||||
"@brief Transfers item attributes from one database to another for identical items\n"
|
||||
"This method will identify items that are identical between the two databases and transfer "
|
||||
"item attributes from the 'other' database to this database. Transferable attributes are:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li Images @/li\n"
|
||||
"@li Item tags @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"Existing attributes in this database are overwritten.\n"
|
||||
"\n"
|
||||
"Items are identical if\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li They belong to the same cell (by qname) @/li\n"
|
||||
"@li They belong to the same category (by name) @/li\n"
|
||||
"@li Their values are identical @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"Values are identical if their individual values and (optional) value tags are identical. "
|
||||
"Values tagged with a tag unknown to the other database are ignored. "
|
||||
"The order of values matters during the compare. So the value pair (17.0, 'abc') is different from ('abc', 17.0).\n"
|
||||
"\n"
|
||||
"The intended application for this method is use for error waiving: as the waived attribute is a transferable "
|
||||
"attribute, it is possible to apply the waived flag from from a waiver database (the 'other' database) using this "
|
||||
"method.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.29.1."
|
||||
) +
|
||||
gsi::method ("is_modified?", &rdb::Database::is_modified,
|
||||
"@brief Returns a value indicating whether the database has been modified\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -60,16 +60,18 @@ namespace rdb
|
|||
// type index specializations
|
||||
|
||||
template <> RDB_PUBLIC int type_index_of<double> () { return 0; }
|
||||
template <> RDB_PUBLIC int type_index_of<std::string> () { return 1; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DPolygon> () { return 2; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DEdge> () { return 3; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DEdgePair> () { return 4; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DBox> () { return 5; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DPath> () { return 6; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DText> () { return 7; }
|
||||
template <> RDB_PUBLIC int type_index_of<int> () { return 1; }
|
||||
template <> RDB_PUBLIC int type_index_of<std::string> () { return 2; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DPolygon> () { return 3; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DEdge> () { return 4; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DEdgePair> () { return 5; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DBox> () { return 6; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DPath> () { return 7; }
|
||||
template <> RDB_PUBLIC int type_index_of<db::DText> () { return 8; }
|
||||
|
||||
// Explicit instantiations to make VC++ happy in debug mode
|
||||
template class RDB_PUBLIC Value<double>;
|
||||
template class RDB_PUBLIC Value<int>;
|
||||
template class RDB_PUBLIC Value<std::string>;
|
||||
template class RDB_PUBLIC Value<db::DPolygon>;
|
||||
template class RDB_PUBLIC Value<db::DEdge>;
|
||||
|
|
@ -85,6 +87,11 @@ template <> RDB_PUBLIC std::string Value<double>::to_string () const
|
|||
return "float: " + tl::to_string (m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC std::string Value<int>::to_string () const
|
||||
{
|
||||
return "int: " + tl::to_string (m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC std::string Value<std::string>::to_string () const
|
||||
{
|
||||
return "text: " + tl::to_word_or_quoted_string (m_value);
|
||||
|
|
@ -127,6 +134,11 @@ template <> RDB_PUBLIC std::string Value<double>::to_display_string () const
|
|||
return tl::to_string (m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC std::string Value<int>::to_display_string () const
|
||||
{
|
||||
return tl::to_string (m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC std::string Value<std::string>::to_display_string () const
|
||||
{
|
||||
return m_value;
|
||||
|
|
@ -162,6 +174,62 @@ template <> RDB_PUBLIC std::string Value<db::DText>::to_display_string () const
|
|||
return to_string ();
|
||||
}
|
||||
|
||||
// compare implementations
|
||||
|
||||
template <> RDB_PUBLIC bool Value<double>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<double> *other = static_cast<const Value<double> *> (o);
|
||||
return m_value < other->m_value - db::epsilon;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<int>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<int> *other = static_cast<const Value<int> *> (o);
|
||||
return m_value < other->m_value;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<std::string>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<std::string> *other = static_cast<const Value<std::string> *> (o);
|
||||
return m_value < other->m_value;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DPolygon>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<db::DPolygon> *other = static_cast<const Value<db::DPolygon> *> (o);
|
||||
return m_value.less (other->m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DEdge>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<db::DEdge> *other = static_cast<const Value<db::DEdge> *> (o);
|
||||
return m_value.less (other->m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DEdgePair>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<db::DEdgePair> *other = static_cast<const Value<db::DEdgePair> *> (o);
|
||||
return m_value.less (other->m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DBox>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<db::DBox> *other = static_cast<const Value<db::DBox> *> (o);
|
||||
return m_value.less (other->m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DPath>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<db::DPath> *other = static_cast<const Value<db::DPath> *> (o);
|
||||
return m_value.less (other->m_value);
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<db::DText>::compare (const ValueBase *o) const
|
||||
{
|
||||
const Value<db::DText> *other = static_cast<const Value<db::DText> *> (o);
|
||||
return m_value.less (other->m_value);
|
||||
}
|
||||
|
||||
// is_shape implementations
|
||||
|
||||
template <> RDB_PUBLIC bool Value<double>::is_shape () const
|
||||
|
|
@ -169,6 +237,11 @@ template <> RDB_PUBLIC bool Value<double>::is_shape () const
|
|||
return false;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<int>::is_shape () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <> RDB_PUBLIC bool Value<std::string>::is_shape () const
|
||||
{
|
||||
return false;
|
||||
|
|
@ -403,6 +476,58 @@ Values::operator= (const Values &d)
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
Values::compare (const Values &other, const std::map<id_type, id_type> &tag_map, const std::map<id_type, id_type> &rev_tag_map) const
|
||||
{
|
||||
Values::const_iterator a = begin (), b = other.begin ();
|
||||
while (a != end () && b != other.end ()) {
|
||||
|
||||
id_type t12 = 0;
|
||||
while (a != end () && a->tag_id () != 0) {
|
||||
auto j = tag_map.find (a->tag_id ());
|
||||
if (j != tag_map.end ()) {
|
||||
t12 = j->second;
|
||||
break;
|
||||
}
|
||||
++a;
|
||||
}
|
||||
|
||||
id_type t2 = 0;
|
||||
while (b != other.end () && b->tag_id () != 0) {
|
||||
auto j = rev_tag_map.find (b->tag_id ());
|
||||
if (j != rev_tag_map.end ()) {
|
||||
t2 = j->first;
|
||||
break;
|
||||
}
|
||||
++b;
|
||||
}
|
||||
|
||||
if (a == end () || b == other.end ()) {
|
||||
return b != other.end ();
|
||||
}
|
||||
|
||||
if (t12 != t2) {
|
||||
return t12 < t2;
|
||||
}
|
||||
|
||||
if (a->get () && b->get ()) {
|
||||
if (rdb::ValueBase::compare (a->get (), b->get ())) {
|
||||
return true;
|
||||
} else if (rdb::ValueBase::compare (b->get (), a->get ())) {
|
||||
return false;
|
||||
}
|
||||
} else if ((a->get () != 0) != (b->get () != 0)) {
|
||||
return (a->get () != 0) < (b->get () != 0);
|
||||
}
|
||||
|
||||
++a;
|
||||
++b;
|
||||
|
||||
}
|
||||
|
||||
return b != other.end ();
|
||||
}
|
||||
|
||||
std::string
|
||||
Values::to_string (const Database *rdb) const
|
||||
{
|
||||
|
|
@ -447,7 +572,7 @@ Cells::import_cell (const Cell &c)
|
|||
{
|
||||
Cell *cell;
|
||||
if (mp_database) {
|
||||
cell = mp_database->create_cell (c.name (), c.variant ());
|
||||
cell = mp_database->create_cell (c.name (), c.variant (), c.layout_name ());
|
||||
} else {
|
||||
cell = new Cell (0, c.name ());
|
||||
add_cell (cell);
|
||||
|
|
@ -479,8 +604,8 @@ Cell::Cell (id_type id, const std::string &name)
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Cell::Cell (id_type id, const std::string &name, const std::string &variant)
|
||||
: m_id (id), m_name (name), m_variant (variant), m_num_items (0), m_num_items_visited (0), mp_database (0)
|
||||
Cell::Cell (id_type id, const std::string &name, const std::string &variant, const std::string &layout_name = std::string ())
|
||||
: m_id (id), m_name (name), m_variant (variant), m_layout_name (layout_name), m_num_items (0), m_num_items_visited (0), mp_database (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -812,14 +937,14 @@ Tags::tag (const std::string &name, bool user_tag)
|
|||
const Tag &
|
||||
Tags::tag (id_type id) const
|
||||
{
|
||||
tl_assert (id - 1 < m_tags.size () && id > 0);
|
||||
tl_assert (id < m_tags.size () + 1 && id > 0);
|
||||
return m_tags [id - 1];
|
||||
}
|
||||
|
||||
Tag &
|
||||
Tags::tag (id_type id)
|
||||
{
|
||||
tl_assert (id - 1 < m_tags.size () && id > 0);
|
||||
tl_assert (id < m_tags.size () + 1 && id > 0);
|
||||
return m_tags [id - 1];
|
||||
}
|
||||
|
||||
|
|
@ -870,6 +995,7 @@ Item &Item::operator= (const Item &d)
|
|||
m_category_id = d.m_category_id;
|
||||
m_visited = d.m_visited;
|
||||
m_multiplicity = d.m_multiplicity;
|
||||
m_comment = d.m_comment;
|
||||
m_tag_ids = d.m_tag_ids;
|
||||
m_image_str = d.m_image_str;
|
||||
}
|
||||
|
|
@ -1205,6 +1331,10 @@ Database::import_cells (const Cells &cells)
|
|||
Category *
|
||||
Database::create_category (Category *parent, const std::string &name)
|
||||
{
|
||||
if (! parent) {
|
||||
return create_category (name);
|
||||
}
|
||||
|
||||
set_modified ();
|
||||
|
||||
Category *cat = create_category (&parent->sub_categories (), name);
|
||||
|
|
@ -1252,7 +1382,7 @@ Database::category_by_id_non_const (id_type id)
|
|||
}
|
||||
|
||||
Cell *
|
||||
Database::create_cell (const std::string &name, const std::string &variant)
|
||||
Database::create_cell (const std::string &name, const std::string &variant, const std::string &layout_name)
|
||||
{
|
||||
set_modified ();
|
||||
|
||||
|
|
@ -1289,13 +1419,13 @@ Database::create_cell (const std::string &name, const std::string &variant)
|
|||
}
|
||||
}
|
||||
|
||||
new_cell = new Cell (++m_next_id, name, tl::to_string (variant_index + 1));
|
||||
new_cell = new Cell (++m_next_id, name, tl::to_string (variant_index + 1), layout_name);
|
||||
|
||||
variant->second.push_back (new_cell->id ());
|
||||
|
||||
} else {
|
||||
|
||||
new_cell = new Cell (++m_next_id, name);
|
||||
new_cell = new Cell (++m_next_id, name, std::string (), layout_name);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1305,7 +1435,7 @@ Database::create_cell (const std::string &name, const std::string &variant)
|
|||
|
||||
} else {
|
||||
|
||||
new_cell = new Cell (++m_next_id, name, variant);
|
||||
new_cell = new Cell (++m_next_id, name, variant, layout_name);
|
||||
m_cells.add_cell (new_cell);
|
||||
m_cells_by_id.insert (std::make_pair (new_cell->id (), new_cell));
|
||||
m_cells_by_qname.insert (std::make_pair (new_cell->qname (), new_cell));
|
||||
|
|
@ -1399,6 +1529,13 @@ Database::remove_item_tag (const Item *item, id_type tag)
|
|||
const_cast <Item *> (item)->remove_tag (tag);
|
||||
}
|
||||
|
||||
void
|
||||
Database::set_item_comment (const Item *item, const std::string &comment)
|
||||
{
|
||||
set_modified ();
|
||||
const_cast <Item *> (item)->set_comment (comment);
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Database::set_item_image (const Item *item, const QImage &image)
|
||||
|
|
@ -1625,7 +1762,7 @@ read_db_from_layout (rdb::Database *db, tl::InputStream &is)
|
|||
}
|
||||
|
||||
void
|
||||
Database::load (const std::string &fn)
|
||||
Database::load (std::string fn)
|
||||
{
|
||||
tl::log << "Loading RDB from " << fn;
|
||||
|
||||
|
|
@ -1659,6 +1796,161 @@ Database::load (const std::string &fn)
|
|||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class ValueMapEntryCompare
|
||||
{
|
||||
public:
|
||||
ValueMapEntryCompare (const std::map<id_type, id_type> &tag2tag, const std::map<id_type, id_type> &rev_tag2tag)
|
||||
{
|
||||
mp_tag2tag = &tag2tag;
|
||||
mp_rev_tag2tag = &rev_tag2tag;
|
||||
}
|
||||
|
||||
bool operator() (const Item *a, const Item *b) const
|
||||
{
|
||||
return a->values ().compare (b->values (), *mp_tag2tag, *mp_rev_tag2tag);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::map<id_type, id_type> *mp_tag2tag;
|
||||
const std::map<id_type, id_type> *mp_rev_tag2tag;
|
||||
};
|
||||
|
||||
class ValueMapEntry
|
||||
{
|
||||
public:
|
||||
ValueMapEntry ()
|
||||
: mp_tag2tag (0), mp_rev_tag2tag (0)
|
||||
{ }
|
||||
|
||||
void build (const rdb::Database &rdb, id_type cell_id, id_type cat_id, const std::map<id_type, id_type> &tag2tag, const std::map<id_type, id_type> &rev_tag2tag)
|
||||
{
|
||||
mp_tag2tag = &tag2tag;
|
||||
mp_rev_tag2tag = &rev_tag2tag;
|
||||
|
||||
auto i2i = rdb.items_by_cell_and_category (cell_id, cat_id);
|
||||
|
||||
size_t n = 0;
|
||||
for (auto i = i2i.first; i != i2i.second; ++i) {
|
||||
++n;
|
||||
}
|
||||
m_items.reserve (n);
|
||||
|
||||
for (auto i = i2i.first; i != i2i.second; ++i) {
|
||||
m_items.push_back ((*i).operator-> ());
|
||||
}
|
||||
|
||||
ValueMapEntryCompare cmp (*mp_tag2tag, *mp_rev_tag2tag);
|
||||
std::sort (m_items.begin (), m_items.end (), cmp);
|
||||
}
|
||||
|
||||
const Item *find (const rdb::Item &item) const
|
||||
{
|
||||
ValueMapEntryCompare cmp (*mp_tag2tag, *mp_rev_tag2tag);
|
||||
|
||||
auto i = std::lower_bound (m_items.begin (), m_items.end (), &item, cmp);
|
||||
if (i == m_items.end ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmp (&item, *i) || cmp (*i, &item)) {
|
||||
return 0;
|
||||
} else {
|
||||
return *i;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<const Item *> m_items;
|
||||
const std::map<id_type, id_type> *mp_tag2tag;
|
||||
const std::map<id_type, id_type> *mp_rev_tag2tag;
|
||||
};
|
||||
}
|
||||
|
||||
static void map_category (const rdb::Category &cat, const rdb::Database &db, std::map<id_type, id_type> &cat2cat)
|
||||
{
|
||||
const rdb::Category *this_cat = db.category_by_name (cat.path ());
|
||||
if (this_cat) {
|
||||
cat2cat.insert (std::make_pair (this_cat->id (), cat.id ()));
|
||||
}
|
||||
|
||||
for (auto c = cat.sub_categories ().begin (); c != cat.sub_categories ().end (); ++c) {
|
||||
map_category (*c, db, cat2cat);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Database::apply (const rdb::Database &other)
|
||||
{
|
||||
std::map<id_type, id_type> cell2cell;
|
||||
std::map<id_type, id_type> cat2cat;
|
||||
std::map<id_type, id_type> tag2tag;
|
||||
std::map<id_type, id_type> rev_tag2tag;
|
||||
|
||||
for (auto c = other.cells ().begin (); c != other.cells ().end (); ++c) {
|
||||
// TODO: do we have a consistent scheme of naming variants? What requirements
|
||||
// exist towards detecting variant specific waivers
|
||||
const rdb::Cell *this_cell = cell_by_qname (c->qname ());
|
||||
if (this_cell) {
|
||||
cell2cell.insert (std::make_pair (this_cell->id (), c->id ()));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto c = other.categories ().begin (); c != other.categories ().end (); ++c) {
|
||||
map_category (*c, *this, cat2cat);
|
||||
}
|
||||
|
||||
std::map<std::string, id_type> tags_by_name;
|
||||
for (auto c = tags ().begin_tags (); c != tags ().end_tags (); ++c) {
|
||||
tags_by_name.insert (std::make_pair (c->name (), c->id ()));
|
||||
}
|
||||
|
||||
for (auto c = other.tags ().begin_tags (); c != other.tags ().end_tags (); ++c) {
|
||||
auto t = tags_by_name.find (c->name ());
|
||||
if (t != tags_by_name.end ()) {
|
||||
tag2tag.insert (std::make_pair (t->second, c->id ()));
|
||||
rev_tag2tag.insert (std::make_pair (c->id (), t->second));
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::pair<id_type, id_type>, ValueMapEntry> value_map;
|
||||
|
||||
for (Items::iterator i = items_non_const ().begin (); i != items_non_const ().end (); ++i) {
|
||||
|
||||
auto icell = cell2cell.find (i->cell_id ());
|
||||
if (icell == cell2cell.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto icat = cat2cat.find (i->category_id ());
|
||||
if (icat == cat2cat.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// build a cache of value vs. value
|
||||
auto vmap = value_map.find (std::make_pair (icell->second, icat->second));
|
||||
if (vmap == value_map.end ()) {
|
||||
vmap = value_map.insert (std::make_pair (std::make_pair (icell->second, icat->second), ValueMapEntry ())).first;
|
||||
vmap->second.build (other, icell->second, icat->second, tag2tag, rev_tag2tag);
|
||||
}
|
||||
|
||||
// find a value in the reference DB
|
||||
const rdb::Item *other = vmap->second.find (*i);
|
||||
if (other) {
|
||||
|
||||
// actually transfer the attributes here
|
||||
|
||||
i->set_comment (other->comment ());
|
||||
// TODO: this has some optimization potential in terms of performance ...
|
||||
i->set_image_str (other->image_str ());
|
||||
i->set_tag_str (other->tag_str ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Database::scan_layout (const db::Layout &layout, db::cell_index_type cell_index, const std::vector<std::pair<unsigned int, std::string> > &layers_and_descriptions, bool flat)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -506,10 +506,7 @@ public:
|
|||
return type_index_of<C> ();
|
||||
}
|
||||
|
||||
bool compare (const ValueBase *other) const
|
||||
{
|
||||
return m_value < static_cast<const Value<C> *> (other)->m_value;
|
||||
}
|
||||
bool compare (const ValueBase *other) const;
|
||||
|
||||
bool is_shape () const;
|
||||
|
||||
|
|
@ -679,6 +676,19 @@ public:
|
|||
*/
|
||||
Values &operator= (const Values &d);
|
||||
|
||||
/**
|
||||
* @brief Compare two value sets (less operator)
|
||||
*
|
||||
* This compare function will use the tag mapping provided by tag map ("this" tag id to "other" tag id).
|
||||
* Values with tags not listed in the tag map will not be compared.
|
||||
* Untagged values (tag_id 0) will be compared always.
|
||||
*
|
||||
* "rev_tag_map" needs to be the reverse of "tag_map".
|
||||
*
|
||||
* The order of the values matters.
|
||||
*/
|
||||
bool compare (const Values &other, const std::map<id_type, id_type> &tag_map, const std::map<id_type, id_type> &rev_tag_map) const;
|
||||
|
||||
/**
|
||||
* @brief The const iterator (begin)
|
||||
*/
|
||||
|
|
@ -739,6 +749,14 @@ public:
|
|||
m_values.swap (other.m_values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the values
|
||||
*/
|
||||
void clear ()
|
||||
{
|
||||
m_values.clear ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert the values collection to a string
|
||||
*/
|
||||
|
|
@ -993,6 +1011,26 @@ public:
|
|||
*/
|
||||
void set_image_str (const std::string &s);
|
||||
|
||||
/**
|
||||
* @brief Gets the item comment
|
||||
*
|
||||
* The comment string is an arbitrary string attached to the item.
|
||||
*/
|
||||
const std::string &comment () const
|
||||
{
|
||||
return m_comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the item comment
|
||||
*
|
||||
* The comment string is an arbitrary string attached to the item.
|
||||
*/
|
||||
void set_comment (const std::string &s)
|
||||
{
|
||||
m_comment = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the database reference
|
||||
*/
|
||||
|
|
@ -1017,6 +1055,7 @@ private:
|
|||
id_type m_cell_id;
|
||||
id_type m_category_id;
|
||||
size_t m_multiplicity;
|
||||
std::string m_comment;
|
||||
bool m_visited;
|
||||
std::vector <bool> m_tag_ids;
|
||||
Database *mp_database;
|
||||
|
|
@ -1441,7 +1480,7 @@ public:
|
|||
*
|
||||
* This method is provided for persistency application only. It should not be used otherwise.
|
||||
*/
|
||||
Cell (id_type id, const std::string &name, const std::string &variant);
|
||||
Cell (id_type id, const std::string &name, const std::string &variant, const std::string &layout_name);
|
||||
|
||||
/**
|
||||
* @brief Cell destructor
|
||||
|
|
@ -1467,7 +1506,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Get the cell name
|
||||
* @brief Gets the cell name
|
||||
*/
|
||||
const std::string &name () const
|
||||
{
|
||||
|
|
@ -1475,7 +1514,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Set the name string (setter)
|
||||
* @brief Sets the name string
|
||||
*
|
||||
* This method must not be used for items in the database to keep the database consistent.
|
||||
*/
|
||||
|
|
@ -1485,7 +1524,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Get the variant id
|
||||
* @brief Gets the variant id
|
||||
*/
|
||||
const std::string &variant () const
|
||||
{
|
||||
|
|
@ -1493,7 +1532,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Set the variant string (setter)
|
||||
* @brief Sets the variant string
|
||||
*
|
||||
* This method must not be used for items in the database to keep the database consistent.
|
||||
*/
|
||||
|
|
@ -1502,6 +1541,24 @@ public:
|
|||
m_variant = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the layout cell name
|
||||
*/
|
||||
const std::string &layout_name () const
|
||||
{
|
||||
return m_layout_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the layout cell string
|
||||
*
|
||||
* This method must not be used for items in the database to keep the database consistent.
|
||||
*/
|
||||
void set_layout_name (const std::string &s)
|
||||
{
|
||||
m_layout_name = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the qualified name (name plus optionally the variant id separated by a colon)
|
||||
*/
|
||||
|
|
@ -1579,6 +1636,7 @@ private:
|
|||
id_type m_id;
|
||||
std::string m_name;
|
||||
std::string m_variant;
|
||||
std::string m_layout_name;
|
||||
size_t m_num_items;
|
||||
size_t m_num_items_visited;
|
||||
References m_references;
|
||||
|
|
@ -2182,7 +2240,7 @@ public:
|
|||
*/
|
||||
Cell *create_cell (const std::string &name)
|
||||
{
|
||||
return create_cell (name, std::string ());
|
||||
return create_cell (name, std::string (), std::string ());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2191,8 +2249,11 @@ public:
|
|||
* A cell with name name/variant combination must not exist already.
|
||||
* If the variant string is empty, this method behaves the same as the
|
||||
* method without variant.
|
||||
*
|
||||
* "layout_name" is the name of the cell in the layout. If empty, the layout
|
||||
* cell is assumed to be identical to "name".
|
||||
*/
|
||||
Cell *create_cell (const std::string &name, const std::string &variant);
|
||||
Cell *create_cell (const std::string &name, const std::string &variant, const std::string &layout_name);
|
||||
|
||||
/**
|
||||
* @brief Get all variants registered for a given cell name (not qname!)
|
||||
|
|
@ -2286,6 +2347,11 @@ public:
|
|||
*/
|
||||
void remove_item_tag (const Item *item, id_type tag);
|
||||
|
||||
/**
|
||||
* @brief Sets the comment string of the item
|
||||
*/
|
||||
void set_item_comment (const Item *item, const std::string &comment);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Set the image of an item
|
||||
|
|
@ -2378,12 +2444,29 @@ public:
|
|||
*/
|
||||
void save (const std::string &filename);
|
||||
|
||||
/**
|
||||
* @brief Write the database to a file
|
||||
*
|
||||
* This function is like "save", but does not update the file name attribute.
|
||||
*/
|
||||
void write (const std::string &filename);
|
||||
|
||||
/**
|
||||
* @brief Load the database from a file
|
||||
*
|
||||
* @brief This clears the existing database.
|
||||
* Note: This clears the existing database.
|
||||
* The argument intentionally is a copy, so we can call
|
||||
* "load (this->filename ())" for reloading.
|
||||
*/
|
||||
void load (const std::string &filename);
|
||||
void load (std::string filename);
|
||||
|
||||
/**
|
||||
* @brief Applies the attributes from a different database
|
||||
*
|
||||
* Attributes are waived flags, images etc.
|
||||
* The attributes are applied to markers with identical value(s), category and cell context.
|
||||
*/
|
||||
void apply (const rdb::Database &other);
|
||||
|
||||
/**
|
||||
* @brief Scans a layout into this RDB
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ make_rdb_structure (rdb::Database *rdb)
|
|||
tl::make_element_with_parent_ref<rdb::Cell, rdb::Cells::const_iterator, rdb::Cells> (&rdb::Cells::begin, &rdb::Cells::end, &rdb::Cells::import_cell, "cell",
|
||||
tl::make_member<std::string, rdb::Cell> (&rdb::Cell::name, &rdb::Cell::set_name, "name") +
|
||||
tl::make_member<std::string, rdb::Cell> (&rdb::Cell::variant, &rdb::Cell::set_variant, "variant") +
|
||||
tl::make_element_with_parent_ref<rdb::References, rdb::Cell> (&rdb::Cell::references, &rdb::Cell::import_references, "references",
|
||||
tl::make_member<std::string, rdb::Cell> (&rdb::Cell::layout_name, &rdb::Cell::set_layout_name, "layout-name") +
|
||||
tl::make_element_with_parent_ref<rdb::References, rdb::Cell> (&rdb::Cell::references, &rdb::Cell::import_references, "references",
|
||||
tl::make_element_with_parent_ref<rdb::Reference, rdb::References::const_iterator, rdb::References> (&rdb::References::begin, &rdb::References::end, &rdb::References::insert, "ref",
|
||||
tl::make_member<std::string, rdb::Reference> (&rdb::Reference::parent_cell_qname, &rdb::Reference::set_parent_cell_qname, "parent") +
|
||||
tl::make_member<std::string, rdb::Reference> (&rdb::Reference::trans_str, &rdb::Reference::set_trans_str, "trans")
|
||||
|
|
@ -106,6 +107,7 @@ make_rdb_structure (rdb::Database *rdb)
|
|||
tl::make_member<std::string, rdb::Item> (&rdb::Item::cell_qname, &rdb::Item::set_cell_qname, "cell") +
|
||||
tl::make_member<bool, rdb::Item> (&rdb::Item::visited, &rdb::Item::set_visited, "visited") +
|
||||
tl::make_member<size_t, rdb::Item> (&rdb::Item::multiplicity, &rdb::Item::set_multiplicity, "multiplicity") +
|
||||
tl::make_member<std::string, rdb::Item> (&rdb::Item::comment, &rdb::Item::set_comment, "comment") +
|
||||
tl::make_member<std::string, rdb::Item> (&rdb::Item::image_str, &rdb::Item::set_image_str, "image") +
|
||||
tl::make_element<rdb::Values, rdb::Item> (&rdb::Item::values, &rdb::Item::set_values, "values",
|
||||
tl::make_member<rdb::ValueWrapper, rdb::Values::const_iterator, rdb::Values> (&rdb::Values::begin, &rdb::Values::end, &rdb::Values::add, "value", ValueConverter (rdb))
|
||||
|
|
@ -116,17 +118,25 @@ make_rdb_structure (rdb::Database *rdb)
|
|||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Implementation of rdb::Database::save
|
||||
// Implementation of rdb::Database::save and write
|
||||
// TODO: move this somewhere else - with generalized functionality
|
||||
|
||||
void
|
||||
rdb::Database::save (const std::string &fn)
|
||||
{
|
||||
tl::OutputStream os (fn, tl::OutputStream::OM_Auto);
|
||||
make_rdb_structure (this).write (os, *this);
|
||||
write (fn);
|
||||
set_filename (fn);
|
||||
}
|
||||
|
||||
tl::log << "Saved RDB to " << fn;
|
||||
void
|
||||
rdb::Database::write (const std::string &fn)
|
||||
{
|
||||
tl::OutputStream os (fn, tl::OutputStream::OM_Auto);
|
||||
make_rdb_structure (this).write (os, *this);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << "Saved RDB to " << fn;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -174,10 +174,28 @@ public:
|
|||
const rdb::Cell *cell_for_id (const db::Layout *layout, db::cell_index_type ci)
|
||||
{
|
||||
tl_assert (layout != 0);
|
||||
|
||||
std::string cn = layout->cell_name (ci);
|
||||
const rdb::Cell *rdb_cell = mp_rdb->cell_by_qname (cn);
|
||||
std::string layout_cn = cn;
|
||||
std::string qname = cn;
|
||||
std::string var;
|
||||
|
||||
// resolve references to original cells in deep mode and determine variant
|
||||
if (layout->builder ()) {
|
||||
const db::Layout *source = layout->builder ()->source ().layout ();
|
||||
if (source) {
|
||||
const std::pair<db::cell_index_type, std::string> &vs = layout->builder ()->variant_of_source (ci);
|
||||
if (! vs.second.empty () && source->is_valid_cell_index (vs.first)) {
|
||||
var = vs.second;
|
||||
cn = source->cell_name (vs.first);
|
||||
qname = cn + ":" + var;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rdb::Cell *rdb_cell = mp_rdb->cell_by_qname (qname);
|
||||
if (! rdb_cell) {
|
||||
return mp_rdb->create_cell (cn);
|
||||
return mp_rdb->create_cell (cn, var, layout_cn);
|
||||
} else {
|
||||
return rdb_cell;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,15 +69,15 @@ void run_rve_test (tl::TestBase *_this, const std::string &fn_rve, const std::st
|
|||
|
||||
TEST(1)
|
||||
{
|
||||
run_rve_test (_this, "rve1.db", "rve1_au.txt");
|
||||
run_rve_test (_this, "rve1.db", "rve1_au_2.txt");
|
||||
}
|
||||
|
||||
TEST(2)
|
||||
{
|
||||
run_rve_test (_this, "rve2.db", "rve2_au.txt");
|
||||
run_rve_test (_this, "rve2.db", "rve2_au_2.txt");
|
||||
}
|
||||
|
||||
TEST(3)
|
||||
{
|
||||
run_rve_test (_this, "rve3.db", "rve3_au.txt");
|
||||
run_rve_test (_this, "rve3.db", "rve3_au_2.txt");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -521,11 +521,11 @@ TEST(6)
|
|||
EXPECT_EQ (db.variants ("c1")[0], c1->id ());
|
||||
EXPECT_EQ (db.variants ("c1")[1], c1a->id ());
|
||||
|
||||
rdb::Cell *c1b = db.create_cell ("c1", "var");
|
||||
rdb::Cell *c1b = db.create_cell ("c1", "var", std::string ());
|
||||
EXPECT_EQ (c1b->qname (), "c1:var")
|
||||
EXPECT_EQ (db.variants ("c1").size (), size_t (3));
|
||||
|
||||
rdb::Cell *c2 = db.create_cell ("c2", "1027");
|
||||
rdb::Cell *c2 = db.create_cell ("c2", "1027", std::string ());
|
||||
EXPECT_EQ (c2->qname (), "c2:1027");
|
||||
EXPECT_EQ (db.variants ("c2").size (), size_t (1));
|
||||
|
||||
|
|
@ -534,8 +534,9 @@ TEST(6)
|
|||
EXPECT_EQ (c2->qname (), "c2:1027")
|
||||
EXPECT_EQ (db.variants ("c2").size (), size_t (2));
|
||||
|
||||
rdb::Cell *c2b = db.create_cell ("c2", "var");
|
||||
rdb::Cell *c2b = db.create_cell ("c2", "var", "c2$1");
|
||||
EXPECT_EQ (c2b->qname (), "c2:var")
|
||||
EXPECT_EQ (c2b->layout_name (), "c2$1")
|
||||
|
||||
rdb::Cell *c2c = db.create_cell ("c2");
|
||||
EXPECT_EQ (c2c->qname (), "c2:2");
|
||||
|
|
@ -598,3 +599,226 @@ TEST(7)
|
|||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
TEST(8_ApplyBasicEmptyValue)
|
||||
{
|
||||
rdb::Database db1;
|
||||
rdb::Category *cat1 = db1.create_category ("cat_name");
|
||||
rdb::Cell *c1 = db1.create_cell ("cell");
|
||||
rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ());
|
||||
|
||||
rdb::Database db2;
|
||||
db2.create_category ("dummy_cat");
|
||||
rdb::Category *cat2 = db2.create_category ("cat_name");
|
||||
db2.create_cell ("dummy_cell");
|
||||
rdb::Cell *c2 = db2.create_cell ("cell");
|
||||
rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ());
|
||||
|
||||
rdb::id_type tag2 = db2.tags ().tag ("tag2").id ();
|
||||
i2->add_tag (tag2);
|
||||
|
||||
EXPECT_EQ (i2->tag_str (), "tag2");
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// empty value apply
|
||||
db1.apply (db2);
|
||||
|
||||
EXPECT_EQ (i1->tag_str (), "tag2");
|
||||
}
|
||||
|
||||
TEST(9_ApplyBasicSomeValue)
|
||||
{
|
||||
rdb::Database db1;
|
||||
rdb::Category *cat1 = db1.create_category ("cat_name");
|
||||
rdb::Cell *c1 = db1.create_cell ("cell");
|
||||
rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ());
|
||||
i1->add_value (std::string ("abc"));
|
||||
|
||||
rdb::Database db2;
|
||||
db2.create_category ("dummy_cat");
|
||||
rdb::Category *cat2 = db2.create_category ("cat_name");
|
||||
db2.create_cell ("dummy_cell");
|
||||
rdb::Cell *c2 = db2.create_cell ("cell");
|
||||
rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ());
|
||||
|
||||
db2.tags ().tag ("dummy_tag");
|
||||
rdb::id_type tag2 = db2.tags ().tag ("tag2").id ();
|
||||
i2->add_tag (tag2);
|
||||
|
||||
EXPECT_EQ (i2->tag_str (), "tag2");
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// empty value apply
|
||||
db1.apply (db2);
|
||||
|
||||
// not applied (different value)
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// incorrect value
|
||||
i2->add_value (17);
|
||||
|
||||
db1.apply (db2);
|
||||
|
||||
// still not applied
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// correct value
|
||||
i2->values ().clear ();
|
||||
i2->add_value (std::string ("abc"));
|
||||
|
||||
db1.apply (db2);
|
||||
|
||||
// now, the tag is applied
|
||||
EXPECT_EQ (i1->tag_str (), "tag2");
|
||||
|
||||
// too many values
|
||||
i1->remove_tags ();
|
||||
i2->add_value (17);
|
||||
|
||||
db1.apply (db2);
|
||||
|
||||
// not applied
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
}
|
||||
|
||||
TEST(10_ApplyTaggedValue)
|
||||
{
|
||||
rdb::Database db1;
|
||||
rdb::Category *cat1 = db1.create_category ("cat_name");
|
||||
rdb::Cell *c1 = db1.create_cell ("cell");
|
||||
rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ());
|
||||
rdb::id_type vtag11 = db1.tags ().tag ("vtag1").id ();
|
||||
rdb::id_type vtag12 = db1.tags ().tag ("vtag2").id ();
|
||||
i1->add_value (std::string ("abc"));
|
||||
|
||||
rdb::Database db2;
|
||||
db2.create_category ("dummy_cat");
|
||||
rdb::Category *cat2 = db2.create_category ("cat_name");
|
||||
db2.create_cell ("dummy_cell");
|
||||
rdb::Cell *c2 = db2.create_cell ("cell");
|
||||
rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ());
|
||||
db2.tags ().tag ("dummy_tag");
|
||||
|
||||
rdb::id_type tag2 = db2.tags ().tag ("tag2").id ();
|
||||
rdb::id_type vtag21 = db2.tags ().tag ("vtag1").id ();
|
||||
i2->add_tag (tag2);
|
||||
i2->add_value (std::string ("abc"), vtag21);
|
||||
|
||||
// empty tag vs. vtag1
|
||||
db1.apply (db2);
|
||||
|
||||
// not applied (empty tag vs. tagged)
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// vtag2 vs. vtag1
|
||||
i1->values ().clear ();
|
||||
i1->add_value (std::string ("abc"), vtag12);
|
||||
|
||||
db1.apply (db2);
|
||||
|
||||
// not applied (different tags)
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// vtag1 vs. vtag1
|
||||
i1->values ().clear ();
|
||||
i1->add_value (std::string ("abc"), vtag11);
|
||||
|
||||
db1.apply (db2);
|
||||
|
||||
// this time it is applied (same tag)
|
||||
EXPECT_EQ (i1->tag_str (), "tag2");
|
||||
}
|
||||
|
||||
TEST(11_ApplyWrongCat)
|
||||
{
|
||||
rdb::Database db1;
|
||||
rdb::Category *cat1 = db1.create_category ("cat_name");
|
||||
rdb::Cell *c1 = db1.create_cell ("cell");
|
||||
rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ());
|
||||
|
||||
rdb::Database db2;
|
||||
db2.create_category ("dummy_cat");
|
||||
rdb::Category *cat2 = db2.create_category ("xcat_name");
|
||||
db2.create_cell ("dummy_cell");
|
||||
rdb::Cell *c2 = db2.create_cell ("cell");
|
||||
rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ());
|
||||
|
||||
rdb::id_type tag2 = db2.tags ().tag ("tag2").id ();
|
||||
i2->add_tag (tag2);
|
||||
|
||||
EXPECT_EQ (i2->tag_str (), "tag2");
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// empty value apply
|
||||
db1.apply (db2);
|
||||
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
}
|
||||
|
||||
TEST(12_ApplyWrongCell)
|
||||
{
|
||||
rdb::Database db1;
|
||||
rdb::Category *cat1 = db1.create_category ("cat_name");
|
||||
rdb::Cell *c1 = db1.create_cell ("cell");
|
||||
rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ());
|
||||
|
||||
rdb::Database db2;
|
||||
db2.create_category ("dummy_cat");
|
||||
rdb::Category *cat2 = db2.create_category ("cat_name");
|
||||
db2.create_cell ("dummy_cell");
|
||||
rdb::Cell *c2 = db2.create_cell ("xcell");
|
||||
rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ());
|
||||
|
||||
rdb::id_type tag2 = db2.tags ().tag ("tag2").id ();
|
||||
i2->add_tag (tag2);
|
||||
|
||||
EXPECT_EQ (i2->tag_str (), "tag2");
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// empty value apply
|
||||
db1.apply (db2);
|
||||
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
}
|
||||
|
||||
TEST(13_ApplyIgnoreUnknownTag)
|
||||
{
|
||||
rdb::Database db1;
|
||||
rdb::Category *cat1 = db1.create_category ("cat_name");
|
||||
rdb::Cell *c1 = db1.create_cell ("cell");
|
||||
rdb::Item *i1 = db1.create_item (c1->id (), cat1->id ());
|
||||
rdb::id_type vtag11 = db1.tags ().tag ("vtag1").id ();
|
||||
i1->add_value (std::string ("abc"), vtag11);
|
||||
|
||||
rdb::Database db2;
|
||||
db2.create_category ("dummy_cat");
|
||||
rdb::Category *cat2 = db2.create_category ("cat_name");
|
||||
db2.create_cell ("dummy_cell");
|
||||
rdb::Cell *c2 = db2.create_cell ("cell");
|
||||
rdb::Item *i2 = db2.create_item (c2->id (), cat2->id ());
|
||||
db2.tags ().tag ("dummy_tag");
|
||||
|
||||
rdb::id_type tag2 = db2.tags ().tag ("tag2").id ();
|
||||
rdb::id_type vtag21 = db2.tags ().tag ("vtag1").id ();
|
||||
rdb::id_type vtag22 = db2.tags ().tag ("vtag2").id ();
|
||||
i2->add_tag (tag2);
|
||||
|
||||
// same tags, different values
|
||||
i2->add_value (std::string ("xyz"), vtag21);
|
||||
|
||||
db1.apply (db2);
|
||||
|
||||
// not applied
|
||||
EXPECT_EQ (i1->tag_str (), "");
|
||||
|
||||
// different tags without mapping
|
||||
i2->values ().clear ();
|
||||
i2->add_value (std::string ("xyz"), vtag22);
|
||||
|
||||
// values with incompatible tags are ignored -> tag2 is applied
|
||||
db1.apply (db2);
|
||||
|
||||
EXPECT_EQ (i1->tag_str (), "tag2");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,14 +145,14 @@ ExpressionParserContext::where () const
|
|||
// ----------------------------------------------------------------------------
|
||||
// Utilities for evaluation
|
||||
|
||||
static double to_double (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static double to_double (const ExpressionParserContext &context, const tl::Variant &v, unsigned int narg)
|
||||
{
|
||||
if (v.can_convert_to_double ()) {
|
||||
return v.to_double ();
|
||||
} else if (v.is_list ()) {
|
||||
return v.get_list ().size ();
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Double precision floating point value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Double precision floating point value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,50 +162,50 @@ static double to_double (const ExpressionParserContext &context, const std::vect
|
|||
throw EvalError (tl::to_string (tr ("Function expects a single numeric argument")), context);
|
||||
}
|
||||
|
||||
return to_double (context, v [0]);
|
||||
return to_double (context, v [0], 0);
|
||||
}
|
||||
|
||||
static long to_long (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static long to_long (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_long ()) {
|
||||
return v.to_long ();
|
||||
} else if (v.is_list ()) {
|
||||
return long (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long to_ulong (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static unsigned long to_ulong (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_ulong ()) {
|
||||
return v.to_ulong ();
|
||||
} else if (v.is_list ()) {
|
||||
return (unsigned long) (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
static long long to_longlong (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static long long to_longlong (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_longlong ()) {
|
||||
return v.to_longlong ();
|
||||
} else if (v.is_list ()) {
|
||||
return long (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long long to_ulonglong (const ExpressionParserContext &context, const tl::Variant &v)
|
||||
static unsigned long long to_ulonglong (const ExpressionParserContext &context, const tl::Variant &v, int narg)
|
||||
{
|
||||
if (v.can_convert_to_ulonglong ()) {
|
||||
return v.to_ulong ();
|
||||
} else if (v.is_list ()) {
|
||||
return (unsigned long long) (v.get_list ().size ());
|
||||
} else {
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected")), context);
|
||||
throw EvalError (tl::to_string (tr ("Unsigned integer value expected for argument #")) + tl::to_string (narg + 1), context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1089,13 +1089,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_longlong ()) {
|
||||
v.set (tl::Variant (v->to_longlong () << to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_longlong () << to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong ()) {
|
||||
v.set (tl::Variant (v->to_ulonglong () << to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulonglong () << to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong ()) {
|
||||
v.set (tl::Variant (v->to_ulong () << to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulong () << to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) << to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) << to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1145,13 +1145,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_longlong ()) {
|
||||
v.set (tl::Variant (v->to_longlong () >> to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_longlong () >> to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong ()) {
|
||||
v.set (tl::Variant (v->to_ulonglong () >> to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulonglong () >> to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong ()) {
|
||||
v.set (tl::Variant (v->to_ulong () >> to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (v->to_ulong () >> to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) >> to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) >> to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1203,17 +1203,17 @@ public:
|
|||
} else if (v->is_a_string () || b->is_a_string ()) {
|
||||
v.set (tl::Variant (std::string (v->to_string ()) + b->to_string ()));
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
v.set (tl::Variant (to_double (m_context, *v) + to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) + to_double (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) + to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) + to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) + to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) + to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) + to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) + to_ulong (m_context, *b, 1)));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
v.set (tl::Variant (to_long (m_context, *v) + to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) + to_long (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_double (m_context, *v) + to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) + to_double (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1263,17 +1263,17 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
v.set (tl::Variant (to_double (m_context, *v) - to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) - to_double (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) - to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) - to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) - to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) - to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) - to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) - to_ulong (m_context, *b, 1)));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
v.set (tl::Variant (to_long (m_context, *v) - to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) - to_long (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_double (m_context, *v) - to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) - to_double (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1324,7 +1324,7 @@ public:
|
|||
|
||||
} else if (v->is_a_string ()) {
|
||||
|
||||
long x = to_long (m_context, *b);
|
||||
long x = to_long (m_context, *b, 1);
|
||||
if (x < 0) {
|
||||
throw EvalError (tl::to_string (tr ("Numeric argument of '*' operator with string must be positive")), m_context);
|
||||
}
|
||||
|
|
@ -1339,7 +1339,7 @@ public:
|
|||
|
||||
} else if (b->is_a_string ()) {
|
||||
|
||||
long x = to_long (m_context, *v);
|
||||
long x = to_long (m_context, *v, 0);
|
||||
if (x < 0) {
|
||||
throw EvalError (tl::to_string (tr ("Numeric argument of '*' operator with string must be positive")), m_context);
|
||||
}
|
||||
|
|
@ -1353,17 +1353,17 @@ public:
|
|||
v.set (tl::Variant (s));
|
||||
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
v.set (tl::Variant (to_double (m_context, *v) * to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) * to_double (m_context, *b, 1)));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) * to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) * to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) * to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) * to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) * to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) * to_ulong (m_context, *b, 1)));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
v.set (tl::Variant (to_long (m_context, *v) * to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) * to_long (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_double (m_context, *v) * to_double (m_context, *b)));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) * to_double (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1413,41 +1413,41 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_double () || b->is_double ()) {
|
||||
double d = to_double (m_context, *b);
|
||||
double d = to_double (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_double (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) / d));
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
unsigned long long d = to_ulonglong (m_context, *b);
|
||||
unsigned long long d = to_ulonglong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) / d));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
long long d = to_longlong (m_context, *b);
|
||||
long long d = to_longlong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) / d));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
unsigned long d = to_ulong (m_context, *b);
|
||||
unsigned long d = to_ulong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) / d));
|
||||
} else if (v->is_long () || b->is_long ()) {
|
||||
long d = to_long (m_context, *b);
|
||||
long d = to_long (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_long (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) / d));
|
||||
} else {
|
||||
double d = to_double (m_context, *b);
|
||||
double d = to_double (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Division by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_double (m_context, *v) / d));
|
||||
v.set (tl::Variant (to_double (m_context, *v, 0) / d));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1497,29 +1497,29 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
unsigned long long d = to_ulonglong (m_context, *b);
|
||||
unsigned long long d = to_ulonglong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) % d));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
long long d = to_longlong (m_context, *b);
|
||||
long long d = to_longlong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) % d));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
unsigned long d = to_ulong (m_context, *b);
|
||||
unsigned long d = to_ulong (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) % d));
|
||||
} else {
|
||||
long d = to_long (m_context, *b);
|
||||
long d = to_long (m_context, *b, 1);
|
||||
if (d == 0) {
|
||||
throw EvalError (tl::to_string (tr ("Modulo by zero")), m_context);
|
||||
}
|
||||
v.set (tl::Variant (to_long (m_context, *v) % d));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) % d));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1569,13 +1569,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) & to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) & to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) & to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) & to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) & to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) & to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) & to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) & to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1625,13 +1625,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) | to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) | to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) | to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) | to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) | to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) | to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) | to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) | to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1681,13 +1681,13 @@ public:
|
|||
v.swap (o);
|
||||
|
||||
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v) ^ to_ulonglong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulonglong (m_context, *v, 0) ^ to_ulonglong (m_context, *b, 1)));
|
||||
} else if (v->is_longlong () || b->is_longlong ()) {
|
||||
v.set (tl::Variant (to_longlong (m_context, *v) ^ to_longlong (m_context, *b)));
|
||||
v.set (tl::Variant (to_longlong (m_context, *v, 0) ^ to_longlong (m_context, *b, 1)));
|
||||
} else if (v->is_ulong () || b->is_ulong ()) {
|
||||
v.set (tl::Variant (to_ulong (m_context, *v) ^ to_ulong (m_context, *b)));
|
||||
v.set (tl::Variant (to_ulong (m_context, *v, 0) ^ to_ulong (m_context, *b, 1)));
|
||||
} else {
|
||||
v.set (tl::Variant (to_long (m_context, *v) ^ to_long (m_context, *b)));
|
||||
v.set (tl::Variant (to_long (m_context, *v, 0) ^ to_long (m_context, *b, 1)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1826,7 +1826,7 @@ public:
|
|||
} else if (v->is_ulonglong ()) {
|
||||
v.set (-(long long)(v->to_ulonglong ()));
|
||||
} else {
|
||||
v.set (-to_double (m_context, *v));
|
||||
v.set (-to_double (m_context, *v, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1881,7 +1881,7 @@ public:
|
|||
} else if (v->is_ulonglong ()) {
|
||||
v.set (~v->to_ulonglong ());
|
||||
} else {
|
||||
v.set (~to_long (m_context, *v));
|
||||
v.set (~to_long (m_context, *v, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -2388,7 +2388,7 @@ abs_f (const ExpressionParserContext &context, tl::Variant &out, const std::vect
|
|||
} else if (v[0].is_double ()) {
|
||||
out = fabs (v[0].to_double ());
|
||||
} else {
|
||||
out = labs (to_long (context, v[0]));
|
||||
out = labs (to_long (context, v[0], 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2463,7 +2463,7 @@ pow_f (const ExpressionParserContext &context, tl::Variant &out, const std::vect
|
|||
throw EvalError (tl::to_string (tr ("'pow' function expects exactly two arguments")), context);
|
||||
}
|
||||
|
||||
out = pow (to_double (context, vv [0]), to_double (context, vv [1]));
|
||||
out = pow (to_double (context, vv [0], 0), to_double (context, vv [1], 1));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2473,7 +2473,7 @@ atan2_f (const ExpressionParserContext &context, tl::Variant &out, const std::ve
|
|||
throw EvalError (tl::to_string (tr ("'atan2' function expects exactly two arguments")), context);
|
||||
}
|
||||
|
||||
out = atan2 (to_double (context, vv [0]), to_double (context, vv [1]));
|
||||
out = atan2 (to_double (context, vv [0], 0), to_double (context, vv [1], 1));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2690,10 +2690,10 @@ substr_f (const ExpressionParserContext &context, tl::Variant &out, const std::v
|
|||
|
||||
long len = -1;
|
||||
if (vv.size () > 2) {
|
||||
len = std::max (long (0), to_long (context, vv [2]));
|
||||
len = std::max (long (0), to_long (context, vv [2], 2));
|
||||
}
|
||||
|
||||
long l = to_long (context, vv [1]);
|
||||
long l = to_long (context, vv [1], 1);
|
||||
if (l < 0) {
|
||||
l = long (s.size ()) + l;
|
||||
if (l < 0) {
|
||||
|
|
@ -2713,6 +2713,26 @@ substr_f (const ExpressionParserContext &context, tl::Variant &out, const std::v
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
upcase_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
||||
{
|
||||
if (vv.size () != 1) {
|
||||
throw EvalError (tl::to_string (tr ("'upcase' function expects one argument")), context);
|
||||
}
|
||||
|
||||
out = tl::to_upper_case (vv [0].to_string ());
|
||||
}
|
||||
|
||||
static void
|
||||
downcase_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
||||
{
|
||||
if (vv.size () != 1) {
|
||||
throw EvalError (tl::to_string (tr ("'upcase' function expects one argument")), context);
|
||||
}
|
||||
|
||||
out = tl::to_lower_case (vv [0].to_string ());
|
||||
}
|
||||
|
||||
static void
|
||||
join_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
||||
{
|
||||
|
|
@ -2752,7 +2772,7 @@ item_f (const ExpressionParserContext &context, tl::Variant &out, const std::vec
|
|||
throw EvalError (tl::to_string (tr ("First argument of 'item' function must be a list")), context);
|
||||
}
|
||||
|
||||
long index = to_long (context, vv [1]);
|
||||
long index = to_long (context, vv [1], 1);
|
||||
if (index < 0 || index >= long (vv [0].end () - vv [0].begin ())) {
|
||||
out = tl::Variant ();
|
||||
} else {
|
||||
|
|
@ -3042,6 +3062,8 @@ static EvalStaticFunction f55 ("file_exists", &file_exists_f);
|
|||
static EvalStaticFunction f56 ("is_dir", &is_dir_f);
|
||||
static EvalStaticFunction f57 ("combine", &combine_f);
|
||||
static EvalStaticFunction f58 ("abs", &abs_f);
|
||||
static EvalStaticFunction f59 ("upcase", &upcase_f);
|
||||
static EvalStaticFunction f60 ("downcase", &downcase_f);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Implementation of a constant wrapper
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "tlDeferredExecution.h"
|
||||
#include "tlObject.h"
|
||||
#include "tlTimer.h"
|
||||
#include "tlSleep.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
|
@ -447,9 +448,18 @@ InputHttpStreamPrivateData::read (char *b, size_t n)
|
|||
issue_request (QUrl (tl::to_qstring (m_url)));
|
||||
}
|
||||
|
||||
tl::Clock start_time = tl::Clock::current ();
|
||||
while (mp_reply == 0 && (m_timeout <= 0.0 || (tl::Clock::current() - start_time).seconds () < m_timeout)) {
|
||||
const unsigned long tick_ms = 10;
|
||||
double time_waited = 0.0;
|
||||
|
||||
while (mp_reply == 0 && (m_timeout <= 0.0 || time_waited < m_timeout)) {
|
||||
|
||||
mp_stream->tick ();
|
||||
|
||||
// NOTE: as tick() includes waiting for the password dialog, we must not include
|
||||
// the time spent there.
|
||||
tl::msleep (tick_ms);
|
||||
time_waited += tick_ms * 1e-3;
|
||||
|
||||
}
|
||||
|
||||
if (! mp_reply) {
|
||||
|
|
|
|||
|
|
@ -784,6 +784,10 @@ TEST(6)
|
|||
EXPECT_EQ (v.to_string (), std::string ("0"));
|
||||
v = e.parse ("rfind('abcabc','x')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("nil"));
|
||||
v = e.parse ("upcase('abcABC')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("ABCABC"));
|
||||
v = e.parse ("downcase('abcABC')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("abcabc"));
|
||||
v = e.parse ("len('abcabc')").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("6"));
|
||||
v = e.parse ("len([])").execute ();
|
||||
|
|
@ -859,6 +863,14 @@ TEST(6)
|
|||
msg = ex.msg();
|
||||
}
|
||||
EXPECT_EQ (msg, std::string ("My error"));
|
||||
// argument index in error messages
|
||||
msg.clear ();
|
||||
try {
|
||||
v = e.parse ("substr('abcabc',2,'xyz')").execute ();
|
||||
} catch (tl::Exception &ex) {
|
||||
msg = ex.msg();
|
||||
}
|
||||
EXPECT_EQ (msg, std::string ("Integer value expected for argument #3 at position 0 (substr('abcabc',2,'x..)"));
|
||||
}
|
||||
|
||||
// compare ops
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,14 @@
|
|||
* Testing recursive call detection
|
||||
|
||||
.subckt c1 a b
|
||||
x1 a b c2
|
||||
.end
|
||||
|
||||
.subckt c2 a b
|
||||
x1 a b c1
|
||||
.ends
|
||||
|
||||
xtop vdd vss c2
|
||||
|
||||
.end
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
* Test: dismiss empty top level circuit
|
||||
|
||||
.subckt top a b
|
||||
m1 a b a b nmos
|
||||
.ends
|
||||
|
||||
* this triggered generation of a top level circuit
|
||||
.param p1 17
|
||||
|
||||
.end
|
||||
|
||||
|
|
@ -27,4 +27,6 @@ l1.drc(angle < 0.0).output(111, 0)
|
|||
l1.drc(primary.angle > 0.0).output(112, 0)
|
||||
l1.drc(primary.edges.angle == 90).output(113, 0)
|
||||
l1.drc((angle == 0.0) + (angle == 90)).output(114, 0)
|
||||
l1.drc(angle == 45).output(115, 0)
|
||||
l1.drc(angle(absolute) == 45).output(116, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ l1.drc(corners(as_boxes) == -90).output(102, 0) # outer corners
|
|||
l1.drc(corners(as_boxes) == 90).output(103, 0) # inner corners
|
||||
l1.drc(corners(as_boxes) <= -90).output(104, 0)
|
||||
l1.drc(corners(as_edge_pairs) == 90).output(105, 0)
|
||||
l1.drc(corners(as_boxes, absolute) == 90).output(106, 0) # inner and outer corners
|
||||
l1.drc(corners(as_boxes) != 90).output(107, 0) # not inner corners
|
||||
|
||||
l1.drc(middle).output(110, 0)
|
||||
l1.drc(middle(as_dots)).output(111, 0)
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
source($drc_test_source)
|
||||
report("Report comment with\nanother line", $drc_test_report)
|
||||
|
||||
deep
|
||||
|
||||
l1 = input(1, 0)
|
||||
l1 = l1.sized(0.1, 0.0)
|
||||
|
||||
l1.output("l1", "L1 (1/0 sized by x=100nm,y=0)")
|
||||
l1.width(1.0.um).output("w1um", "w < 1µm\nFrom sized input")
|
||||
|
||||
l1s = l1.snapped(200.nm)
|
||||
l1s.output("l1_snapped", "L1 snapped to 200nm")
|
||||
l1s.width(1.0.um).output("w1um_snapped", "w < 1µm\nFrom snapped input")
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
source($drc_test_source)
|
||||
report("Report comment with\nanother line", $drc_test_report)
|
||||
|
||||
deep
|
||||
|
||||
l1 = input(1, 0)
|
||||
l1s = l1.sized(0.1, 0.0)
|
||||
|
||||
l1.output([ "input", "L1" ], "Original layer")
|
||||
l1s.output([ "input", "L1S" ], "Sized original layer")
|
||||
|
||||
l1s.width(1.0.um).output("w1um", "w < 1µm\nFrom sized input")
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
source($drc_test_source)
|
||||
report("Report comment with\nanother line", $drc_test_report)
|
||||
|
||||
deep
|
||||
|
||||
l1 = input(1, 0)
|
||||
l1 = l1.sized(0.1, 0.0)
|
||||
|
||||
l1.output(["inputs", "l1"], "L1 (1/0 sized by x=100nm,y=0)")
|
||||
l1.width(1.0.um).output("w1um", "w < 1µm\nAnother line")
|
||||
|
||||
l1s = l1.snapped(200.nm)
|
||||
l1s.output([ "inputs", "l1_snapped" ], "L1 snapped to 200nm")
|
||||
l1s.width(1.0.um).output("w1um_snapped", "w < 1µm\nFrom snapped input")
|
||||
|
||||
Binary file not shown.
|
|
@ -14,10 +14,12 @@ end
|
|||
a1 = input(1)
|
||||
b1 = input(2)
|
||||
c1 = input(3)
|
||||
e1 = input(5)
|
||||
|
||||
a1.output(1, 0)
|
||||
b1.output(2, 0)
|
||||
c1.output(3, 0)
|
||||
e1.output(5, 0)
|
||||
|
||||
c1.rounded_corners(0.5, 0.5, 16).output(1010, 0)
|
||||
c1.smoothed(1.5).output(1011, 0)
|
||||
|
|
@ -70,6 +72,11 @@ a1.corners(-90.0, as_edge_pairs).polygons(0).output(1063, 0)
|
|||
a1.corners(-90.0, as_edge_pairs).first_edges.start_segments(0.1).extended(0.05, 0.05, 0.05, 0.05).output(1064, 0)
|
||||
a1.corners(-90.0, as_edge_pairs).second_edges.start_segments(0.1).extended(0.05, 0.05, 0.05, 0.05).output(1065, 0)
|
||||
|
||||
e1.corners(90.0, as_boxes).sized(0.05).output(1066, 0)
|
||||
e1.corners(90.0, absolute, as_boxes).sized(0.05).output(1067, 0)
|
||||
e1.corners(90.0, negative, as_boxes).sized(0.05).output(1068, 0)
|
||||
e1.corners(44.0 .. 46.0, absolute, as_boxes).sized(0.05).output(1069, 0)
|
||||
|
||||
a1.select { |p| p.bbox.width < 0.8 }.output(1100, 0)
|
||||
a1.collect { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1101, 0)
|
||||
a1.collect_to_region { |p| p.is_box? && p.bbox.enlarged(0.1, 0.1) }.output(1102, 0)
|
||||
|
|
|
|||
|
|
@ -18,9 +18,13 @@ ep.without_distance(0.25, nil).polygons(0).output(121, 0)
|
|||
ep.with_angle(45.0).polygons(0).output(200, 0)
|
||||
ep.with_angle(0.0).polygons(0).output(201, 0)
|
||||
ep.with_angle(45.0..91.0).polygons(0).output(202, 0)
|
||||
ep.with_angle(45.0, absolute).polygons(0).output(203, 0)
|
||||
ep.with_angle(45.0..91.0, absolute).polygons(0).output(204, 0)
|
||||
ep.with_angle(45.0, 91.0, absolute).polygons(0).output(205, 0)
|
||||
ep.with_angle(45.0, both).polygons(0).output(210, 0)
|
||||
ep.with_angle(0.0, both).polygons(0).output(211, 0)
|
||||
ep.with_angle(45.0..91.0, both).polygons(0).output(212, 0)
|
||||
ep.with_angle(45.0..91.0, absolute, both).polygons(0).output(213, 0)
|
||||
|
||||
ep.without_angle(45.0).polygons(0).output(220, 0)
|
||||
ep.without_angle(0.0).polygons(0).output(221, 0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
r = input(1, 0)
|
||||
e = r.edges
|
||||
|
||||
r.output(1, 0)
|
||||
|
||||
r.with_angle(45.0).polygons(0).output(100, 0)
|
||||
r.with_angle(90.0).polygons(0).output(101, 0)
|
||||
r.with_angle(91.0..100.0).polygons(0).output(102, 0)
|
||||
|
||||
r.without_angle(45.0).polygons(0).output(120, 0)
|
||||
r.without_angle(90.0).polygons(0).output(121, 0)
|
||||
r.without_angle(45.0..100.0).polygons(0).output(122, 0)
|
||||
|
||||
e.with_angle(45.0).output(200, 0)
|
||||
e.with_angle(0.0).output(201, 0)
|
||||
e.with_angle(45.0..91.0).output(202, 0)
|
||||
e.with_angle(45.0, absolute).output(203, 0)
|
||||
e.with_angle(45.0..91.0, absolute).output(204, 0)
|
||||
e.with_angle(45.0, 91.0, absolute).output(205, 0)
|
||||
|
||||
e.without_angle(45.0).output(220, 0)
|
||||
e.without_angle(0.0).output(221, 0)
|
||||
e.without_angle(45.0..91.0).output(222, 0)
|
||||
e.without_angle(45.0, absolute).output(223, 0)
|
||||
e.without_angle(45.0..91.0, absolute).output(224, 0)
|
||||
e.without_angle(45.0, 91.0, absolute).output(225, 0)
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,585 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<report-database>
|
||||
<description>Report comment with
|
||||
another line</description>
|
||||
<original-file/>
|
||||
<generator>drc: script='.drc'</generator>
|
||||
<top-cell>TOP</top-cell>
|
||||
<tags>
|
||||
</tags>
|
||||
<categories>
|
||||
<category>
|
||||
<name>l1</name>
|
||||
<description>L1 (1/0 sized by x=100nm,y=0)</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>w1um</name>
|
||||
<description>w < 1µm
|
||||
From sized input</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>l1_snapped</name>
|
||||
<description>L1 snapped to 200nm</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>w1um_snapped</name>
|
||||
<description>w < 1µm
|
||||
From snapped input</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
</categories>
|
||||
<cells>
|
||||
<cell>
|
||||
<name>TOP</name>
|
||||
<variant/>
|
||||
<layout-name/>
|
||||
<references>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0</variant>
|
||||
<layout-name>A</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 0.5,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r90</variant>
|
||||
<layout-name>A$VAR1</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r270 *1 2,2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0;r0(-0.1,0)</variant>
|
||||
<layout-name>A</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 0.5,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0;r0</variant>
|
||||
<layout-name>A$VAR1$1</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 1.2,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
</cells>
|
||||
<items>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.7,3.9;3.3,4;3.6,4.6;5.1,4.9;5.3,4.9;5.2,4.2;5,4.2;3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.1,3;2.1,3.6;2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (-0.1,0;-0.1,1.6;0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,-0.1;0,1.7;0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.6,4.6;4.256,4.731)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.53,4.233;3.804,4.285)|(3.455,4.31;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.3,4;3.6,4.6)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.266,4.733;5.1,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(4.138,4.708;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;3.804,4.285)|(3.6,4.6;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.6,4.6;4.408,4.762)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.1,4.9;5.3,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;4.343,4.247)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.1,3;2.1,3.6)|(2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.9,3;2.1,3)|(2.1,3.6;2.9,3.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.1,0;-0.1,1.6)|(0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,-0.1;0,1.7)|(0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.4,4;3.6,4.6;5.2,5;5.4,5;5.2,4.2;3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.2,3;2.2,3.6;3,3.6;3,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1_snapped</category>
|
||||
<cell>A:r0;r0(-0.1,0)</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (-0.1,0;-0.1,1.6;0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1_snapped</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.8;0.2,1.8;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>l1_snapped</category>
|
||||
<cell>A:r0;r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.6;0.4,1.6;0.4,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.467,4.2;3.6,4.6)|(4.521,4.2;3.8,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.4,4;3.55,4.45)|(3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.4,4;3.6,4.6)|(4,4;3.4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.314,4.778;5.2,5)|(5.4,5;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;3.8,4.2)|(3.6,4.6;5.2,5)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4,4;3.4,4)|(3.6,4.6;4.547,4.837)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,5;5.4,5)|(5.4,5;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;4.6,4.2)|(5.2,5;5.4,5)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4,4;3.4,4)|(3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.2,3;2.2,3.6)|(3,3.6;3,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3,3;2.2,3)|(2.2,3.6;3,3.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r0;r0(-0.1,0)</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.1,0;-0.1,1.6)|(0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0;0,1.8)|(0.2,1.8;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r0;r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0;0,1.6)|(0.4,1.6;0.4,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
</items>
|
||||
</report-database>
|
||||
|
|
@ -0,0 +1,382 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<report-database>
|
||||
<description>Report comment with
|
||||
another line</description>
|
||||
<original-file/>
|
||||
<generator>drc: script='.drc'</generator>
|
||||
<top-cell>TOP</top-cell>
|
||||
<tags>
|
||||
</tags>
|
||||
<categories>
|
||||
<category>
|
||||
<name>input</name>
|
||||
<description/>
|
||||
<categories>
|
||||
<category>
|
||||
<name>L1</name>
|
||||
<description>Original layer</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>L1S</name>
|
||||
<description>Sized original layer</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>w1um</name>
|
||||
<description>w < 1µm
|
||||
From sized input</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
</categories>
|
||||
<cells>
|
||||
<cell>
|
||||
<name>TOP</name>
|
||||
<variant/>
|
||||
<layout-name/>
|
||||
<references>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0</variant>
|
||||
<layout-name>A</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 0.5,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r90</variant>
|
||||
<layout-name>A$VAR1</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r270 *1 2,2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
</cells>
|
||||
<items>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.8,3.9;3.4,4;3.7,4.6;5.2,4.9;5.1,4.2;3.7,4.3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.2,3;2.2,3.6;2.8,3.6;2.8,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.6;0.2,1.6;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.6;0.2,1.6;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1S</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.7,3.9;3.3,4;3.6,4.6;5.1,4.9;5.3,4.9;5.2,4.2;5,4.2;3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1S</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.1,3;2.1,3.6;2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1S</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (-0.1,0;-0.1,1.6;0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>input.L1S</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,-0.1;0,1.7;0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.6,4.6;4.256,4.731)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.53,4.233;3.804,4.285)|(3.455,4.31;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.3,4;3.6,4.6)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.266,4.733;5.1,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(4.138,4.708;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;3.804,4.285)|(3.6,4.6;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.6,4.6;4.408,4.762)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.1,4.9;5.3,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;4.343,4.247)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.1,3;2.1,3.6)|(2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.9,3;2.1,3)|(2.1,3.6;2.9,3.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.1,0;-0.1,1.6)|(0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,-0.1;0,1.7)|(0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
</items>
|
||||
</report-database>
|
||||
|
|
@ -0,0 +1,596 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<report-database>
|
||||
<description>Report comment with
|
||||
another line</description>
|
||||
<original-file/>
|
||||
<generator>drc: script='.drc'</generator>
|
||||
<top-cell>TOP</top-cell>
|
||||
<tags>
|
||||
<tag>
|
||||
<name>waived</name>
|
||||
<description/>
|
||||
</tag>
|
||||
</tags>
|
||||
<categories>
|
||||
<category>
|
||||
<name>inputs</name>
|
||||
<description/>
|
||||
<categories>
|
||||
<category>
|
||||
<name>l1</name>
|
||||
<description>L1 (1/0 sized by x=100nm,y=0)</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>l1_snapped</name>
|
||||
<description>L1 snapped to 200nm</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>w1um</name>
|
||||
<description>w < 1µm
|
||||
Another line</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>w1um_snapped</name>
|
||||
<description>w < 1µm
|
||||
From snapped input</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
</categories>
|
||||
<cells>
|
||||
<cell>
|
||||
<name>TOP</name>
|
||||
<variant/>
|
||||
<layout-name/>
|
||||
<references>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0</variant>
|
||||
<layout-name>A</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 0.5,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r90</variant>
|
||||
<layout-name>A$VAR1</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r270 *1 2,2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0;r0(-0.1,0)</variant>
|
||||
<layout-name>A</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 0.5,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0;r0</variant>
|
||||
<layout-name>A$VAR1$1</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 1.2,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
</cells>
|
||||
<items>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.7,3.9;3.3,4;3.6,4.6;5.1,4.9;5.3,4.9;5.2,4.2;5,4.2;3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.1,3;2.1,3.6;2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (-0.1,0;-0.1,1.6;0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,-0.1;0,1.7;0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.6,4.6;4.256,4.731)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.53,4.233;3.804,4.285)|(3.455,4.31;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.3,4;3.6,4.6)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.266,4.733;5.1,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(4.138,4.708;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;3.804,4.285)|(3.6,4.6;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.6,4.6;4.408,4.762)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment>First item von w1um</comment>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.1,4.9;5.3,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;4.343,4.247)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.1,3;2.1,3.6)|(2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.9,3;2.1,3)|(2.1,3.6;2.9,3.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.1,0;-0.1,1.6)|(0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,-0.1;0,1.7)|(0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.4,4;3.6,4.6;5.2,5;5.4,5;5.2,4.2;3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.2,3;2.2,3.6;3,3.6;3,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>A:r0;r0(-0.1,0)</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment>A comment on the only waived input shape</comment>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (-0.1,0;-0.1,1.6;0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.8;0.2,1.8;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>A:r0;r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.6;0.4,1.6;0.4,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.467,4.2;3.6,4.6)|(4.521,4.2;3.8,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.4,4;3.55,4.45)|(3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.4,4;3.6,4.6)|(4,4;3.4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.314,4.778;5.2,5)|(5.4,5;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;3.8,4.2)|(3.6,4.6;5.2,5)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4,4;3.4,4)|(3.6,4.6;4.547,4.837)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,5;5.4,5)|(5.4,5;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;4.6,4.2)|(5.2,5;5.4,5)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4,4;3.4,4)|(3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.2,3;2.2,3.6)|(3,3.6;3,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3,3;2.2,3)|(2.2,3.6;3,3.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r0;r0(-0.1,0)</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.1,0;-0.1,1.6)|(0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0;0,1.8)|(0.2,1.8;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r0;r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment>A comment
|
||||
With two lines</comment>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0;0,1.6)|(0.4,1.6;0.4,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
</items>
|
||||
</report-database>
|
||||
|
|
@ -0,0 +1,616 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<report-database>
|
||||
<description>waiving
|
||||
another line</description>
|
||||
<original-file>/home/matthias/klayout/testdata/waiving.gds</original-file>
|
||||
<generator>drc: script='/home/matthias/.klayout/drc/waiving.lydrc'</generator>
|
||||
<top-cell>TOP</top-cell>
|
||||
<tags>
|
||||
<tag>
|
||||
<name>waived</name>
|
||||
<description/>
|
||||
</tag>
|
||||
<tag>
|
||||
<name>red</name>
|
||||
<description/>
|
||||
</tag>
|
||||
<tag>
|
||||
<name>green</name>
|
||||
<description/>
|
||||
</tag>
|
||||
<tag>
|
||||
<name>blue</name>
|
||||
<description/>
|
||||
</tag>
|
||||
<tag>
|
||||
<name>yellow</name>
|
||||
<description/>
|
||||
</tag>
|
||||
<tag>
|
||||
<name>important</name>
|
||||
<description/>
|
||||
</tag>
|
||||
</tags>
|
||||
<categories>
|
||||
<category>
|
||||
<name>inputs</name>
|
||||
<description/>
|
||||
<categories>
|
||||
<category>
|
||||
<name>l1</name>
|
||||
<description>L1 (1/0 sized by x=100nm,y=0)</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>l1_snapped</name>
|
||||
<description>L1 snapped to 200nm</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>w1um</name>
|
||||
<description>w < 1µm
|
||||
Another line</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
<category>
|
||||
<name>w1um_snapped</name>
|
||||
<description>w < 1µm
|
||||
From snapped input</description>
|
||||
<categories>
|
||||
</categories>
|
||||
</category>
|
||||
</categories>
|
||||
<cells>
|
||||
<cell>
|
||||
<name>TOP</name>
|
||||
<variant/>
|
||||
<layout-name/>
|
||||
<references>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0</variant>
|
||||
<layout-name>A</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 0.5,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r90</variant>
|
||||
<layout-name>A$VAR1</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r270 *1 2,2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0;r0(-0.1,0)</variant>
|
||||
<layout-name>A</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 0.5,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
<cell>
|
||||
<name>A</name>
|
||||
<variant>r0;r0</variant>
|
||||
<layout-name>A$VAR1$1</layout-name>
|
||||
<references>
|
||||
<ref>
|
||||
<parent>TOP</parent>
|
||||
<trans>r0 *1 1.2,1.2</trans>
|
||||
</ref>
|
||||
</references>
|
||||
</cell>
|
||||
</cells>
|
||||
<items>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.7,3.9;3.3,4;3.6,4.6;5.1,4.9;5.3,4.9;5.2,4.2;5,4.2;3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.1,3;2.1,3.6;2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (-0.1,0;-0.1,1.6;0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,-0.1;0,1.7;0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment>First item von w1um</comment>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.1,4.9;5.3,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.6,4.6;4.408,4.762)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(4.138,4.708;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.9,3;2.1,3)|(2.1,3.6;2.9,3.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.9,3.9;3.7,3.9)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.3,4;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.3,4;3.6,4.6)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.6,4.6;4.256,4.731)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.53,4.233;3.804,4.285)|(3.455,4.31;3.6,4.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.1,3;2.1,3.6)|(2.9,3.6;2.9,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;5,4.2)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.7,3.9;3.3,4)|(3.804,4.285;3.9,3.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;4.343,4.247)|(5.1,4.9;5.3,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.266,4.733;5.1,4.9)|(5.3,4.9;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5,4.2;3.804,4.285)|(3.6,4.6;5.1,4.9)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>A:r0</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.1,0;-0.1,1.6)|(0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,-0.1;0,1.7)|(0.2,1.7;0.2,-0.1)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (3.4,4;3.6,4.6;5.2,5;5.4,5;5.2,4.2;3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (2.2,3;2.2,3.6;3,3.6;3,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>A:r0;r0(-0.1,0)</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment>A comment on the only waived input shape</comment>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (-0.1,0;-0.1,1.6;0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.8;0.2,1.8;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>inputs.l1_snapped</category>
|
||||
<cell>A:r0;r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>polygon: (0,0;0,1.6;0.4,1.6;0.4,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;4.6,4.2)|(5.2,5;5.4,5)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4,4;3.4,4)|(3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,5;5.4,5)|(5.4,5;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4,4;3.4,4)|(3.6,4.6;4.547,4.837)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (5.2,4.2;3.8,4.2)|(3.6,4.6;5.2,5)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (4.314,4.778;5.2,5)|(5.4,5;5.2,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.4,4;3.6,4.6)|(4,4;3.4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.4,4;3.55,4.45)|(3.8,4.2;4,4)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3.467,4.2;3.6,4.6)|(4.521,4.2;3.8,4.2)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (3,3;2.2,3)|(2.2,3.6;3,3.6)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (2.2,3;2.2,3.6)|(3,3.6;3,3)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r0;r0(-0.1,0)</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.1,0;-0.1,1.6)|(0.3,1.6;0.3,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags>waived</tags>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r90</cell>
|
||||
<visited>true</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0;0,1.8)|(0.2,1.8;0.2,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
<item>
|
||||
<tags/>
|
||||
<category>w1um_snapped</category>
|
||||
<cell>A:r0;r0</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment>A comment
|
||||
With two lines</comment>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0;0,1.6)|(0.4,1.6;0.4,0)</value>
|
||||
</values>
|
||||
</item>
|
||||
</items>
|
||||
</report-database>
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
<cell>
|
||||
<name>TOP</name>
|
||||
<variant/>
|
||||
<layout-name/>
|
||||
<references>
|
||||
</references>
|
||||
</cell>
|
||||
|
|
@ -35,6 +36,7 @@
|
|||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (-0.2,0.7;1,0.7)|(1,1.1;-0.2,1.1)</value>
|
||||
|
|
@ -46,6 +48,7 @@
|
|||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0;0,0.9)|(0.3,0.9;0.3,0)</value>
|
||||
|
|
@ -57,6 +60,7 @@
|
|||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0.3,0;0,0)|(0,0.9;0.3,0.9)</value>
|
||||
|
|
@ -68,6 +72,7 @@
|
|||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0.5,0;0.5,0.9)|(0.8,0.9;0.8,0)</value>
|
||||
|
|
@ -79,6 +84,7 @@
|
|||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0.8,0;0.5,0)|(0.5,0.9;0.8,0.9)</value>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<cell>
|
||||
<name>TOP</name>
|
||||
<variant/>
|
||||
<layout-name/>
|
||||
<references>
|
||||
</references>
|
||||
</cell>
|
||||
|
|
@ -29,6 +30,7 @@
|
|||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0,0.9;0.3,0.9)/(1,1.1;-0.2,1.1)</value>
|
||||
|
|
@ -40,6 +42,7 @@
|
|||
<cell>TOP</cell>
|
||||
<visited>false</visited>
|
||||
<multiplicity>1</multiplicity>
|
||||
<comment/>
|
||||
<image/>
|
||||
<values>
|
||||
<value>edge-pair: (0.5,0.9;0.8,0.9)/(1,1.1;-0.2,1.1)</value>
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,13 @@
|
|||
* Extracted by KLayout
|
||||
|
||||
.SUBCKT TOP A Q VDD SUBSTRATE|VSS
|
||||
X$1 SUBSTRATE|VSS VDD VDD \$1 Q SUBSTRATE|VSS INV
|
||||
X$2 SUBSTRATE|VSS VDD VDD A \$1 SUBSTRATE|VSS INV
|
||||
.ENDS TOP
|
||||
|
||||
.SUBCKT INV \$1 \$2 \$3 \$4 \$5 SUBSTRATE
|
||||
M$1 \$2 \$4 \$5 \$3 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
M$2 \$1 \$4 \$5 SUBSTRATE NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||
+ PD=3.45U
|
||||
.ENDS INV
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
#%l2n-klayout
|
||||
W(TOP)
|
||||
U(0.001)
|
||||
L(l3 '1/0')
|
||||
L(l4 '3/0')
|
||||
L(l15 '3/1')
|
||||
L(l8 '4/0')
|
||||
L(l11 '5/0')
|
||||
L(l12 '6/0')
|
||||
L(l16 '6/1')
|
||||
L(l13 '7/0')
|
||||
L(l14 '8/0')
|
||||
L(l17 '8/1')
|
||||
L(l7)
|
||||
L(l10)
|
||||
L(l2)
|
||||
L(l9)
|
||||
L(l6)
|
||||
C(l3 l3 l10)
|
||||
C(l4 l4 l15 l11)
|
||||
C(l15 l4 l15)
|
||||
C(l8 l8 l12 l10 l2 l9 l6)
|
||||
CS(l8 l10 l2 l9 l6)
|
||||
C(l11 l4 l11 l12)
|
||||
CS(l11 l4)
|
||||
C(l12 l8 l11 l12 l16 l13)
|
||||
C(l16 l12 l16)
|
||||
C(l13 l12 l13 l14)
|
||||
C(l14 l13 l14 l17)
|
||||
C(l17 l14 l17)
|
||||
C(l7 l7)
|
||||
C(l10 l3 l8 l10)
|
||||
CS(l10 l3)
|
||||
C(l2 l8 l2)
|
||||
C(l9 l8 l9)
|
||||
C(l6 l8 l6)
|
||||
G(l7 SUBSTRATE)
|
||||
GS(l7 SUBSTRATE)
|
||||
G(l9 SUBSTRATE)
|
||||
GS(l9 SUBSTRATE)
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VDD') C(TOP) Q('(0.6,3.95;0.6,4.85;4.5,4.85;4.5,3.95)'))
|
||||
H(B('\tPartial net #2: TOP - $I4') C(TOP) Q('(5.1,3.95;5.1,4.85;9,4.85;9,3.95)'))
|
||||
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||
H(B('\tPartial net #1: TOP - VSS') C(TOP) Q('(0.6,1.15;0.6,2.05;4.5,2.05;4.5,1.15)'))
|
||||
H(B('\tPartial net #2: TOP - $I1') C(TOP) Q('(5.1,1.15;5.1,2.05;9,2.05;9,1.15)'))
|
||||
K(PMOS MOS4)
|
||||
K(NMOS MOS4)
|
||||
D(D$PMOS PMOS
|
||||
T(S
|
||||
R(l2 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l2 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l3 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
D(D$NMOS NMOS
|
||||
T(S
|
||||
R(l6 (-900 -475) (775 950))
|
||||
)
|
||||
T(G
|
||||
R(l4 (-125 -475) (250 950))
|
||||
)
|
||||
T(D
|
||||
R(l6 (125 -475) (775 950))
|
||||
)
|
||||
T(B
|
||||
R(l7 (-125 -475) (250 950))
|
||||
)
|
||||
)
|
||||
X(INV
|
||||
R((-1500 -800) (3000 4600))
|
||||
N(1
|
||||
R(l8 (290 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
R(l6 (-1375 -925) (775 950))
|
||||
)
|
||||
N(2
|
||||
R(l8 (290 2490) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -690) (360 760))
|
||||
R(l13 (-305 -705) (250 250))
|
||||
R(l13 (-250 150) (250 250))
|
||||
R(l14 (-2025 -775) (3000 900))
|
||||
R(l2 (-1375 -925) (775 950))
|
||||
)
|
||||
N(3
|
||||
R(l3 (-1500 1800) (3000 2000))
|
||||
)
|
||||
N(4
|
||||
R(l4 (-125 -250) (250 2500))
|
||||
R(l4 (-250 -3050) (250 1600))
|
||||
R(l4 (-250 1200) (250 1600))
|
||||
)
|
||||
N(5
|
||||
R(l8 (-510 -310) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l8 (-220 2180) (220 220))
|
||||
R(l8 (-220 180) (220 220))
|
||||
R(l12 (-290 -3530) (360 2840))
|
||||
R(l12 (-360 -2800) (360 760))
|
||||
R(l12 (-360 2040) (360 760))
|
||||
R(l2 (-680 -855) (775 950))
|
||||
R(l6 (-775 -3750) (775 950))
|
||||
)
|
||||
N(6 I(SUBSTRATE))
|
||||
P(1)
|
||||
P(2)
|
||||
P(3)
|
||||
P(4)
|
||||
P(5)
|
||||
P(6 I(SUBSTRATE))
|
||||
D(1 D$PMOS
|
||||
Y(0 2800)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 5)
|
||||
T(G 4)
|
||||
T(D 2)
|
||||
T(B 3)
|
||||
)
|
||||
D(2 D$NMOS
|
||||
Y(0 0)
|
||||
E(L 0.25)
|
||||
E(W 0.95)
|
||||
E(AS 0.73625)
|
||||
E(AD 0.73625)
|
||||
E(PS 3.45)
|
||||
E(PD 3.45)
|
||||
T(S 5)
|
||||
T(G 4)
|
||||
T(D 1)
|
||||
T(B 6)
|
||||
)
|
||||
)
|
||||
X(TOP
|
||||
R((600 800) (8880 4600))
|
||||
N(1
|
||||
R(l4 (2920 2600) (2880 400))
|
||||
R(l11 (-300 -300) (200 200))
|
||||
R(l12 (-300 -300) (690 400))
|
||||
)
|
||||
N(2 I(A)
|
||||
R(l4 (6600 2600) (2880 400))
|
||||
R(l15 (-2380 -200) (0 0))
|
||||
)
|
||||
N(3 I(Q)
|
||||
R(l12 (1810 2600) (690 400))
|
||||
R(l16 (-400 -200) (0 0))
|
||||
)
|
||||
N(4 I(VDD)
|
||||
R(l3 (4000 3400) (1600 2000))
|
||||
R(l3 (-5000 -2000) (1000 2000))
|
||||
R(l3 (6400 -2000) (1000 2000))
|
||||
R(l8 (-8000 -900) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-8000 -350) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -450) (0 0))
|
||||
)
|
||||
N(5 I('SUBSTRATE,VSS')
|
||||
R(l8 (1000 1700) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l8 (7200 200) (200 200))
|
||||
R(l8 (-200 -600) (200 200))
|
||||
R(l12 (-7900 -350) (800 900))
|
||||
R(l12 (6600 -900) (800 900))
|
||||
R(l13 (-7900 -350) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l13 (7200 200) (200 200))
|
||||
R(l13 (-200 -600) (200 200))
|
||||
R(l14 (-8000 -350) (1000 900))
|
||||
R(l14 (6400 -900) (1000 900))
|
||||
R(l17 (-4800 -550) (0 0))
|
||||
)
|
||||
P(2 I(A))
|
||||
P(3 I(Q))
|
||||
P(4 I(VDD))
|
||||
P(5 I('SUBSTRATE,VSS'))
|
||||
X(1 INV Y(3000 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 1)
|
||||
P(4 3)
|
||||
P(5 5)
|
||||
)
|
||||
X(2 INV Y(6600 1600)
|
||||
P(0 5)
|
||||
P(1 4)
|
||||
P(2 4)
|
||||
P(3 2)
|
||||
P(4 1)
|
||||
P(5 5)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
$lvs_test_source && source($lvs_test_source)
|
||||
|
||||
if $lvs_test_target_l2n
|
||||
report_netlist($lvs_test_target_l2n)
|
||||
else
|
||||
report_netlist
|
||||
end
|
||||
|
||||
writer = write_spice(true, false)
|
||||
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||
|
||||
deep
|
||||
|
||||
# Drawing layers
|
||||
|
||||
nwell = input(1, 0)
|
||||
active = input(2, 0)
|
||||
nplus = input(2, 1)
|
||||
pplus = input(2, 2)
|
||||
poly = input(3, 0)
|
||||
poly_lbl = input(3, 1)
|
||||
diff_cont = input(4, 0)
|
||||
poly_cont = input(5, 0)
|
||||
metal1 = input(6, 0)
|
||||
metal1_lbl = input(6, 1)
|
||||
via1 = input(7, 0)
|
||||
metal2 = input(8, 0)
|
||||
metal2_lbl = input(8, 1)
|
||||
|
||||
# Bulk layer for terminal provisioning
|
||||
|
||||
bulk = polygon_layer
|
||||
|
||||
psd = nil
|
||||
nsd = nil
|
||||
|
||||
# Computed layers
|
||||
|
||||
active_in_nwell = active & nwell
|
||||
pactive = active_in_nwell & pplus
|
||||
ntie = active_in_nwell & nplus
|
||||
pgate = pactive & poly
|
||||
psd = pactive - pgate
|
||||
|
||||
active_outside_nwell = active - nwell
|
||||
nactive = active_outside_nwell & nplus
|
||||
ptie = active_outside_nwell & pplus
|
||||
ngate = nactive & poly
|
||||
nsd = nactive - ngate
|
||||
|
||||
# Device extraction
|
||||
|
||||
# PMOS transistor device extraction
|
||||
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||
|
||||
# NMOS transistor device extraction
|
||||
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||
|
||||
# Define connectivity for netlist extraction
|
||||
|
||||
# Inter-layer
|
||||
|
||||
soft_connect(diff_cont, psd)
|
||||
soft_connect(diff_cont, nsd)
|
||||
soft_connect(diff_cont, ptie)
|
||||
soft_connect(diff_cont, ntie)
|
||||
soft_connect(ntie, nwell)
|
||||
soft_connect(poly_cont, poly)
|
||||
|
||||
connect(diff_cont, metal1)
|
||||
connect(poly_cont, metal1)
|
||||
connect(metal1, via1)
|
||||
connect(via1, metal2)
|
||||
|
||||
# attach labels
|
||||
connect(poly, poly_lbl)
|
||||
connect(metal1, metal1_lbl)
|
||||
connect(metal2, metal2_lbl)
|
||||
|
||||
# Global
|
||||
soft_connect_global(bulk, "SUBSTRATE")
|
||||
soft_connect_global(ptie, "SUBSTRATE")
|
||||
|
||||
# Netlist section (NOTE: we only check log here)
|
||||
netlist
|
||||
|
||||
netlist.simplify
|
||||
|
||||
|
||||
|
|
@ -294,6 +294,7 @@ class DBEdgePairs_TestClass < TestBase
|
|||
ep4 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 10, 10))
|
||||
|
||||
r1 = RBA::EdgePairs::new([ ep1, ep2, ep3, ep4 ])
|
||||
assert_equal(r1.with_angle(0, 90, false).to_s, "") # @@@
|
||||
|
||||
assert_equal(r1.with_distance(10, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_distance(5, 20, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
|
|
@ -310,15 +311,25 @@ class DBEdgePairs_TestClass < TestBase
|
|||
assert_equal(r1.with_length_both(10, true).to_s, "(0,0;0,20)/(10,20;10,0)")
|
||||
|
||||
assert_equal(r1.with_angle(0, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle(0, false).to_s, "")
|
||||
assert_equal(r1.with_angle(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(0, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle_both(0, false).to_s, "")
|
||||
assert_equal(r1.with_angle_both(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle_both(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_abs_angle_both(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_angle_both(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_abs_angle_both(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
|
||||
assert_equal(r1.with_area(0, false).to_s, "(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_area(150, false).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
|
|
|
|||
|
|
@ -585,12 +585,19 @@ class DBEdges_TestClass < TestBase
|
|||
r.insert(RBA::Edge::new(0, 0, 100, 0))
|
||||
r.insert(RBA::Edge::new(100, 0, 100, 50))
|
||||
assert_equal(r.with_angle(0, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_abs_angle(0, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_angle(0, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(0, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_angle(90, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(90, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_angle(90, true).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_abs_angle(90, true).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_angle(-10, 10, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_abs_angle(-10, 10, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_angle(-10, 10, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(-10, 10, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_angle(80, 100, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_abs_angle(80, 100, false).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_length(100, false).to_s, "(0,0;100,0)")
|
||||
assert_equal(r.with_length(100, true).to_s, "(100,0;100,50)")
|
||||
assert_equal(r.with_length(50, false).to_s, "(100,0;100,50)")
|
||||
|
|
|
|||
|
|
@ -76,16 +76,22 @@ class RDB_TestClass < TestBase
|
|||
assert_equal(cell.name, "cell_name")
|
||||
assert_equal(cell.rdb_id, 1)
|
||||
|
||||
cell2 = db.create_cell("cell_name", "var1")
|
||||
cell2 = db.create_cell("new_cell", "var1")
|
||||
assert_equal(cell2.name, "new_cell")
|
||||
assert_equal(cell2.layout_name, "")
|
||||
assert_equal(cell2.qname, "new_cell:var1")
|
||||
|
||||
cell2 = db.create_cell("cell_name", "var1", "cell_name$1")
|
||||
assert_equal(cell.name, "cell_name")
|
||||
assert_equal(cell.qname, "cell_name:1")
|
||||
assert_equal(db.cell_by_qname("cell_name:1").rdb_id, cell.rdb_id)
|
||||
assert_equal(db.cell_by_id(cell.rdb_id).rdb_id, cell.rdb_id)
|
||||
assert_equal(cell2.name, "cell_name")
|
||||
assert_equal(cell2.layout_name, "cell_name$1")
|
||||
assert_equal(cell2.qname, "cell_name:var1")
|
||||
assert_equal(db.cell_by_qname("cell_name:var1").rdb_id, cell2.rdb_id)
|
||||
assert_equal(db.cell_by_id(cell2.rdb_id).rdb_id, cell2.rdb_id)
|
||||
assert_equal(cell2.rdb_id, 2)
|
||||
assert_equal(cell2.rdb_id, 3)
|
||||
assert_equal(cell.num_items, 0)
|
||||
assert_equal(cell2.num_items, 0)
|
||||
assert_equal(cell.num_items_visited, 0)
|
||||
|
|
@ -98,19 +104,19 @@ class RDB_TestClass < TestBase
|
|||
|
||||
cc = []
|
||||
db.each_cell { |c| cc.push(c) }
|
||||
assert_equal(cc.size, 2)
|
||||
assert_equal(cc.size, 3)
|
||||
assert_equal(cc[0].rdb_id, cell.rdb_id)
|
||||
assert_equal(cc[1].rdb_id, cell2.rdb_id)
|
||||
assert_equal(cc[2].rdb_id, cell2.rdb_id)
|
||||
|
||||
cat = db.create_category("cat")
|
||||
assert_equal(cat.database.inspect, db.inspect)
|
||||
assert_equal(cat.name, "cat")
|
||||
assert_equal(cat.rdb_id, 3)
|
||||
assert_equal(cat.rdb_id, 4)
|
||||
assert_equal(cat.path, "cat")
|
||||
|
||||
cats = db.create_category(cat, "subcat")
|
||||
assert_equal(cats.name, "subcat")
|
||||
assert_equal(cats.rdb_id, 4)
|
||||
assert_equal(cats.rdb_id, 5)
|
||||
assert_equal(cats.path, "cat.subcat")
|
||||
assert_equal(cats.parent.rdb_id, cat.rdb_id)
|
||||
|
||||
|
|
@ -425,6 +431,10 @@ class RDB_TestClass < TestBase
|
|||
assert_equal(item.image_str, "")
|
||||
assert_equal(item.has_image?, false)
|
||||
|
||||
assert_equal(item.comment, "")
|
||||
item.comment = "abc"
|
||||
assert_equal(item.comment, "abc")
|
||||
|
||||
# can actually by any string, but only base64-encoded PNG images make sense
|
||||
is="iVBORw0KGgoAAAANSUhEUgAAACoAAAA0CAIAAABzfT3nAAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAA0SAAANOgHo3ZneAAAA3UlEQVRYhe2WwQ3DIAxFoco8XaGZIaeO43FyYgZYgYXcQ6SWuDGgBhWq/qccIvGCEd9SbAwAAPSGaW2lFR2rfWDpXrPpSe2SP10fvnn/PZHZH9IwbKFVZZ/Z6wMtZcjW02Bn2FVpZYdWdkr2nvh23S2FyDNJuVITpwmRjTGbNr0v20U5byNtJuuJt/fO2f93+UlbEJl5UjVPr3Y71EQ/PoPPlU+lDJtWlCt3GwCMG33BuJGAcWMEMG6c1jBudCyf/nzV8nbZPRohclFLHdGbZ8eNSjN1fmf0AACA1jwA4hKxu4C6P7EAAAAASUVORK5CYII="
|
||||
item.image_str=is
|
||||
|
|
|
|||
Loading…
Reference in New Issue