mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' of github.com:KLayout/klayout
This commit is contained in:
commit
bdb8389420
|
|
@ -680,13 +680,17 @@ bool run_tiled_xor (const XORData &xor_data)
|
|||
if (ll->second.first < 0) {
|
||||
proc.input (in_a, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_a, db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first));
|
||||
db::RecursiveShapeIterator si (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
|
||||
si.set_for_merged_input (true);
|
||||
proc.input (in_a, si);
|
||||
}
|
||||
|
||||
if (ll->second.second < 0) {
|
||||
proc.input (in_b, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_b, db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second));
|
||||
db::RecursiveShapeIterator si (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
|
||||
si.set_for_merged_input (true);
|
||||
proc.input (in_b, si);
|
||||
}
|
||||
|
||||
std::string expr = "var x=" + in_a + "^" + in_b + "; ";
|
||||
|
|
@ -805,10 +809,12 @@ bool run_deep_xor (const XORData &xor_data)
|
|||
|
||||
if (ll->second.first >= 0) {
|
||||
ri_a = db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
|
||||
ri_a.set_for_merged_input (true);
|
||||
}
|
||||
|
||||
if (ll->second.second >= 0) {
|
||||
ri_b = db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
|
||||
ri_b.set_for_merged_input (true);
|
||||
}
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (xor_data.layout_a->dbu () / dbu));
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ AsIfFlatRegion::area (const db::Box &box) const
|
|||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
if (box.empty () || p->box ().inside (box)) {
|
||||
a += p->area ();
|
||||
} else if (p->is_box ()) {
|
||||
a += (p->box () & box).area ();
|
||||
} else {
|
||||
std::vector<db::Polygon> clipped;
|
||||
clip_poly (*p, box, clipped);
|
||||
|
|
|
|||
|
|
@ -254,6 +254,27 @@ struct DB_PUBLIC_TEMPLATE box
|
|||
*/
|
||||
box<C, R> &operator+= (const point<C> &p);
|
||||
|
||||
/**
|
||||
* @brief Subtraction of boxes.
|
||||
*
|
||||
* The -= operator subtracts the argument box from *this.
|
||||
* Subtraction leaves the bounding box of the region resulting
|
||||
* from the geometrical NOT of *this and the argument box.
|
||||
* Subtracting a box from itself gives an empty box.
|
||||
* Subtracting a box that does not cover a full side of
|
||||
* *this will not modify the box.
|
||||
*
|
||||
* @param b The box to subtract from *this.
|
||||
*
|
||||
* @return The result box.
|
||||
*/
|
||||
box<C, R> &operator-= (const box<C, R> &b);
|
||||
|
||||
/**
|
||||
* @brief A method version for operator- (mainly for automation purposes)
|
||||
*/
|
||||
box<C, R> subtracted (const box<C, R> &b) const;
|
||||
|
||||
/**
|
||||
* @brief Intersection of boxes.
|
||||
*
|
||||
|
|
@ -784,6 +805,50 @@ box<C, R>::operator+= (const point<C> &p)
|
|||
return *this;
|
||||
}
|
||||
|
||||
template <class C, class R>
|
||||
inline box<C, R>
|
||||
box<C, R>::subtracted (const box<C, R> &b) const
|
||||
{
|
||||
box<C, R> r (*this);
|
||||
r -= b;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class C, class R>
|
||||
inline box<C, R> &
|
||||
box<C, R>::operator-= (const box<C, R> &bx)
|
||||
{
|
||||
if (bx.empty () || empty ()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
coord_type l = m_p1.x (), r = m_p2.x ();
|
||||
coord_type b = m_p1.y (), t = m_p2.y ();
|
||||
|
||||
if (bx.bottom () <= bottom () && bx.top () >= top ()) {
|
||||
if (bx.left () <= left ()) {
|
||||
l = std::max (bx.right (), left ());
|
||||
}
|
||||
if (bx.right () >= right ()) {
|
||||
r = std::min (bx.left (), right ());
|
||||
}
|
||||
}
|
||||
|
||||
if (bx.left () <= left () && bx.right () >= right ()) {
|
||||
if (bx.bottom () <= bottom ()) {
|
||||
b = std::max (bx.top (), bottom ());
|
||||
}
|
||||
if (bx.top () >= top ()) {
|
||||
t = std::min (bx.bottom (), top ());
|
||||
}
|
||||
}
|
||||
|
||||
m_p1 = point_type (l, b);
|
||||
m_p2 = point_type (r, t);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class C, class R>
|
||||
inline box<C, R> &
|
||||
box<C, R>::operator&= (const box<C, R> &b)
|
||||
|
|
@ -1363,6 +1428,23 @@ operator+ (const box<C> &b1, const box<C> &b2)
|
|||
return bb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Box subtraction mapped on the - operator
|
||||
*
|
||||
* @param b1 The first box
|
||||
* @param b2 The second box to subtract from the first
|
||||
*
|
||||
* @return The bounding box of the region formed but subtracting b2 from b1
|
||||
*/
|
||||
template <class C>
|
||||
inline box<C>
|
||||
operator- (const box<C> &b1, const box<C> &b2)
|
||||
{
|
||||
box<C> bb (b1);
|
||||
bb -= b2;
|
||||
return bb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief "Folding" of two boxes
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1052,6 +1052,10 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const
|
|||
|
||||
return AsIfFlatEdges::and_with (other);
|
||||
|
||||
} else if (deep_layer () == other_deep->deep_layer ()) {
|
||||
|
||||
return clone ();
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepEdges (and_or_not_with (other_deep, EdgeAnd).first);
|
||||
|
|
@ -1071,6 +1075,10 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const
|
|||
|
||||
return AsIfFlatEdges::not_with (other);
|
||||
|
||||
} else if (deep_layer () == other_deep->deep_layer ()) {
|
||||
|
||||
return new DeepEdges (deep_layer ().derived ());
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepEdges (and_or_not_with (other_deep, EdgeNot).first);
|
||||
|
|
@ -1164,6 +1172,10 @@ DeepEdges::andnot_with (const Edges &other) const
|
|||
|
||||
return AsIfFlatEdges::andnot_with (other);
|
||||
|
||||
} else if (deep_layer () == other_deep->deep_layer ()) {
|
||||
|
||||
return std::make_pair (clone (), new DeepEdges (deep_layer ().derived ()));
|
||||
|
||||
} else {
|
||||
|
||||
auto res = and_or_not_with (other_deep, EdgeAndNot);
|
||||
|
|
@ -1188,6 +1200,10 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
|
|||
|
||||
return AsIfFlatEdges::xor_with (other);
|
||||
|
||||
} else if (deep_layer () == other_deep->deep_layer ()) {
|
||||
|
||||
return new DeepEdges (deep_layer ().derived ());
|
||||
|
||||
} else {
|
||||
|
||||
// Implement XOR as (A-B)+(B-A) - only this implementation
|
||||
|
|
@ -1203,6 +1219,11 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
|
|||
|
||||
EdgesDelegate *DeepEdges::or_with (const Edges &other) const
|
||||
{
|
||||
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
|
||||
if (other_deep && other_deep->deep_layer () == deep_layer ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
// NOTE: in the hierarchical case we don't do a merge on "or": just map to add
|
||||
return add (other);
|
||||
}
|
||||
|
|
@ -1503,8 +1524,19 @@ DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer () && !counting) {
|
||||
if ((mode == EdgesOutside) == inverse) {
|
||||
return clone ();
|
||||
} else {
|
||||
return new DeepEdges (deep_layer ().derived ());
|
||||
}
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
// NOTE: with counting the other region needs to be merged
|
||||
const db::DeepLayer &other_edges = (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ());
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
|
||||
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal, min_count, max_count);
|
||||
|
|
@ -1513,8 +1545,13 @@ DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode
|
|||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
// NOTE: with counting the other region needs to be merged
|
||||
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
|
||||
if (edges == other_edges) {
|
||||
// with counting and two identical inputs, a copy needs to be made
|
||||
db::DeepLayer copy (other_edges.copy ());
|
||||
proc.run (&op, edges.layer (), copy.layer (), dl_out.layer ());
|
||||
} else {
|
||||
proc.run (&op, edges.layer (), other_edges.layer (), dl_out.layer ());
|
||||
}
|
||||
|
||||
return new db::DeepEdges (dl_out);
|
||||
}
|
||||
|
|
@ -1533,8 +1570,19 @@ DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractio
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer () && !counting) {
|
||||
if (mode != EdgesOutside) {
|
||||
return std::make_pair (clone (), new DeepEdges (deep_layer ().derived ()));
|
||||
} else {
|
||||
return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ());
|
||||
}
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
// NOTE: with counting the other region needs to be merged
|
||||
const db::DeepLayer &other_edges = (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ());
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
DeepLayer dl_out2 (edges.derived ());
|
||||
|
||||
|
|
@ -1550,7 +1598,13 @@ DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractio
|
|||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
// NOTE: with counting the other region needs to be merged
|
||||
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), output_layers);
|
||||
if (edges == other_edges) {
|
||||
// with counting and two identical inputs, a copy needs to be made
|
||||
db::DeepLayer copy (other_edges.copy ());
|
||||
proc.run (&op, edges.layer (), copy.layer (), output_layers);
|
||||
} else {
|
||||
proc.run (&op, edges.layer (), other_edges.layer (), output_layers);
|
||||
}
|
||||
|
||||
return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
|
||||
}
|
||||
|
|
@ -1591,6 +1645,10 @@ EdgesDelegate *DeepEdges::pull_generic (const Edges &other) const
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = deep_layer ();
|
||||
const db::DeepLayer &other_edges = other_deep->merged_deep_layer ();
|
||||
|
||||
|
|
@ -1617,6 +1675,10 @@ EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer ()) {
|
||||
return invert ? new db::DeepEdges (deep_layer ().derived ()) : clone ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
|
|
@ -1646,6 +1708,10 @@ std::pair<EdgesDelegate *, EdgesDelegate *> DeepEdges::in_and_out (const Edges &
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer ()) {
|
||||
return std::make_pair (clone (), new db::DeepEdges (deep_layer ().derived ()));
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
|
|
|
|||
|
|
@ -797,6 +797,10 @@ DeepRegion::and_with (const Region &other, PropertyConstraint property_constrain
|
|||
|
||||
return AsIfFlatRegion::and_with (other, property_constraint);
|
||||
|
||||
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
|
||||
|
||||
return clone ();
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepRegion (and_or_not_with (other_deep, true, property_constraint));
|
||||
|
|
@ -817,6 +821,10 @@ DeepRegion::not_with (const Region &other, PropertyConstraint property_constrain
|
|||
|
||||
return AsIfFlatRegion::not_with (other, property_constraint);
|
||||
|
||||
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
|
||||
|
||||
return new DeepRegion (deep_layer ().derived ());
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepRegion (and_or_not_with (other_deep, false, property_constraint));
|
||||
|
|
@ -825,8 +833,13 @@ DeepRegion::not_with (const Region &other, PropertyConstraint property_constrain
|
|||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::or_with (const Region &other, db::PropertyConstraint /*property_constraint*/) const
|
||||
DeepRegion::or_with (const Region &other, db::PropertyConstraint property_constraint) const
|
||||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
if (other_deep && other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
// TODO: implement property_constraint
|
||||
RegionDelegate *res = add (other);
|
||||
return res->merged_in_place ();
|
||||
|
|
@ -849,6 +862,10 @@ DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constr
|
|||
|
||||
return AsIfFlatRegion::andnot_with (other, property_constraint);
|
||||
|
||||
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
|
||||
|
||||
return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
|
||||
|
||||
} else {
|
||||
|
||||
std::pair<DeepLayer, DeepLayer> res = and_and_not_with (other_deep, property_constraint);
|
||||
|
|
@ -962,6 +979,10 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
|
|||
|
||||
return AsIfFlatRegion::xor_with (other, property_constraint);
|
||||
|
||||
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
|
||||
|
||||
return new DeepRegion (deep_layer ().derived ());
|
||||
|
||||
} else {
|
||||
|
||||
// Implement XOR as (A-B)+(B-A) - only this implementation
|
||||
|
|
@ -2127,6 +2148,16 @@ DeepRegion::in_and_out_generic (const Region &other, InteractingOutputMode outpu
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
}
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();
|
||||
|
||||
|
|
@ -2188,6 +2219,26 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer () && !counting) {
|
||||
if (mode <= 0 /*inside or interacting*/) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
}
|
||||
} else {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
// NOTE: with counting, the other polygons must be merged
|
||||
const db::DeepLayer &other_polygons = counting ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
|
||||
|
|
@ -2205,7 +2256,13 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
|
||||
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
|
||||
|
||||
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
|
||||
if (polygons == other_polygons) {
|
||||
// with counting and two identical inputs we need to create a layer copy
|
||||
db::DeepLayer other_copy (other_polygons.copy ());
|
||||
proc.run (&op, polygons.layer (), other_copy.layer (), orh.layers ());
|
||||
} else {
|
||||
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
|
||||
}
|
||||
|
||||
return orh.result_pair ();
|
||||
}
|
||||
|
|
@ -2285,6 +2342,10 @@ DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
|
|||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
if (deep_layer () == other_deep->deep_layer ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
// in "inside" mode, the first argument needs to be merged too
|
||||
const db::DeepLayer &polygons = mode < 0 ? merged_deep_layer () : deep_layer ();
|
||||
const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#include "dbOriginalLayerEdgePairs.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include "tlVariant.h"
|
||||
|
||||
|
|
@ -93,6 +96,23 @@ EdgePairs::EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
|||
mp_delegate = new DeepEdgePairs (si, dss, trans);
|
||||
}
|
||||
|
||||
void
|
||||
EdgePairs::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("EDGE_PAIRS"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
template <class Sh>
|
||||
void EdgePairs::insert (const Sh &shape)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -185,6 +185,14 @@ public:
|
|||
*/
|
||||
explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Writes the edge pair collection to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -251,6 +251,13 @@ struct CutPoints
|
|||
|
||||
}
|
||||
|
||||
// do not insert points twice
|
||||
for (auto c = cut_points.begin (); c != cut_points.end (); ++c) {
|
||||
if (*c == p) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cut_points.push_back (p);
|
||||
|
||||
}
|
||||
|
|
@ -1057,6 +1064,12 @@ EdgeProcessor::reserve (size_t n)
|
|||
mp_work_edges->reserve (n);
|
||||
}
|
||||
|
||||
size_t
|
||||
EdgeProcessor::count () const
|
||||
{
|
||||
return mp_work_edges->size ();
|
||||
}
|
||||
|
||||
void
|
||||
EdgeProcessor::insert (const db::Edge &e, EdgeProcessor::property_type p)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -695,6 +695,11 @@ public:
|
|||
*/
|
||||
void reserve (size_t n);
|
||||
|
||||
/**
|
||||
* @brief Reports the number of edges stored in the processor
|
||||
*/
|
||||
size_t count () const;
|
||||
|
||||
/**
|
||||
* @brief Insert an edge
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
#include "dbFlatEdges.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -141,6 +144,23 @@ Edges::set_delegate (EdgesDelegate *delegate, bool keep_attributes)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Edges::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("EDGES"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
void
|
||||
Edges::clear ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -833,6 +833,14 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes the edge collection to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Intersections with other edges
|
||||
* Intersections are similar to "AND", but will also report
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ FlatRegion::FlatRegion (const FlatRegion &other)
|
|||
: MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons), mp_properties_repository (other.mp_properties_repository)
|
||||
{
|
||||
init ();
|
||||
|
||||
m_is_merged = other.m_is_merged;
|
||||
m_merged_polygons_valid = other.m_merged_polygons_valid;
|
||||
}
|
||||
|
|
@ -52,15 +51,22 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged)
|
|||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
|
||||
{
|
||||
init ();
|
||||
|
||||
m_is_merged = is_merged;
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
|
||||
{
|
||||
init ();
|
||||
m_is_merged = is_merged;
|
||||
transform_generic (trans);
|
||||
set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (bool is_merged)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
|
||||
{
|
||||
init ();
|
||||
|
||||
m_is_merged = is_merged;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ public:
|
|||
typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type;
|
||||
|
||||
FlatRegion ();
|
||||
FlatRegion (const db::Shapes &polygons, bool is_merged);
|
||||
FlatRegion (const db::Shapes &polygons, bool is_merged = false);
|
||||
FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false);
|
||||
FlatRegion (bool is_merged);
|
||||
|
||||
FlatRegion (const FlatRegion &other);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
mp_shape_prop_sel = d.mp_shape_prop_sel;
|
||||
m_shape_inv_prop_sel = d.m_shape_inv_prop_sel;
|
||||
m_overlapping = d.m_overlapping;
|
||||
m_for_merged_input = d.m_for_merged_input;
|
||||
|
||||
m_start = d.m_start;
|
||||
m_stop = d.m_stop;
|
||||
|
||||
|
|
@ -80,6 +82,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
m_cells = d.m_cells;
|
||||
m_local_complex_region_stack = d.m_local_complex_region_stack;
|
||||
m_local_region_stack = d.m_local_region_stack;
|
||||
m_skip_shapes_stack = d.m_skip_shapes_stack;
|
||||
m_needs_reinit = d.m_needs_reinit;
|
||||
m_inst_quad_id = d.m_inst_quad_id;
|
||||
m_inst_quad_id_stack = d.m_inst_quad_id_stack;
|
||||
|
|
@ -99,6 +102,7 @@ RecursiveShapeIterator::RecursiveShapeIterator ()
|
|||
mp_cell = 0;
|
||||
m_current_layer = 0;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = false;
|
||||
m_max_depth = std::numeric_limits<int>::max (); // all
|
||||
m_min_depth = 0;
|
||||
m_shape_flags = shape_iterator::All;
|
||||
|
|
@ -116,6 +120,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes)
|
|||
mp_shapes = &shapes;
|
||||
mp_top_cell = 0;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = false;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
|
@ -127,6 +132,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
|
|||
mp_shapes = &shapes;
|
||||
mp_top_cell = 0;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = false;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
|
@ -138,11 +144,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
|
|||
mp_shapes = &shapes;
|
||||
mp_top_cell = 0;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = false;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout, layer)
|
||||
{
|
||||
m_layer = layer;
|
||||
|
|
@ -151,11 +158,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout, layer)
|
||||
{
|
||||
m_layer = layer;
|
||||
|
|
@ -164,11 +172,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input)
|
||||
: m_box_convert (layout, layer)
|
||||
{
|
||||
m_layer = layer;
|
||||
|
|
@ -177,11 +186,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -191,11 +201,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -205,11 +216,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -219,11 +231,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -233,11 +246,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -247,11 +261,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -261,6 +276,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
|
@ -447,6 +463,8 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
m_local_region_stack.clear ();
|
||||
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
|
||||
m_skip_shapes_stack.clear ();
|
||||
m_skip_shapes_stack.push_back (false);
|
||||
|
||||
m_local_complex_region_stack.clear ();
|
||||
if (mp_complex_region.get ()) {
|
||||
|
|
@ -723,11 +741,21 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
if (is_empty) {
|
||||
|
||||
// skip entire cell
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
|
||||
} else {
|
||||
down (receiver);
|
||||
} else if (!down (receiver)) {
|
||||
|
||||
// skip this instance array member
|
||||
++m_inst_array;
|
||||
new_inst_member (receiver);
|
||||
|
||||
if (m_inst_array.at_end ()) {
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -755,9 +783,42 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
bool skip_shapes = false;
|
||||
|
||||
if (m_for_merged_input && ! m_skip_shapes_stack.back () && (! m_has_layers || m_layers.size () == 1)) {
|
||||
|
||||
// Try some optimization: if the instance we're looking at is entirely covered
|
||||
// by a rectangle (other objects are too expensive to check), then we skip it
|
||||
//
|
||||
// We check 10 shapes max.
|
||||
|
||||
box_type inst_bx;
|
||||
if (m_inst->size () == 1) {
|
||||
inst_bx = m_inst->bbox (m_box_convert);
|
||||
} else {
|
||||
inst_bx = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ());
|
||||
}
|
||||
|
||||
unsigned int l = m_has_layers ? m_layers.front () : m_layer;
|
||||
auto si = cell ()->shapes (l).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
size_t nmax = 10;
|
||||
while (! si.at_end () && nmax-- > 0) {
|
||||
if (inst_bx.inside (si->rectangle ())) {
|
||||
skip_shapes = true;
|
||||
break;
|
||||
}
|
||||
++si;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (skip_shapes && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tl_assert (mp_layout);
|
||||
|
||||
m_trans_stack.push_back (m_trans);
|
||||
|
|
@ -779,11 +840,13 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
box_type new_region = box_type::world ();
|
||||
|
||||
// compute the region inside the new cell
|
||||
if (new_region != m_region) {
|
||||
new_region = m_trans.inverted () * m_region;
|
||||
if (new_region != m_local_region_stack.back ()) {
|
||||
new_region = m_inst->complex_trans (*m_inst_array).inverted () * m_local_region_stack.back ();
|
||||
new_region &= cell_bbox (cell_index ());
|
||||
}
|
||||
|
||||
m_local_region_stack.push_back (new_region);
|
||||
m_skip_shapes_stack.push_back (m_skip_shapes_stack.back () || skip_shapes);
|
||||
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
|
||||
|
|
@ -817,11 +880,25 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
}
|
||||
|
||||
if (receiver) {
|
||||
receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
|
||||
}
|
||||
// do not descend if the box is empty
|
||||
|
||||
new_cell (receiver);
|
||||
if (m_local_region_stack.back ().empty ()) {
|
||||
|
||||
pop ();
|
||||
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
if (receiver) {
|
||||
receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
|
||||
}
|
||||
|
||||
new_cell (receiver);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -831,6 +908,12 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
|
|||
receiver->leave_cell (this, cell ());
|
||||
}
|
||||
|
||||
pop ();
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::pop () const
|
||||
{
|
||||
m_shape = shape_iterator ();
|
||||
m_shape_quad_id = 0;
|
||||
|
||||
|
|
@ -846,6 +929,7 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
|
|||
mp_cell = m_cells.back ();
|
||||
m_cells.pop_back ();
|
||||
m_local_region_stack.pop_back ();
|
||||
m_skip_shapes_stack.pop_back ();
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
m_local_complex_region_stack.pop_back ();
|
||||
}
|
||||
|
|
@ -870,7 +954,7 @@ RecursiveShapeIterator::start_shapes () const
|
|||
void
|
||||
RecursiveShapeIterator::new_layer () const
|
||||
{
|
||||
if (int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
if (m_skip_shapes_stack.back () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
m_shape = shape_iterator ();
|
||||
} else if (! m_overlapping) {
|
||||
m_shape = cell ()->shapes (m_layer).begin_touching (m_local_region_stack.back (), m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
|
|
@ -901,12 +985,16 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
new_layer ();
|
||||
|
||||
m_inst = cell ()->begin_touching (m_local_region_stack.back ());
|
||||
if (m_overlapping) {
|
||||
m_inst = cell ()->begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1)));
|
||||
} else {
|
||||
m_inst = cell ()->begin_touching (m_local_region_stack.back ());
|
||||
}
|
||||
|
||||
m_inst_quad_id = 0;
|
||||
|
||||
// skip instance quad if possible
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
skip_inst_iter_for_complex_region ();
|
||||
}
|
||||
|
||||
|
|
@ -922,7 +1010,7 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
|||
while (! m_inst.at_end ()) {
|
||||
|
||||
// skip instance quad if possible
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
skip_inst_iter_for_complex_region ();
|
||||
if (m_inst.at_end ()) {
|
||||
break;
|
||||
|
|
@ -950,7 +1038,11 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
|||
// a singular iterator
|
||||
m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false);
|
||||
} else if (with_region) {
|
||||
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
|
||||
if (m_overlapping) {
|
||||
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1)), m_box_convert);
|
||||
} else {
|
||||
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
|
||||
}
|
||||
} else {
|
||||
m_inst_array = m_inst->cell_inst ().begin ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,12 +122,13 @@ public:
|
|||
* @param layer The layer from which to deliver the shapes
|
||||
* @param region The region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor
|
||||
|
|
@ -137,13 +138,14 @@ public:
|
|||
* @param layer The layer from which to deliver the shapes
|
||||
* @param region The complex region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit. It allows specification of a complex
|
||||
* search region.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor for "world" iteration
|
||||
|
|
@ -153,8 +155,9 @@ public:
|
|||
* @param layout The layout from which to get the cell hierarchy
|
||||
* @param cell The starting cell
|
||||
* @param layer The layer from which to deliver the shapes
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -164,12 +167,13 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -179,13 +183,14 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The complex region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit. It allows specification of a complex
|
||||
* search region.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -195,12 +200,13 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -210,13 +216,14 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The complex region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit. It allows specification of a complex
|
||||
* search region.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor for "world" iteration with a layer set
|
||||
|
|
@ -226,8 +233,9 @@ public:
|
|||
* @param layout The layout from which to get the cell hierarchy
|
||||
* @param cell The starting cell
|
||||
* @param layers The layers from which to deliver the shapes
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor for "world" iteration with a layer set
|
||||
|
|
@ -237,8 +245,9 @@ public:
|
|||
* @param layout The layout from which to get the cell hierarchy
|
||||
* @param cell The starting cell
|
||||
* @param layers The layers from which to deliver the shapes
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -427,6 +436,25 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether optimizing for merged input
|
||||
*/
|
||||
bool for_merged_input () const
|
||||
{
|
||||
return m_for_merged_input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether optimizing for merged input
|
||||
*/
|
||||
void set_for_merged_input (bool f)
|
||||
{
|
||||
if (m_for_merged_input != f) {
|
||||
m_for_merged_input = f;
|
||||
m_needs_reinit = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a global transformation
|
||||
*
|
||||
|
|
@ -812,7 +840,7 @@ private:
|
|||
unsigned int m_shape_flags;
|
||||
const shape_iterator::property_selector *mp_shape_prop_sel;
|
||||
bool m_shape_inv_prop_sel;
|
||||
bool m_overlapping;
|
||||
bool m_overlapping, m_for_merged_input;
|
||||
std::set<db::cell_index_type> m_start, m_stop;
|
||||
cplx_trans_type m_global_trans;
|
||||
db::PropertiesTranslator m_property_translator;
|
||||
|
|
@ -839,6 +867,7 @@ private:
|
|||
mutable std::vector<const cell_type *> m_cells;
|
||||
mutable std::vector<box_tree_type> m_local_complex_region_stack;
|
||||
mutable std::vector<box_type> m_local_region_stack;
|
||||
mutable std::vector<bool> m_skip_shapes_stack;
|
||||
mutable bool m_needs_reinit;
|
||||
mutable size_t m_inst_quad_id;
|
||||
mutable std::vector<size_t> m_inst_quad_id_stack;
|
||||
|
|
@ -858,7 +887,8 @@ private:
|
|||
void new_cell (RecursiveShapeReceiver *receiver) const;
|
||||
void new_layer () const;
|
||||
void up (RecursiveShapeReceiver *receiver) const;
|
||||
void down (RecursiveShapeReceiver *receiver) const;
|
||||
bool down (RecursiveShapeReceiver *receiver) const;
|
||||
void pop () const;
|
||||
|
||||
bool is_outside_complex_region (const db::Box &box) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
#include "dbFlatEdges.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "dbCompoundOperation.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
// NOTE: include this to provide the symbols for "make_variant"
|
||||
|
|
@ -74,14 +77,42 @@ Region &Region::operator= (const Region &other)
|
|||
return *this;
|
||||
}
|
||||
|
||||
Region::Region (const RecursiveShapeIterator &si)
|
||||
Region::Region (const RecursiveShapeIterator &si, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
mp_delegate = new OriginalLayerRegion (si);
|
||||
mp_delegate = new OriginalLayerRegion (si, db::ICplxTrans (), merged_semantics, is_merged);
|
||||
}
|
||||
|
||||
Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics)
|
||||
Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics);
|
||||
mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics, is_merged);
|
||||
}
|
||||
|
||||
Region::Region (const Shapes &shapes, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
db::FlatRegion *flat_region = new FlatRegion (is_merged);
|
||||
flat_region->reserve (shapes.size (db::ShapeIterator::Regions));
|
||||
|
||||
// NOTE: we need to normalize the shapes to polygons because this is what the flat region expects
|
||||
for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) {
|
||||
flat_region->insert (*s);
|
||||
}
|
||||
|
||||
mp_delegate = flat_region;
|
||||
mp_delegate->set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
||||
Region::Region (const Shapes &shapes, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
db::FlatRegion *flat_region = new FlatRegion (is_merged);
|
||||
flat_region->reserve (shapes.size (db::ShapeIterator::Regions));
|
||||
|
||||
// NOTE: we need to normalize the shapes to polygons because this is what the flat region expects
|
||||
for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) {
|
||||
flat_region->insert (*s, trans);
|
||||
}
|
||||
|
||||
mp_delegate = flat_region;
|
||||
mp_delegate->set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
||||
Region::Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
|
|
@ -101,6 +132,23 @@ Region::Region (DeepShapeStore &dss)
|
|||
mp_delegate = new db::DeepRegion (db::DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||
}
|
||||
|
||||
void
|
||||
Region::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("REGION"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator &
|
||||
Region::iter () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ public:
|
|||
* Creates a region from a recursive shape iterator. This allows feeding a region
|
||||
* from a hierarchy of cells.
|
||||
*/
|
||||
explicit Region (const RecursiveShapeIterator &si);
|
||||
explicit Region (const RecursiveShapeIterator &si, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator with a transformation
|
||||
|
|
@ -208,7 +208,23 @@ public:
|
|||
* from a hierarchy of cells. The transformation is useful to scale to a specific
|
||||
* DBU for example.
|
||||
*/
|
||||
explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true);
|
||||
explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a Shapes container
|
||||
*
|
||||
* Creates a region from a shapes container.
|
||||
*/
|
||||
explicit Region (const Shapes &si, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a Shapes container with a transformation
|
||||
*
|
||||
* Creates a region from a recursive shape iterator. This allows feeding a region
|
||||
* from a hierarchy of cells. The transformation is useful to scale to a specific
|
||||
* DBU for example.
|
||||
*/
|
||||
explicit Region (const Shapes &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator providing a deep representation
|
||||
|
|
@ -232,6 +248,14 @@ public:
|
|||
*/
|
||||
explicit Region (DeepShapeStore &dss);
|
||||
|
||||
/**
|
||||
* @brief Writes the region to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -807,6 +807,61 @@ Shape::box_type Shape::bbox () const
|
|||
}
|
||||
}
|
||||
|
||||
Shape::box_type Shape::rectangle () const
|
||||
{
|
||||
if (is_box ()) {
|
||||
return box ();
|
||||
}
|
||||
|
||||
switch (m_type) {
|
||||
case db::Shape::Polygon:
|
||||
return polygon ().is_box () ? polygon ().box () : box_type ();
|
||||
case db::Shape::PolygonRef:
|
||||
case db::Shape::PolygonPtrArrayMember:
|
||||
return polygon_ref ().is_box () ? polygon_ref ().box () : box_type ();
|
||||
case db::Shape::SimplePolygon:
|
||||
return simple_polygon ().is_box () ? simple_polygon ().box () : box_type ();
|
||||
case db::Shape::SimplePolygonRef:
|
||||
case db::Shape::SimplePolygonPtrArrayMember:
|
||||
return simple_polygon_ref ().is_box () ? simple_polygon_ref ().box () : box_type ();
|
||||
case db::Shape::Path:
|
||||
{
|
||||
const path_type &p = path ();
|
||||
if (! p.round () && p.points () <= 2 && p.points () > 0) {
|
||||
point_type p1 = *p.begin ();
|
||||
point_type p2 = p1;
|
||||
if (p.points () == 2) {
|
||||
p2 = *++p.begin ();
|
||||
}
|
||||
if (p1.x () == p2.x () || p1.y () == p2.y ()) {
|
||||
return p.box ();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case db::Shape::PathRef:
|
||||
case db::Shape::PathPtrArrayMember:
|
||||
{
|
||||
const path_ref_type &p = path_ref ();
|
||||
if (! p.ptr ()->round () && p.ptr ()->points () <= 2 && p.ptr ()->points () > 0) {
|
||||
point_type p1 = *p.begin ();
|
||||
point_type p2 = p1;
|
||||
if (p.ptr ()->points () == 2) {
|
||||
p2 = *++p.begin ();
|
||||
}
|
||||
if (p1.x () == p2.x () || p1.y () == p2.y ()) {
|
||||
return p.box ();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return box_type ();
|
||||
}
|
||||
|
||||
std::string
|
||||
Shape::to_string () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2651,6 +2651,16 @@ public:
|
|||
*/
|
||||
box_type bbox () const;
|
||||
|
||||
/**
|
||||
* @brief Returns the box if the object represents a rectangle or an empty box if not
|
||||
*
|
||||
* This method returns the rectangle (aka box) the shape represents a polygon
|
||||
* that is a rectangle, a path with two points and no rounded ends or an actual box.
|
||||
*
|
||||
* If not, an empty box is returned.
|
||||
*/
|
||||
box_type rectangle () const;
|
||||
|
||||
/**
|
||||
* @brief Compute the area of the shape
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -53,6 +53,12 @@ ShapeProcessor::reserve (size_t n)
|
|||
m_processor.reserve (n);
|
||||
}
|
||||
|
||||
size_t
|
||||
ShapeProcessor::count () const
|
||||
{
|
||||
return m_processor.count ();
|
||||
}
|
||||
|
||||
void
|
||||
ShapeProcessor::process (db::EdgeSink &es, EdgeEvaluatorBase &op)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -196,6 +196,11 @@ public:
|
|||
*/
|
||||
void reserve (size_t n);
|
||||
|
||||
/**
|
||||
* @brief Reports the number of edges stored in the processor
|
||||
*/
|
||||
size_t count () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the base verbosity of the processor (see EdgeProcessor::set_base_verbosity for details)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -30,6 +30,42 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Implementation of StreamFormatDeclaration
|
||||
|
||||
std::string StreamFormatDeclaration::all_formats_string ()
|
||||
{
|
||||
std::string fmts = tl::to_string (tr ("All layout files ("));
|
||||
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
|
||||
if (rdr != tl::Registrar<db::StreamFormatDeclaration>::begin ()) {
|
||||
fmts += " ";
|
||||
}
|
||||
std::string f = rdr->file_format ();
|
||||
if (!f.empty ()) {
|
||||
const char *fp = f.c_str ();
|
||||
while (*fp && *fp != '(') {
|
||||
++fp;
|
||||
}
|
||||
if (*fp) {
|
||||
++fp;
|
||||
}
|
||||
while (*fp && *fp != ')') {
|
||||
fmts += *fp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fmts += ")";
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
|
||||
if (!rdr->file_format ().empty ()) {
|
||||
fmts += ";;";
|
||||
fmts += rdr->file_format ();
|
||||
}
|
||||
}
|
||||
|
||||
return fmts;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Implementation of load_options_xml_element_list
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,11 @@ public:
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a string for the file dialogs that describes all formats
|
||||
*/
|
||||
static std::string all_formats_string ();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -347,12 +347,10 @@ Technology::get_display_string () const
|
|||
return d;
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
Technology::default_grid_list () const
|
||||
static void
|
||||
parse_default_grids (const std::string &s, std::vector<double> &grids, double &default_grid)
|
||||
{
|
||||
tl::Extractor ex (m_default_grids.c_str ());
|
||||
|
||||
std::vector<double> grids;
|
||||
tl::Extractor ex (s.c_str ());
|
||||
|
||||
// convert the list of grids to a list of doubles
|
||||
while (! ex.at_end ()) {
|
||||
|
|
@ -361,12 +359,32 @@ Technology::default_grid_list () const
|
|||
break;
|
||||
}
|
||||
grids.push_back (g);
|
||||
if (ex.test ("!")) {
|
||||
default_grid = g;
|
||||
}
|
||||
ex.test (",");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
Technology::default_grid_list () const
|
||||
{
|
||||
std::vector<double> grids;
|
||||
double default_grid = 0.0;
|
||||
parse_default_grids (m_default_grids, grids, default_grid);
|
||||
return grids;
|
||||
}
|
||||
|
||||
double
|
||||
Technology::default_grid () const
|
||||
{
|
||||
std::vector<double> grids;
|
||||
double default_grid = 0.0;
|
||||
parse_default_grids (m_default_grids, grids, default_grid);
|
||||
return default_grid;
|
||||
}
|
||||
|
||||
|
||||
tl::XMLElementList
|
||||
Technology::xml_elements ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -480,6 +480,15 @@ public:
|
|||
*/
|
||||
std::vector<double> default_grid_list () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the default grid (strong grid), parsed from the list
|
||||
*
|
||||
* The default grid is the one marked with an exclamation mark in the
|
||||
* grid list (e.g. "0.01!,0.02,0.05"). If there is not such default
|
||||
* grid, this method returns zero.
|
||||
*/
|
||||
double default_grid () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the default default grids
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@
|
|||
#include "dbOriginalLayerTexts.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlVariant.h"
|
||||
|
||||
#include <sstream>
|
||||
|
|
@ -90,6 +92,23 @@ Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::I
|
|||
mp_delegate = new DeepTexts (si, dss, trans);
|
||||
}
|
||||
|
||||
void
|
||||
Texts::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("TEXTS"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
template <class Sh>
|
||||
void Texts::insert (const Sh &shape)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -181,6 +181,14 @@ public:
|
|||
*/
|
||||
explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Writes the text collection to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -324,6 +324,21 @@ struct box_defs
|
|||
"\n"
|
||||
"@return The joined box\n"
|
||||
) +
|
||||
method ("-", &C::subtracted, gsi::arg ("box"),
|
||||
"@brief Subtraction of boxes\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The - operator subtracts the argument box from self.\n"
|
||||
"This will return the bounding box of the are covered by self, but not by argument box. "
|
||||
"Subtracting a box from itself will render an empty box. Subtracting another box from "
|
||||
"self will modify the first box only if the argument box covers one side entirely.\n"
|
||||
"\n"
|
||||
"@param box The box to subtract from this box.\n"
|
||||
"\n"
|
||||
"@return The result box\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.29."
|
||||
) +
|
||||
method ("&", &C::intersection, gsi::arg ("box"),
|
||||
"@brief Returns the intersection of this box with another box\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -602,6 +602,12 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
"\n"
|
||||
"This constructor has been introduced in version 0.26."
|
||||
) +
|
||||
method ("write", &db::EdgePairs::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
method ("insert_into", &db::EdgePairs::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
|
||||
"@brief Inserts this edge pairs into the given layout, below the given cell and into the given layer.\n"
|
||||
"If the edge pair collection is a hierarchical one, a suitable hierarchy will be built below the top cell or "
|
||||
|
|
|
|||
|
|
@ -1567,6 +1567,12 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"\n"
|
||||
"This method has been added in version 0.28.\n"
|
||||
) +
|
||||
method ("write", &db::Edges::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
method ("clear", &db::Edges::clear,
|
||||
"@brief Clears the edge collection\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -476,13 +476,29 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("region"),
|
||||
gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether overlapping shapes are selected when a region is used\n"
|
||||
"\n"
|
||||
"If this flag is false, shapes touching the search region are returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("for_merged_input?", &db::RecursiveShapeIterator::for_merged_input,
|
||||
"@brief Gets a flag indicating whether iterator optimizes for merged input\n"
|
||||
"\n"
|
||||
"see \\for_merged_input= for details of this attribute.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("for_merged_input=", &db::RecursiveShapeIterator::set_for_merged_input, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether iterator optimizes for merged input\n"
|
||||
"\n"
|
||||
"If this flag is set to true, the iterator is allowed to skip shapes it deems irrelevant "
|
||||
"because they are covered entirely by other shapes. This allows shortcutting hierarchy traversal in "
|
||||
"some cases.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("unselect_all_cells", &db::RecursiveShapeIterator::unselect_all_cells,
|
||||
"@brief Unselects all cells.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -270,15 +270,6 @@ static db::Region *new_path (const db::Path &o)
|
|||
return new db::Region (o);
|
||||
}
|
||||
|
||||
static db::Region *new_shapes (const db::Shapes &s)
|
||||
{
|
||||
db::Region *r = new db::Region ();
|
||||
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::All); !i.at_end (); ++i) {
|
||||
r->insert (*i);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static db::Region *new_texts_as_boxes1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern, db::Coord enl)
|
||||
{
|
||||
return new db::Region (db::Region (si).texts_as_boxes (pat, pattern, enl));
|
||||
|
|
@ -329,16 +320,26 @@ static db::Region *new_si (const db::RecursiveShapeIterator &si)
|
|||
return new db::Region (si);
|
||||
}
|
||||
|
||||
static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
{
|
||||
return new db::Region (si, dss, area_ratio, max_vertex_count);
|
||||
}
|
||||
|
||||
static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
return new db::Region (si, trans);
|
||||
}
|
||||
|
||||
static db::Region *new_sis (const db::Shapes &si)
|
||||
{
|
||||
return new db::Region (si);
|
||||
}
|
||||
|
||||
static db::Region *new_sis2 (const db::Shapes &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
return new db::Region (si, trans);
|
||||
}
|
||||
|
||||
static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
{
|
||||
return new db::Region (si, dss, area_ratio, max_vertex_count);
|
||||
}
|
||||
|
||||
static db::Region *new_sid2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const db::ICplxTrans &trans, double area_ratio, size_t max_vertex_count)
|
||||
{
|
||||
return new db::Region (si, dss, trans, true, area_ratio, max_vertex_count);
|
||||
|
|
@ -1088,13 +1089,6 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This constructor creates a region from a path.\n"
|
||||
) +
|
||||
constructor ("new", &new_shapes, gsi::arg ("shapes"),
|
||||
"@brief Shapes constructor\n"
|
||||
"\n"
|
||||
"This constructor creates a region from a \\Shapes collection.\n"
|
||||
"\n"
|
||||
"This constructor has been introduced in version 0.25."
|
||||
) +
|
||||
constructor ("new", &new_si, gsi::arg ("shape_iterator"),
|
||||
"@brief Constructor from a hierarchical shape set\n"
|
||||
"\n"
|
||||
|
|
@ -1126,6 +1120,24 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
constructor ("new", &new_sis, gsi::arg ("shapes"),
|
||||
"@brief Constructor from a shapes container\n"
|
||||
"\n"
|
||||
"This constructor creates a region from the shapes container.\n"
|
||||
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
|
||||
"This method allows feeding the shapes from a hierarchy of cells into the region.\n"
|
||||
"\n"
|
||||
"This constructor has been introduced in version 0.25 and extended in version 0.29."
|
||||
) +
|
||||
constructor ("new", &new_sis2, gsi::arg ("shapes"), gsi::arg ("trans"),
|
||||
"@brief Constructor from a shapes container with a transformation\n"
|
||||
"\n"
|
||||
"This constructor creates a region from the shapes container after applying the transformation.\n"
|
||||
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
|
||||
"This method allows feeding the shapes from a hierarchy of cells into the region.\n"
|
||||
"\n"
|
||||
"This constructor variant has been introduced in version 0.29."
|
||||
) +
|
||||
constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("deep_shape_store"), gsi::arg ("area_ratio", 0.0), gsi::arg ("max_vertex_count", size_t (0)),
|
||||
"@brief Constructor for a deep region from a hierarchical shape set\n"
|
||||
"\n"
|
||||
|
|
@ -1209,6 +1221,12 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.26."
|
||||
) +
|
||||
method ("write", &db::Region::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
factory_ext ("texts", &texts_as_boxes1, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true), gsi::arg ("enl", 1),
|
||||
"@hide\n"
|
||||
"This method is provided for DRC implementation only."
|
||||
|
|
|
|||
|
|
@ -669,6 +669,26 @@ static tl::Variant get_dbox (const db::Shape *s)
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_rectangle (const db::Shape *s)
|
||||
{
|
||||
db::Shape::box_type b = s->rectangle ();
|
||||
if (! b.empty ()) {
|
||||
return tl::Variant (b);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_drectangle (const db::Shape *s)
|
||||
{
|
||||
db::Shape::box_type b = s->rectangle ();
|
||||
if (! b.empty ()) {
|
||||
return tl::Variant (db::CplxTrans (shape_dbu (s)) * b);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_edge (const db::Shape *s)
|
||||
{
|
||||
db::Shape::edge_type p;
|
||||
|
|
@ -1982,6 +2002,22 @@ Class<db::Shape> decl_Shape ("db", "Shape",
|
|||
"\n"
|
||||
"This method has been added in version 0.25.\n"
|
||||
) +
|
||||
gsi::method_ext ("rectangle", &get_rectangle,
|
||||
"@brief Gets the rectangle if the object represents one or nil if not\n"
|
||||
"\n"
|
||||
"If the shape represents a rectangle - i.e. a box or box polygon, a path with two points and no round ends - "
|
||||
"this method returns the box. If not, nil is returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method_ext ("drectangle", &get_drectangle,
|
||||
"@brief Gets the rectangle in micron units if the object represents one or nil if not\n"
|
||||
"\n"
|
||||
"If the shape represents a rectangle - i.e. a box or box polygon, a path with two points and no round ends - "
|
||||
"this method returns the box. If not, nil is returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("is_user_object?", &db::Shape::is_user_object,
|
||||
"@brief Returns true if the shape is a user defined object\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ gsi::Class<db::TechnologyComponent> technology_component_decl ("db", "Technology
|
|||
DB_PUBLIC gsi::Class<db::TechnologyComponent> &decl_dbTechnologyComponent () { return technology_component_decl; }
|
||||
|
||||
static void
|
||||
set_default_grid_list (db::Technology *tech, const std::vector<double> &grids)
|
||||
set_default_grid_list2 (db::Technology *tech, const std::vector<double> &grids, double default_grid)
|
||||
{
|
||||
std::string r;
|
||||
for (auto g = grids.begin (); g != grids.end (); ++g) {
|
||||
|
|
@ -144,10 +144,19 @@ set_default_grid_list (db::Technology *tech, const std::vector<double> &grids)
|
|||
r += ",";
|
||||
}
|
||||
r += tl::micron_to_string (*g);
|
||||
if (db::coord_traits<db::DCoord>::equals (*g, default_grid)) {
|
||||
r += "!";
|
||||
}
|
||||
}
|
||||
tech->set_default_grids (r);
|
||||
}
|
||||
|
||||
static void
|
||||
set_default_grid_list (db::Technology *tech, const std::vector<double> &grids)
|
||||
{
|
||||
set_default_grid_list2 (tech, grids, 0.0);
|
||||
}
|
||||
|
||||
gsi::Class<db::Technology> technology_decl ("db", "Technology",
|
||||
gsi::method ("name", &db::Technology::name,
|
||||
"@brief Gets the name of the technology"
|
||||
|
|
@ -238,12 +247,32 @@ gsi::Class<db::Technology> technology_decl ("db", "Technology",
|
|||
"\n"
|
||||
"This property has been introduced in version 0.28.17."
|
||||
) +
|
||||
gsi::method ("default_grid", &db::Technology::default_grid,
|
||||
"@brief Gets the default grid\n"
|
||||
"\n"
|
||||
"The default grid is a specific one from the default grid list.\n"
|
||||
"It indicates the one that is taken if the current grid is not matching one of "
|
||||
"the default grids.\n"
|
||||
"\n"
|
||||
"To set the default grid, use \\set_default_grids.\n"
|
||||
"\n"
|
||||
"This property has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method_ext ("default_grids=", &set_default_grid_list, gsi::arg ("grids"),
|
||||
"@brief Sets the default grids\n"
|
||||
"If not empty, this list replaces the global grid list for this technology.\n"
|
||||
"Note that this method will reset the default grid (see \\default_grid). Use "
|
||||
"\\set_default_grids to set the default grids and the strong default one.\n"
|
||||
"\n"
|
||||
"This property has been introduced in version 0.28.17."
|
||||
) +
|
||||
gsi::method_ext ("set_default_grids", &set_default_grid_list2, gsi::arg ("grids"), gsi::arg ("default_grid", 0.0),
|
||||
"@brief Sets the default grids and the strong default one\n"
|
||||
"See \\default_grids and \\default_grid for a description of this property.\n"
|
||||
"Note that the default grid has to be a member of the 'grids' array to become active.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("layer_properties_file", &db::Technology::layer_properties_file,
|
||||
"@brief Gets the path of the layer properties file\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -436,6 +436,12 @@ Class<db::Texts> decl_Texts (decl_dbShapeCollection, "db", "Texts",
|
|||
"r = RBA::Texts::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
method ("write", &db::Texts::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
method ("insert_into", &db::Texts::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
|
||||
"@brief Inserts this texts into the given layout, below the given cell and into the given layer.\n"
|
||||
"If the text collection is a hierarchical one, a suitable hierarchy will be built below the top cell or "
|
||||
|
|
|
|||
|
|
@ -49,6 +49,17 @@ TEST(2)
|
|||
EXPECT_EQ (b & db::Box (110, 220, 120, 250), empty);
|
||||
EXPECT_EQ (b & db::Box (50, 100, 120, 250), db::Box (50, 100, 100, 200));
|
||||
EXPECT_EQ (b & db::Box (50, 100, 60, 120), db::Box (50, 100, 60, 120));
|
||||
EXPECT_EQ (b - b, db::Box ());
|
||||
EXPECT_EQ (b - db::Box (), b);
|
||||
EXPECT_EQ (db::Box () - b, db::Box ());
|
||||
EXPECT_EQ (db::Box () - db::Box (), db::Box ());
|
||||
EXPECT_EQ (b - db::Box (0, 0, 50, 50), b);
|
||||
EXPECT_EQ (b - db::Box (0, 0, 50, 200), db::Box (50, 0, 100, 200));
|
||||
EXPECT_EQ (b - db::Box (50, 0, 100, 200), db::Box (0, 0, 50, 200));
|
||||
EXPECT_EQ (b - db::Box (0, 0, 100, 100), db::Box (0, 100, 100, 200));
|
||||
EXPECT_EQ (b - db::Box (0, 100, 100, 200), db::Box (0, 0, 100, 100));
|
||||
EXPECT_EQ (db::Box::world () - b, db::Box::world ());
|
||||
EXPECT_EQ (b - db::Box::world (), db::Box ());
|
||||
|
||||
empty.move (db::Vector (10, 20));
|
||||
EXPECT_EQ (empty == db::Box (), true);
|
||||
|
|
|
|||
|
|
@ -1505,6 +1505,55 @@ TEST(22_InteractingWithCount)
|
|||
EXPECT_EQ (db::compare (e.selected_interacting_differential (r2, size_t (2), size_t(3)).second, "(0,0;200,0)"), true);
|
||||
}
|
||||
|
||||
TEST(23_SameInputs)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/deep_region_l1.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
|
||||
db::Edges e2 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss)).edges ());
|
||||
|
||||
EXPECT_EQ ((e2 & e2).to_string (), e2.to_string ());
|
||||
EXPECT_EQ ((e2 - e2).to_string (), "");
|
||||
EXPECT_EQ (e2.andnot (e2).first.to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.andnot (e2).second.to_string (), "");
|
||||
EXPECT_EQ ((e2 | e2).to_string (), e2.to_string ());
|
||||
EXPECT_EQ ((e2 ^ e2).to_string (), "");
|
||||
EXPECT_EQ (e2.in (e2).to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.in (e2, true).to_string (), "");
|
||||
EXPECT_EQ (e2.in_and_out (e2).first.to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.in_and_out (e2).second.to_string (), "");
|
||||
EXPECT_EQ (e2.selected_interacting (e2).to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.selected_not_interacting (e2).to_string (), "");
|
||||
EXPECT_EQ (e2.selected_interacting_differential (e2).first.to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.selected_interacting_differential (e2).second.to_string (), "");
|
||||
EXPECT_EQ ((e2.selected_interacting (e2, (size_t) 1, (size_t) 3) ^ e2).to_string (), "");
|
||||
EXPECT_EQ ((e2.selected_interacting_differential (e2, (size_t) 1, (size_t) 3).first ^ e2).to_string (), "");
|
||||
EXPECT_EQ (e2.selected_interacting_differential (e2, (size_t) 1, (size_t) 3).second.to_string (), "");
|
||||
EXPECT_EQ (e2.selected_interacting (e2, (size_t) 4).to_string (), "");
|
||||
EXPECT_EQ (e2.selected_interacting_differential (e2, (size_t) 4).first.to_string (), "");
|
||||
EXPECT_EQ ((e2.selected_interacting_differential (e2, (size_t) 4).second ^ e2).to_string (), "");
|
||||
EXPECT_EQ (e2.selected_inside (e2).to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.selected_not_inside (e2).to_string (), "");
|
||||
EXPECT_EQ (e2.selected_inside_differential (e2).first.to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.selected_inside_differential (e2).second.to_string (), "");
|
||||
EXPECT_EQ (e2.selected_outside (e2).to_string (), "");
|
||||
EXPECT_EQ (e2.selected_not_outside (e2).to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.selected_outside_differential (e2).first.to_string (), "");
|
||||
EXPECT_EQ (e2.selected_outside_differential (e2).second.to_string (), e2.to_string ());
|
||||
EXPECT_EQ (e2.pull_interacting (e2).to_string (), e2.to_string ());
|
||||
}
|
||||
|
||||
TEST(deep_edges_and_cheats)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2649,6 +2649,66 @@ TEST(101_DeepFlatCollaboration)
|
|||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au101.gds");
|
||||
}
|
||||
|
||||
TEST(102_SameInputs)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/deep_region_l1.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
|
||||
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ ((r2 & r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ ((r2 - r2).to_string (), "");
|
||||
EXPECT_EQ (r2.andnot (r2).first.to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.andnot (r2).second.to_string (), "");
|
||||
EXPECT_EQ ((r2 | r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ ((r2 ^ r2).to_string (), "");
|
||||
EXPECT_EQ (r2.in (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.in (r2, true).to_string (), "");
|
||||
EXPECT_EQ (r2.in_and_out (r2).first.to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.in_and_out (r2).second.to_string (), "");
|
||||
EXPECT_EQ (r2.selected_enclosing (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_not_enclosing (r2).to_string (), "");
|
||||
EXPECT_EQ (r2.selected_enclosing_differential (r2).first.to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_enclosing_differential (r2).second.to_string (), "");
|
||||
EXPECT_EQ (r2.selected_interacting (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_not_interacting (r2).to_string (), "");
|
||||
EXPECT_EQ (r2.selected_interacting_differential (r2).first.to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_interacting_differential (r2).second.to_string (), "");
|
||||
EXPECT_EQ (r2.selected_interacting (r2, (size_t) 1, (size_t) 2).to_string (), r2.merged ().to_string ());
|
||||
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 1, (size_t) 2).first.to_string (), r2.merged ().to_string ());
|
||||
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 1, (size_t) 2).second.to_string (), "");
|
||||
EXPECT_EQ (r2.selected_interacting (r2, (size_t) 2).to_string (), "");
|
||||
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 2).first.to_string (), "");
|
||||
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 2).second.to_string (), r2.merged ().to_string ());
|
||||
EXPECT_EQ (r2.selected_inside (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_not_inside (r2).to_string (), "");
|
||||
EXPECT_EQ (r2.selected_inside_differential (r2).first.to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_inside_differential (r2).second.to_string (), "");
|
||||
EXPECT_EQ (r2.selected_outside (r2).to_string (), "");
|
||||
EXPECT_EQ (r2.selected_not_outside (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_outside_differential (r2).first.to_string (), "");
|
||||
EXPECT_EQ (r2.selected_outside_differential (r2).second.to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_overlapping (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_not_overlapping (r2).to_string (), "");
|
||||
EXPECT_EQ (r2.selected_overlapping_differential (r2).first.to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.selected_overlapping_differential (r2).second.to_string (), "");
|
||||
EXPECT_EQ (r2.pull_inside (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.pull_overlapping (r2).to_string (), r2.to_string ());
|
||||
EXPECT_EQ (r2.pull_interacting (r2).to_string (), r2.to_string ());
|
||||
}
|
||||
|
||||
TEST(issue_277)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "dbHierProcessor.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbReader.h"
|
||||
|
|
@ -32,6 +33,9 @@
|
|||
#include "dbLocalOperationUtils.h"
|
||||
#include "dbRegionLocalOperations.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbRecursiveInstanceIterator.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
static std::string testdata (const std::string &fn)
|
||||
{
|
||||
|
|
@ -1284,3 +1288,87 @@ TEST(Arrays)
|
|||
run_test_bool2 (_this, "hlp18.oas", TMNot, 100);
|
||||
}
|
||||
|
||||
TEST(XORTool)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
||||
std::string fna (tl::combine_path (tl::testdata_private (), "xor/a.gds.gz"));
|
||||
std::string fnb (tl::combine_path (tl::testdata_private (), "xor/b.gds.gz"));
|
||||
std::string fn_au (tl::combine_path (tl::testdata_private (), "xor/xor_au.oas.gz"));
|
||||
|
||||
db::Layout lya, lyb;
|
||||
|
||||
unsigned int l1, l2;
|
||||
|
||||
db::LayerMap lmap;
|
||||
|
||||
lmap.map (db::LDPair (1, 0), l1 = lya.insert_layer ());
|
||||
lyb.insert_layer ();
|
||||
|
||||
lmap.map (db::LDPair (2, 0), l2 = lya.insert_layer ());
|
||||
lyb.insert_layer ();
|
||||
|
||||
{
|
||||
tl::InputStream stream (fna);
|
||||
db::Reader reader (stream);
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
reader.read (lya, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream stream (fnb);
|
||||
db::Reader reader (stream);
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
reader.read (lyb, options);
|
||||
}
|
||||
|
||||
db::Layout ly_out;
|
||||
db::cell_index_type top_out = ly_out.add_cell ("TOP");
|
||||
unsigned int l1_out = ly_out.insert_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2_out = ly_out.insert_layer (db::LayerProperties (2, 0));
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_wants_all_cells (true); // saves time for less cell mapping operations
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator ri_a, ri_b;
|
||||
|
||||
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l1);
|
||||
ri_a.set_for_merged_input (true);
|
||||
|
||||
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l1);
|
||||
ri_b.set_for_merged_input (true);
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
|
||||
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
|
||||
|
||||
db::Region xor_res = in_a ^ in_b;
|
||||
EXPECT_EQ (xor_res.count (), size_t (12));
|
||||
|
||||
xor_res.insert_into (&ly_out, top_out, l1_out);
|
||||
}
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator ri_a, ri_b;
|
||||
|
||||
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l2);
|
||||
ri_a.set_for_merged_input (true);
|
||||
|
||||
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l2);
|
||||
ri_b.set_for_merged_input (true);
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
|
||||
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
|
||||
|
||||
db::Region xor_res = in_a ^ in_b;
|
||||
EXPECT_EQ (xor_res.count (), size_t (15984));
|
||||
|
||||
xor_res.insert_into (&ly_out, top_out, l2_out);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, ly_out, fn_au, db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
#include "dbLayoutDiff.h"
|
||||
#include "tlString.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlStream.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbWriter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -1554,3 +1558,225 @@ TEST(11_LayoutIsWeakPointer)
|
|||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "");
|
||||
}
|
||||
|
||||
TEST(12_ForMerged)
|
||||
{
|
||||
std::unique_ptr<db::Layout> g (new db::Layout ());
|
||||
g->insert_layer (0);
|
||||
g->insert_layer (1);
|
||||
db::Cell &c0 (g->cell (g->add_cell ()));
|
||||
db::Cell &c1 (g->cell (g->add_cell ()));
|
||||
db::Cell &c2 (g->cell (g->add_cell ()));
|
||||
db::Cell &c3 (g->cell (g->add_cell ()));
|
||||
|
||||
db::Box b (0, 100, 1000, 1200);
|
||||
c0.shapes (0).insert (db::Box (0, 0, 3000, 2000));
|
||||
c1.shapes (0).insert (b);
|
||||
c2.shapes (0).insert (b);
|
||||
c3.shapes (0).insert (b);
|
||||
|
||||
db::Trans tt;
|
||||
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
|
||||
c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100))));
|
||||
c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1)));
|
||||
c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0))));
|
||||
|
||||
std::string x;
|
||||
|
||||
db::RecursiveShapeIterator i1 (*g, c0, 0);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
std::vector<unsigned int> lv;
|
||||
lv.push_back (0);
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, lv);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
lv.push_back (1); // empty, but kills "for merged" optimization
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, lv);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
// no longer optimized
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-100, 0, 100, 50));
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-101, 0, 100, 50));
|
||||
i1.set_overlapping (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
}
|
||||
|
||||
|
||||
TEST(13_ForMergedPerformance)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
||||
std::string fn (tl::combine_path (tl::testdata_private (), "oasis/caravel.oas.gz"));
|
||||
|
||||
db::Layout ly;
|
||||
|
||||
{
|
||||
tl::InputStream is (fn);
|
||||
db::Reader reader (is);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
unsigned l1 = ly.get_layer (db::LayerProperties (66, 20));
|
||||
unsigned l2 = ly.get_layer (db::LayerProperties (235, 4));
|
||||
|
||||
db::RecursiveShapeIterator si1 (ly, ly.cell (*ly.begin_top_down ()), l1);
|
||||
db::RecursiveShapeIterator si2 (ly, ly.cell (*ly.begin_top_down ()), l2);
|
||||
|
||||
size_t n1_expected_full = db::default_editable_mode () ? 1203072 : 1203078;
|
||||
size_t n2_expected_full = 10;
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (1218378));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (57462));
|
||||
}
|
||||
|
||||
si1.set_for_merged_input (true);
|
||||
si2.set_for_merged_input (true);
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (n1_expected_full));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (n2_expected_full));
|
||||
}
|
||||
|
||||
si1.set_for_merged_input (false);
|
||||
si1.set_region (db::Box (0, 0, 1000000, 1000000));
|
||||
si2.set_for_merged_input (false);
|
||||
si2.set_region (db::Box (0, 0, 1000000, 1000000));
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (218823));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (2578));
|
||||
}
|
||||
|
||||
si1.set_for_merged_input (true);
|
||||
si2.set_for_merged_input (true);
|
||||
|
||||
size_t n1_expected = db::default_editable_mode () ? 218068 : 218069;
|
||||
size_t n2_expected = 2;
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (n1_expected));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (n2_expected));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("XOR on tile of 66/20");
|
||||
si1.set_for_merged_input (false);
|
||||
db::Region r1 (si1);
|
||||
si1.set_for_merged_input (true);
|
||||
db::Region r2 (si1);
|
||||
|
||||
EXPECT_EQ (r1.count (), size_t (218823));
|
||||
EXPECT_EQ (r2.count (), size_t (n1_expected));
|
||||
EXPECT_EQ ((r1 ^ r2).count (), size_t (0));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("XOR on tile of 235/4");
|
||||
si2.set_for_merged_input (false);
|
||||
db::Region r1 (si2);
|
||||
si2.set_for_merged_input (true);
|
||||
db::Region r2 (si2);
|
||||
|
||||
EXPECT_EQ (r1.count (), size_t (2578));
|
||||
EXPECT_EQ (r2.count (), size_t (n2_expected));
|
||||
EXPECT_EQ ((r1 ^ r2).count (), size_t (0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2537,6 +2537,35 @@ TEST(55_PropertiesFilterFlat)
|
|||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
}
|
||||
|
||||
TEST(56_RegionsFromShapes)
|
||||
{
|
||||
db::Shapes shapes;
|
||||
|
||||
shapes.insert (db::Box (0, 0, 100, 200));
|
||||
shapes.insert (db::Box (50, 50, 150, 250));
|
||||
|
||||
EXPECT_EQ (db::Region (shapes).area (), 32500);
|
||||
EXPECT_EQ (db::Region (shapes, false).area (), 40000);
|
||||
EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5)).area (), 8125);
|
||||
EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5), false).area (), 10000);
|
||||
|
||||
// for cross-checking: same for RecursiveShapeIterator
|
||||
|
||||
db::Layout layout;
|
||||
unsigned int l1 = layout.insert_layer ();
|
||||
db::Cell &top = layout.cell (layout.add_cell ("TOP"));
|
||||
|
||||
top.shapes (l1).insert (db::Box (0, 0, 100, 200));
|
||||
top.shapes (l1).insert (db::Box (50, 50, 150, 250));
|
||||
|
||||
db::RecursiveShapeIterator si (layout, top, l1);
|
||||
|
||||
EXPECT_EQ (db::Region (si).area (), 32500);
|
||||
EXPECT_EQ (db::Region (si, false).area (), 40000);
|
||||
EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5)).area (), 8125);
|
||||
EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5), false).area (), 10000);
|
||||
}
|
||||
|
||||
TEST(100_Processors)
|
||||
{
|
||||
db::Region r;
|
||||
|
|
|
|||
|
|
@ -948,3 +948,89 @@ TEST(9)
|
|||
EXPECT_EQ (si.at_end (), true);
|
||||
}
|
||||
|
||||
// Rectangle
|
||||
TEST(10)
|
||||
{
|
||||
db::Manager m (true);
|
||||
db::Shapes s (&m, 0, db::default_editable_mode ());
|
||||
db::ShapeIterator si;
|
||||
|
||||
s.insert (db::Point (100, 200));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Edge (db::Point (100, 200), db::Point (200, 400)));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::EdgePair (db::Edge (db::Point (100, 200), db::Point (200, 400)), db::Edge (db::Point (0, 300), db::Point (100, 500))));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Box (0, 0, 1000, 2000));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::ShortBox (0, 0, 1000, 2000));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Polygon (db::Box (0, 0, 1000, 2000)));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Polygon ());
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::SimplePolygon ());
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path ());
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
db::Point pts1 [1] = { db::Point (0, 0) };
|
||||
db::Point pts2 [2] = { db::Point (0, 0), db::Point (1000, 0) };
|
||||
db::Point pts2b [2] = { db::Point (0, 0), db::Point (1000, 1000) };
|
||||
db::Point pts3 [3] = { db::Point (0, 0), db::Point (1000, 0), db::Point (1000, 1000) };
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts1 + 0, pts1 + 1, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (-500, -500, 500, 500));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts2 + 0, pts2 + 2, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (-500, -500, 1500, 500));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts2 + 0, pts2 + 2, 1000, 500, 500, true));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts2b + 0, pts2b + 2, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts3 + 0, pts3 + 3, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -353,9 +353,9 @@ TEST(11)
|
|||
EXPECT_EQ (x.try_read (tt2), true);
|
||||
EXPECT_EQ (x.test ("a"), true);
|
||||
EXPECT_EQ (tt2.to_string (), t2.to_string ());
|
||||
x = tl::Extractor ("m22.5 *0.55 12.4,-17 ++");
|
||||
x = tl::Extractor ("m22.5 *0.55 12.4,-17 ##");
|
||||
EXPECT_EQ (x.try_read (tt2), true);
|
||||
EXPECT_EQ (x.test ("++"), true);
|
||||
EXPECT_EQ (x.test ("##"), true);
|
||||
EXPECT_EQ (tt2.to_string (), "m22.5 *0.55 12.4,-17");
|
||||
EXPECT_EQ (tt2.to_string (), t3.to_string ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,67 +1,75 @@
|
|||
<ui version="4.0" >
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainConfigPage3</class>
|
||||
<widget class="QFrame" name="MainConfigPage3" >
|
||||
<property name="geometry" >
|
||||
<widget class="QFrame" name="MainConfigPage3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>475</width>
|
||||
<height>81</height>
|
||||
<width>504</width>
|
||||
<height>180</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<property name="windowTitle">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="margin" >
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox" >
|
||||
<property name="title" >
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Default Grids</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<layout class="QGridLayout">
|
||||
<property name="margin" stdset="0">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="spacing" >
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="textLabel1_4" >
|
||||
<property name="text" >
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="textLabel1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Grids for "View" menu</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="textLabel1_4">
|
||||
<property name="text">
|
||||
<string>µm (g1,g2,...)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="grids_edit" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>7</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="grids_edit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="textLabel1" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html>You can declare one grid a strong default to enforce an editing grid from this list. To do so, add an exclamation mark - e.g. "0.01!,0.02,0.05".
|
||||
<br/><b>Note</b>: the general default grids can be overridden by technology specific default grids.</html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Grids for "View" menu</string>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -70,7 +78,7 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>625</width>
|
||||
<height>587</height>
|
||||
<height>616</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -331,6 +331,9 @@ properties</string>
|
|||
<property name="text">
|
||||
<string>The default database unit is used as database unit for freshly created layouts</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="4">
|
||||
|
|
@ -352,7 +355,10 @@ properties</string>
|
|||
<item row="11" column="1" colspan="3">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>These grids are available for selection from the "View" menu</string>
|
||||
<string>These grids are available for selection from the "View" menu and will override the general ones. You can declare one grid as a strong default to enforce an editing grid from this list. To do so, add an exclamation mark to the grid - e.g. "0.01!,0.02,0.05".</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ CustomizeMenuConfigPage::commit (lay::Dispatcher *dispatcher)
|
|||
std::map<std::string, std::string>::iterator cb = m_current_bindings.find (kb->first);
|
||||
if (cb != m_current_bindings.end ()) {
|
||||
lay::Action *a = dispatcher->menu ()->action (kb->first);
|
||||
if (cb->second != a->get_default_shortcut ()) {
|
||||
if (a && cb->second != a->get_default_shortcut ()) {
|
||||
if (cb->second.empty ()) {
|
||||
kb->second = lay::Action::no_shortcut ();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -175,9 +175,11 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
|
|||
m_disable_tab_selected (false),
|
||||
m_exited (false),
|
||||
dm_do_update_menu (this, &MainWindow::do_update_menu),
|
||||
dm_do_update_grids (this, &MainWindow::do_update_grids),
|
||||
dm_do_update_mru_menus (this, &MainWindow::do_update_mru_menus),
|
||||
dm_exit (this, &MainWindow::exit),
|
||||
m_grid_micron (0.001),
|
||||
m_default_grid (0.0),
|
||||
m_default_grids_updated (true),
|
||||
m_new_layout_current_panel (false),
|
||||
m_synchronized_views (false),
|
||||
|
|
@ -498,34 +500,9 @@ MainWindow::~MainWindow ()
|
|||
std::string
|
||||
MainWindow::all_layout_file_formats () const
|
||||
{
|
||||
std::string fmts = tl::to_string (QObject::tr ("All layout files ("));
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
|
||||
if (rdr != tl::Registrar<db::StreamFormatDeclaration>::begin ()) {
|
||||
fmts += " ";
|
||||
}
|
||||
std::string f = rdr->file_format ();
|
||||
if (!f.empty ()) {
|
||||
const char *fp = f.c_str ();
|
||||
while (*fp && *fp != '(') {
|
||||
++fp;
|
||||
}
|
||||
if (*fp) {
|
||||
++fp;
|
||||
}
|
||||
while (*fp && *fp != ')') {
|
||||
fmts += *fp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fmts += ");;";
|
||||
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
|
||||
if (!rdr->file_format ().empty ()) {
|
||||
fmts += rdr->file_format ();
|
||||
fmts += ";;";
|
||||
}
|
||||
}
|
||||
fmts += tl::to_string (QObject::tr ("All files (*)"));
|
||||
|
||||
std::string fmts = db::StreamFormatDeclaration::all_formats_string ();
|
||||
fmts += ";;";
|
||||
fmts += tl::to_string (tr ("All files (*)"));
|
||||
return fmts;
|
||||
}
|
||||
|
||||
|
|
@ -583,7 +560,7 @@ MainWindow::technology_changed ()
|
|||
}
|
||||
|
||||
m_default_grids_updated = true; // potentially ...
|
||||
dm_do_update_menu ();
|
||||
dm_do_update_grids ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -939,7 +916,7 @@ MainWindow::config_finalize ()
|
|||
|
||||
// Update the default grids menu if necessary
|
||||
if (m_default_grids_updated) {
|
||||
dm_do_update_menu ();
|
||||
dm_do_update_grids ();
|
||||
}
|
||||
|
||||
// make the changes visible in the setup form if the form is visible
|
||||
|
|
@ -972,6 +949,7 @@ MainWindow::configure (const std::string &name, const std::string &value)
|
|||
|
||||
tl::Extractor ex (value.c_str ());
|
||||
m_default_grids.clear ();
|
||||
m_default_grid = 0.0;
|
||||
m_default_grids_updated = true;
|
||||
|
||||
// convert the list of grids to a list of doubles
|
||||
|
|
@ -980,6 +958,9 @@ MainWindow::configure (const std::string &name, const std::string &value)
|
|||
if (! ex.try_read (g)) {
|
||||
break;
|
||||
}
|
||||
if (ex.test ("!")) {
|
||||
m_default_grid = g;
|
||||
}
|
||||
m_default_grids.push_back (g);
|
||||
ex.test (",");
|
||||
}
|
||||
|
|
@ -4041,6 +4022,38 @@ MainWindow::menu_changed ()
|
|||
dm_do_update_menu ();
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::do_update_grids ()
|
||||
{
|
||||
const std::vector<double> *grids = &m_default_grids;
|
||||
double default_grid = m_default_grid;
|
||||
|
||||
std::vector<double> tech_grids;
|
||||
lay::TechnologyController *tc = lay::TechnologyController::instance ();
|
||||
if (tc && tc->active_technology ()) {
|
||||
tech_grids = tc->active_technology ()->default_grid_list ();
|
||||
if (! tech_grids.empty ()) {
|
||||
grids = &tech_grids;
|
||||
default_grid = tc->active_technology ()->default_grid ();
|
||||
}
|
||||
}
|
||||
|
||||
if (default_grid > db::epsilon) {
|
||||
for (auto g = grids->begin (); g != grids->end (); ++g) {
|
||||
if (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron)) {
|
||||
default_grid = 0.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (default_grid > db::epsilon) {
|
||||
dispatcher ()->config_set (cfg_grid, default_grid);
|
||||
}
|
||||
|
||||
do_update_menu ();
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::do_update_menu ()
|
||||
{
|
||||
|
|
@ -4082,7 +4095,7 @@ MainWindow::do_update_menu ()
|
|||
|
||||
lay::Action *ga = new lay::ConfigureAction (gs, cfg_grid, tl::to_string (*g));
|
||||
ga->set_checkable (true);
|
||||
ga->set_checked (fabs (*g - m_grid_micron) < 1e-10);
|
||||
ga->set_checked (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron));
|
||||
|
||||
for (std::vector<std::string>::const_iterator t = group.begin (); t != group.end (); ++t) {
|
||||
menu ()->insert_item (*t + ".end", name, ga);
|
||||
|
|
|
|||
|
|
@ -706,6 +706,7 @@ protected slots:
|
|||
protected:
|
||||
void update_content ();
|
||||
void do_update_menu ();
|
||||
void do_update_grids ();
|
||||
void do_update_mru_menus ();
|
||||
bool eventFilter (QObject *watched, QEvent *event);
|
||||
|
||||
|
|
@ -753,6 +754,7 @@ private:
|
|||
bool m_disable_tab_selected;
|
||||
bool m_exited;
|
||||
tl::DeferredMethod<MainWindow> dm_do_update_menu;
|
||||
tl::DeferredMethod<MainWindow> dm_do_update_grids;
|
||||
tl::DeferredMethod<MainWindow> dm_do_update_mru_menus;
|
||||
tl::DeferredMethod<MainWindow> dm_exit;
|
||||
QTimer m_message_timer;
|
||||
|
|
@ -765,6 +767,7 @@ private:
|
|||
std::string m_initial_technology;
|
||||
double m_grid_micron;
|
||||
std::vector<double> m_default_grids;
|
||||
double m_default_grid;
|
||||
bool m_default_grids_updated;
|
||||
std::vector<std::pair<std::string, std::string> > m_key_bindings;
|
||||
bool m_new_layout_current_panel;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "layConfigurationDialog.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbStream.h"
|
||||
|
||||
#include "ui_MarkerBrowserDialog.h"
|
||||
|
||||
|
|
@ -420,11 +421,17 @@ BEGIN_PROTECTED
|
|||
// collect the formats available ...
|
||||
std::string fmts = tl::to_string (QObject::tr ("All files (*)"));
|
||||
for (tl::Registrar<rdb::FormatDeclaration>::iterator rdr = tl::Registrar<rdb::FormatDeclaration>::begin (); rdr != tl::Registrar<rdb::FormatDeclaration>::end (); ++rdr) {
|
||||
fmts += ";;" + rdr->file_format ();
|
||||
fmts += ";;";
|
||||
fmts += rdr->file_format ();
|
||||
}
|
||||
|
||||
// also provide the stream formats
|
||||
fmts += ";;";
|
||||
fmts += db::StreamFormatDeclaration::all_formats_string ();
|
||||
|
||||
// prepare and open the file dialog
|
||||
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Load Marker Database File")), fmts);
|
||||
|
||||
if (open_dialog.get_open (m_open_filename)) {
|
||||
|
||||
std::unique_ptr <rdb::Database> db (new rdb::Database ());
|
||||
|
|
@ -731,111 +738,17 @@ MarkerBrowserDialog::deactivated ()
|
|||
void
|
||||
MarkerBrowserDialog::scan_layer ()
|
||||
{
|
||||
std::vector<lay::LayerPropertiesConstIterator> layers = view ()->selected_layers ();
|
||||
if (layers.empty ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("No layer selected to get shapes from")));
|
||||
}
|
||||
|
||||
int cv_index = -1;
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
if (!(*l)->has_children ()) {
|
||||
if (cv_index < 0) {
|
||||
cv_index = (*l)->cellview_index ();
|
||||
} else if ((*l)->cellview_index () >= 0) {
|
||||
if (cv_index != (*l)->cellview_index ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("All layers must originate from the same layout")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cv_index < 0) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected")));
|
||||
}
|
||||
|
||||
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Shapes To Markers")), 10000);
|
||||
progress.set_format (tl::to_string (QObject::tr ("%.0f0000 markers")));
|
||||
progress.set_unit (10000);
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (cv_index);
|
||||
const db::Layout &layout = cv->layout ();
|
||||
|
||||
std::unique_ptr<rdb::Database> rdb (new rdb::Database ());
|
||||
rdb->set_name ("Shapes");
|
||||
rdb->set_top_cell_name (layout.cell_name (cv.cell_index ()));
|
||||
rdb::Cell *rdb_top_cell = rdb->create_cell (rdb->top_cell_name ());
|
||||
|
||||
std::string desc;
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
|
||||
if (! desc.empty ()) {
|
||||
desc += ", ";
|
||||
}
|
||||
desc += layout.get_properties ((*l)->layer_index ()).to_string ();
|
||||
}
|
||||
}
|
||||
desc = tl::to_string (tr ("Hierarchical shapes of layer(s) ")) + desc;
|
||||
desc += " ";
|
||||
desc += tl::to_string (tr ("from cell "));
|
||||
desc += cv->layout ().cell_name (cv.cell_index ());
|
||||
rdb->set_description (desc);
|
||||
|
||||
std::set<db::cell_index_type> called_cells;
|
||||
called_cells.insert (cv.cell_index ());
|
||||
cv->layout ().cell (cv.cell_index ()).collect_called_cells (called_cells);
|
||||
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
|
||||
if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
|
||||
|
||||
rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ());
|
||||
|
||||
for (db::Layout::const_iterator cid = layout.begin (); cid != layout.end (); ++cid) {
|
||||
|
||||
if (called_cells.find (cid->cell_index ()) == called_cells.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const db::Cell &cell = *cid;
|
||||
if (cell.shapes ((*l)->layer_index ()).size () > 0) {
|
||||
|
||||
std::string cn = layout.cell_name (cell.cell_index ());
|
||||
const rdb::Cell *rdb_cell = rdb->cell_by_qname (cn);
|
||||
if (! rdb_cell) {
|
||||
|
||||
rdb::Cell *rdb_cell_nc = rdb->create_cell (cn);
|
||||
rdb_cell = rdb_cell_nc;
|
||||
|
||||
std::pair<bool, db::ICplxTrans> ctx = db::find_layout_context (layout, cell.cell_index (), cv.cell_index ());
|
||||
if (ctx.first) {
|
||||
db::DCplxTrans t = db::DCplxTrans (layout.dbu ()) * db::DCplxTrans (ctx.second) * db::DCplxTrans (1.0 / layout.dbu ());
|
||||
rdb_cell_nc->references ().insert (Reference (t, rdb_top_cell->id ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (db::ShapeIterator shape = cell.shapes ((*l)->layer_index ()).begin (db::ShapeIterator::All); ! shape.at_end (); ++shape) {
|
||||
|
||||
rdb::create_item_from_shape (rdb.get (), rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), *shape);
|
||||
|
||||
++progress;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsigned int rdb_index = view ()->add_rdb (rdb.release ());
|
||||
view ()->open_rdb_browser (rdb_index, cv_index);
|
||||
scan_layer_flat_or_hierarchical (false);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
MarkerBrowserDialog::scan_layer_flat ()
|
||||
{
|
||||
scan_layer_flat_or_hierarchical (true);
|
||||
}
|
||||
|
||||
void
|
||||
MarkerBrowserDialog::scan_layer_flat_or_hierarchical (bool flat)
|
||||
{
|
||||
std::vector<lay::LayerPropertiesConstIterator> layers = view ()->selected_layers ();
|
||||
if (layers.empty ()) {
|
||||
|
|
@ -859,52 +772,19 @@ MarkerBrowserDialog::scan_layer_flat ()
|
|||
throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected")));
|
||||
}
|
||||
|
||||
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Shapes To Markers")), 10000);
|
||||
progress.set_format (tl::to_string (QObject::tr ("%.0f0000 markers")));
|
||||
progress.set_unit (10000);
|
||||
|
||||
const lay::CellView &cv = view ()->cellview (cv_index);
|
||||
const db::Layout &layout = cv->layout ();
|
||||
|
||||
std::vector<std::pair <unsigned int, std::string> > layer_indexes;
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
|
||||
layer_indexes.push_back (std::make_pair ((*l)->layer_index (), (*l)->name ()));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<rdb::Database> rdb (new rdb::Database ());
|
||||
rdb->set_name ("Shapes");
|
||||
rdb->set_top_cell_name (layout.cell_name (cv.cell_index ()));
|
||||
rdb::Cell *rdb_top_cell = rdb->create_cell (rdb->top_cell_name ());
|
||||
|
||||
std::string desc;
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
|
||||
if (! desc.empty ()) {
|
||||
desc += ", ";
|
||||
}
|
||||
desc += layout.get_properties ((*l)->layer_index ()).to_string ();
|
||||
}
|
||||
}
|
||||
desc = tl::to_string (tr ("Flat shapes of layer(s) ")) + desc;
|
||||
desc += " ";
|
||||
desc += tl::to_string (tr ("from cell "));
|
||||
desc += cv->layout ().cell_name (cv.cell_index ());
|
||||
rdb->set_description (desc);
|
||||
|
||||
for (std::vector<lay::LayerPropertiesConstIterator>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
|
||||
if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
|
||||
|
||||
rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ());
|
||||
|
||||
db::RecursiveShapeIterator shape (layout, *cv.cell (), (*l)->layer_index ());
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
rdb::create_item_from_shape (rdb.get (), rdb_top_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()) * shape.trans (), *shape);
|
||||
|
||||
++progress;
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
rdb->scan_layout (layout, cv.cell_index (), layer_indexes, flat);
|
||||
|
||||
unsigned int rdb_index = view ()->add_rdb (rdb.release ());
|
||||
view ()->open_rdb_browser (rdb_index, cv_index);
|
||||
|
|
|
|||
|
|
@ -36,9 +36,16 @@ namespace Ui
|
|||
class MarkerBrowserDialog;
|
||||
}
|
||||
|
||||
namespace db
|
||||
{
|
||||
class Layout;
|
||||
}
|
||||
|
||||
namespace rdb
|
||||
{
|
||||
|
||||
class Database;
|
||||
|
||||
class LAYUI_PUBLIC MarkerBrowserDialog
|
||||
: public lay::Browser
|
||||
{
|
||||
|
|
@ -101,6 +108,7 @@ private:
|
|||
void update_content ();
|
||||
void scan_layer ();
|
||||
void scan_layer_flat ();
|
||||
void scan_layer_flat_or_hierarchical (bool flat);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@
|
|||
namespace lay
|
||||
{
|
||||
|
||||
bool merge_before_bool ()
|
||||
{
|
||||
// $KLAYOUT_XOR_MERGE_BEFORE_BOOLEAN
|
||||
return tl::app_flag ("xor-merge-before-boolean");
|
||||
}
|
||||
|
||||
std::string cfg_xor_input_mode ("xor-input-mode");
|
||||
std::string cfg_xor_output_mode ("xor-output-mode");
|
||||
std::string cfg_xor_nworkers ("xor-num-workers");
|
||||
|
|
@ -766,6 +772,9 @@ XORWorker::do_perform_deep (const XORTask *xor_task)
|
|||
db::RecursiveShapeIterator s_a (mp_job->cva ()->layout (), mp_job->cva ()->layout ().cell (mp_job->cva ().cell_index ()), la, xor_task->region_a ());
|
||||
db::RecursiveShapeIterator s_b (mp_job->cvb ()->layout (), mp_job->cvb ()->layout ().cell (mp_job->cvb ().cell_index ()), lb, xor_task->region_b ());
|
||||
|
||||
s_a.set_for_merged_input (true);
|
||||
s_b.set_for_merged_input (true);
|
||||
|
||||
db::Region ra (s_a, dss, db::ICplxTrans (mp_job->cva ()->layout ().dbu () / mp_job->dbu ()));
|
||||
db::Region rb (s_b, dss, db::ICplxTrans (mp_job->cvb ()->layout ().dbu () / mp_job->dbu ()));
|
||||
|
||||
|
|
@ -794,6 +803,8 @@ XORWorker::do_perform_deep (const XORTask *xor_task)
|
|||
dbu_scale = db::ICplxTrans (mp_job->cvb ()->layout ().dbu () / mp_job->dbu ());
|
||||
}
|
||||
|
||||
s.set_for_merged_input (true);
|
||||
|
||||
rr = db::Region (s, dss, dbu_scale);
|
||||
|
||||
}
|
||||
|
|
@ -861,40 +872,11 @@ XORWorker::do_perform_tiled (const XORTask *xor_task)
|
|||
|
||||
if ((!la.empty () && !lb.empty ()) || mp_job->el_handling () == XORJob::EL_process) {
|
||||
|
||||
if (! mp_job->has_tiles ()) {
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, "Boolean part");
|
||||
size_t n;
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, "Boolean part");
|
||||
#if 0
|
||||
// Straightforward implementation
|
||||
sp.boolean (mp_job->cva ()->layout (), mp_job->cva ()->layout ().cell (mp_job->cva ().cell_index ()), la,
|
||||
mp_job->cvb ()->layout (), mp_job->cvb ()->layout ().cell (mp_job->cvb ().cell_index ()), lb,
|
||||
xor_results_cell.shapes (0), op, true, false, true);
|
||||
#else
|
||||
// This implementation is faster when a lot of overlapping shapes are involved
|
||||
db::Layout merge_helper;
|
||||
db::Cell &merge_helper_cell = merge_helper.cell (merge_helper.add_cell ());
|
||||
merge_helper.insert_layer (0);
|
||||
merge_helper.insert_layer (1);
|
||||
if (! merge_before_bool ()) {
|
||||
|
||||
if (!la.empty ()) {
|
||||
sp.merge (mp_job->cva ()->layout (), mp_job->cva ()->layout ().cell (mp_job->cva ().cell_index ()), la,
|
||||
merge_helper_cell.shapes (0), true, 0, false, true);
|
||||
}
|
||||
if (!lb.empty ()) {
|
||||
sp.merge (mp_job->cvb ()->layout (), mp_job->cvb ()->layout ().cell (mp_job->cvb ().cell_index ()), lb,
|
||||
merge_helper_cell.shapes (1), true, 0, false, true);
|
||||
}
|
||||
sp.boolean (merge_helper, merge_helper_cell, 0,
|
||||
merge_helper, merge_helper_cell, 1,
|
||||
xor_results_cell.shapes (0), mp_job->op (), true, false, true);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 31, "Boolean part");
|
||||
size_t n;
|
||||
|
||||
#if 0
|
||||
// Straightforward implementation
|
||||
sp.clear ();
|
||||
|
||||
|
|
@ -902,20 +884,36 @@ XORWorker::do_perform_tiled (const XORTask *xor_task)
|
|||
db::CplxTrans dbu_scale_b (mp_job->cvb ()->layout ().dbu () / xor_results.dbu ());
|
||||
|
||||
n = 0;
|
||||
for (db::RecursiveShapeIterator s (mp_job->cva ()->layout (), mp_job->cva ().cell (), la, region_a); ! s.at_end (); ++s, ++n) {
|
||||
sp.insert (s.shape (), dbu_scale_a * s.trans (), n * 2);
|
||||
db::RecursiveShapeIterator s_a;
|
||||
if (mp_job->has_tiles ()) {
|
||||
s_a = db::RecursiveShapeIterator (mp_job->cva ()->layout (), *mp_job->cva ().cell (), la, xor_task->region_a ());
|
||||
} else {
|
||||
s_a = db::RecursiveShapeIterator (mp_job->cva ()->layout (), *mp_job->cva ().cell (), la);
|
||||
}
|
||||
s_a.set_for_merged_input (true);
|
||||
for ( ; ! s_a.at_end (); ++s_a, ++n) {
|
||||
sp.insert (s_a.shape (), dbu_scale_a * s_a.trans (), n * 2);
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for (db::RecursiveShapeIterator s (mp_job->cvb ()->layout (), mp_job->cvb ().cell (), lb, region_b); ! s.at_end (); ++s, ++n) {
|
||||
sp.insert (s.shape (), dbu_scale_b * s.trans (), n * 2 + 1);
|
||||
db::RecursiveShapeIterator s_b;
|
||||
if (mp_job->has_tiles ()) {
|
||||
s_b = db::RecursiveShapeIterator (mp_job->cvb ()->layout (), *mp_job->cvb ().cell (), lb, xor_task->region_b ());
|
||||
} else {
|
||||
s_b = db::RecursiveShapeIterator (mp_job->cvb ()->layout (), *mp_job->cvb ().cell (), lb);
|
||||
}
|
||||
s_b.set_for_merged_input (true);
|
||||
for (; ! s_b.at_end (); ++s_b, ++n) {
|
||||
sp.insert (s_b.shape (), dbu_scale_b * s_b.trans (), n * 2 + 1);
|
||||
}
|
||||
|
||||
db::BooleanOp bool_op (mp_job->op ());
|
||||
db::ShapeGenerator sg (xor_results_cell.shapes (0), true /*clear shapes*/);
|
||||
db::PolygonGenerator out (sg, false /*don't resolve holes*/, false /*no min. coherence*/);
|
||||
sp.process (out, mp_job->op ());
|
||||
#else
|
||||
sp.process (out, bool_op);
|
||||
|
||||
} else {
|
||||
|
||||
// This implementation is faster when a lot of overlapping shapes are involved
|
||||
db::Layout merge_helper;
|
||||
merge_helper.dbu (mp_job->dbu ());
|
||||
|
|
@ -931,7 +929,14 @@ XORWorker::do_perform_tiled (const XORTask *xor_task)
|
|||
db::CplxTrans dbu_scale (mp_job->cva ()->layout ().dbu () / xor_results.dbu ());
|
||||
|
||||
n = 0;
|
||||
for (db::RecursiveShapeIterator s (mp_job->cva ()->layout (), *mp_job->cva ().cell (), la, xor_task->region_a ()); ! s.at_end (); ++s, ++n) {
|
||||
db::RecursiveShapeIterator s;
|
||||
if (mp_job->has_tiles ()) {
|
||||
s = db::RecursiveShapeIterator (mp_job->cva ()->layout (), *mp_job->cva ().cell (), la, xor_task->region_a ());
|
||||
} else {
|
||||
s = db::RecursiveShapeIterator (mp_job->cva ()->layout (), *mp_job->cva ().cell (), la);
|
||||
}
|
||||
s.set_for_merged_input (true);
|
||||
for ( ; ! s.at_end (); ++s, ++n) {
|
||||
sp.insert (s.shape (), dbu_scale * s.trans (), n);
|
||||
}
|
||||
|
||||
|
|
@ -949,7 +954,14 @@ XORWorker::do_perform_tiled (const XORTask *xor_task)
|
|||
db::CplxTrans dbu_scale (mp_job->cvb ()->layout ().dbu () / xor_results.dbu ());
|
||||
|
||||
n = 0;
|
||||
for (db::RecursiveShapeIterator s (mp_job->cvb ()->layout (), *mp_job->cvb ().cell (), lb, xor_task->region_b ()); ! s.at_end (); ++s, ++n) {
|
||||
db::RecursiveShapeIterator s;
|
||||
if (mp_job->has_tiles ()) {
|
||||
s = db::RecursiveShapeIterator (mp_job->cvb ()->layout (), *mp_job->cvb ().cell (), lb, xor_task->region_b ());
|
||||
} else {
|
||||
s = db::RecursiveShapeIterator (mp_job->cvb ()->layout (), *mp_job->cvb ().cell (), lb);
|
||||
}
|
||||
s.set_for_merged_input (true);
|
||||
for ( ; ! s.at_end (); ++s, ++n) {
|
||||
sp.insert (s.shape (), dbu_scale * s.trans (), n);
|
||||
}
|
||||
|
||||
|
|
@ -960,10 +972,9 @@ XORWorker::do_perform_tiled (const XORTask *xor_task)
|
|||
|
||||
}
|
||||
|
||||
sp.boolean (merge_helper, merge_helper_cell, 0,
|
||||
merge_helper, merge_helper_cell, 1,
|
||||
sp.boolean (merge_helper, merge_helper_cell, 0,
|
||||
merge_helper, merge_helper_cell, 1,
|
||||
xor_results_cell.shapes (0), mp_job->op (), true, false, true);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -990,6 +1001,8 @@ XORWorker::do_perform_tiled (const XORTask *xor_task)
|
|||
dbu_scale = db::CplxTrans (mp_job->cvb ()->layout ().dbu () / xor_results.dbu ());
|
||||
}
|
||||
|
||||
s.set_for_merged_input (true);
|
||||
|
||||
for (; ! s.at_end (); ++s) {
|
||||
if (s->is_polygon () || s->is_box () || s->is_path ()) {
|
||||
db::Polygon p;
|
||||
|
|
|
|||
|
|
@ -350,9 +350,9 @@ match_method (int mid, PyObject *self, PyObject *args, PyObject *kwargs, bool st
|
|||
PythonPtr arg (i >= argc ? get_kwarg (*a, kwargs) : (is_tuple ? PyTuple_GetItem (args, i) : PyList_GetItem (args, i)));
|
||||
if (! arg) {
|
||||
is_valid = a->spec ()->has_default ();
|
||||
} else if (test_arg (*a, arg.get (), false /*strict*/)) {
|
||||
} else if (test_arg (*a, arg.get (), false /*strict*/, false /*object substitution*/)) {
|
||||
++sc;
|
||||
} else if (test_arg (*a, arg.get (), true /*loose*/)) {
|
||||
} else if (test_arg (*a, arg.get (), true /*loose*/, true /*object substitution*/)) {
|
||||
// non-scoring match
|
||||
} else {
|
||||
is_valid = false;
|
||||
|
|
@ -405,7 +405,7 @@ match_method (int mid, PyObject *self, PyObject *args, PyObject *kwargs, bool st
|
|||
int i = 0;
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments (); ++a, ++i) {
|
||||
PythonPtr arg (i >= argc ? get_kwarg (*a, kwargs) : (is_tuple ? PyTuple_GetItem (args, i) : PyList_GetItem (args, i)));
|
||||
if (arg && ! test_arg (*a, arg.get (), true /*loose*/)) {
|
||||
if (arg && ! test_arg (*a, arg.get (), true /*loose*/, true /*object substitution*/)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1116,7 +1116,8 @@ property_setter_impl (int mid, PyObject *self, PyObject *value)
|
|||
|
||||
// check arguments (count and type)
|
||||
bool is_valid = (*m)->compatible_with_num_args (1);
|
||||
if (is_valid && ! test_arg (*(*m)->begin_arguments (), value, pass != 0 /*loose in the second pass*/)) {
|
||||
bool loose = (pass != 0); // loose in the second pass
|
||||
if (is_valid && ! test_arg (*(*m)->begin_arguments (), value, loose, loose)) {
|
||||
is_valid = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ size_t PythonBasedMapAdaptor::serial_size () const
|
|||
template <class R>
|
||||
struct test_arg_func
|
||||
{
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) {
|
||||
|
||||
|
|
@ -1083,7 +1083,7 @@ struct test_arg_func
|
|||
template <>
|
||||
struct test_arg_func<gsi::VariantType>
|
||||
{
|
||||
void operator() (bool *ret, PyObject *, const gsi::ArgType &, bool)
|
||||
void operator() (bool *ret, PyObject *, const gsi::ArgType &, bool, bool)
|
||||
{
|
||||
// we assume we can convert everything into a variant
|
||||
*ret = true;
|
||||
|
|
@ -1093,7 +1093,7 @@ struct test_arg_func<gsi::VariantType>
|
|||
template <>
|
||||
struct test_arg_func<gsi::StringType>
|
||||
{
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &, bool)
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &, bool, bool)
|
||||
{
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
if (PyString_Check (arg)) {
|
||||
|
|
@ -1117,7 +1117,7 @@ struct test_arg_func<gsi::StringType>
|
|||
template <>
|
||||
struct test_arg_func<gsi::VectorType>
|
||||
{
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) {
|
||||
// for ptr or cptr, null is an allowed value
|
||||
|
|
@ -1138,7 +1138,7 @@ struct test_arg_func<gsi::VectorType>
|
|||
|
||||
size_t n = PyTuple_Size (arg);
|
||||
for (size_t i = 0; i < n && *ret; ++i) {
|
||||
if (! test_arg (ainner, PyTuple_GetItem (arg, i), loose)) {
|
||||
if (! test_arg (ainner, PyTuple_GetItem (arg, i), loose, true /*issue-1651*/)) {
|
||||
*ret = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1147,7 +1147,7 @@ struct test_arg_func<gsi::VectorType>
|
|||
|
||||
size_t n = PyList_Size (arg);
|
||||
for (size_t i = 0; i < n && *ret; ++i) {
|
||||
if (! test_arg (ainner, PyList_GetItem (arg, i), loose)) {
|
||||
if (! test_arg (ainner, PyList_GetItem (arg, i), loose, true /*issue-1651*/)) {
|
||||
*ret = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1159,7 +1159,7 @@ struct test_arg_func<gsi::VectorType>
|
|||
template <>
|
||||
struct test_arg_func<gsi::MapType>
|
||||
{
|
||||
void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) {
|
||||
// for ptr or cptr, null is an allowed value
|
||||
|
|
@ -1184,11 +1184,11 @@ struct test_arg_func<gsi::MapType>
|
|||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
while (PyDict_Next(arg, &pos, &key, &value)) {
|
||||
if (! test_arg (ainner_k, key, loose)) {
|
||||
if (! test_arg (ainner_k, key, loose, true /*issue-1651*/)) {
|
||||
*ret = false;
|
||||
break;
|
||||
}
|
||||
if (! test_arg (ainner, value, loose)) {
|
||||
if (! test_arg (ainner, value, loose, true /*issue-1651*/)) {
|
||||
*ret = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1199,7 +1199,7 @@ struct test_arg_func<gsi::MapType>
|
|||
template <>
|
||||
struct test_arg_func<gsi::ObjectType>
|
||||
{
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool object_substitution)
|
||||
{
|
||||
const gsi::ClassBase *acls = atype.cls ();
|
||||
|
||||
|
|
@ -1209,7 +1209,7 @@ struct test_arg_func<gsi::ObjectType>
|
|||
return;
|
||||
}
|
||||
|
||||
if (loose && (PyTuple_Check (arg) || PyList_Check (arg))) {
|
||||
if (object_substitution && (PyTuple_Check (arg) || PyList_Check (arg))) {
|
||||
|
||||
// we may implicitly convert a tuple into a constructor call of a target object -
|
||||
// for now we only check whether the number of arguments is compatible with the list given.
|
||||
|
|
@ -1247,10 +1247,10 @@ struct test_arg_func<gsi::ObjectType>
|
|||
};
|
||||
|
||||
bool
|
||||
test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose)
|
||||
test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose, bool object_substitution)
|
||||
{
|
||||
bool ret = false;
|
||||
gsi::do_on_type<test_arg_func> () (atype.type (), &ret, arg, atype, loose);
|
||||
gsi::do_on_type<test_arg_func> () (atype.type (), &ret, arg, atype, loose, object_substitution);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ PythonRef pull_arg (const gsi::ArgType &atype, gsi::SerialArgs &aserial, PYAObje
|
|||
* @return True, if the type match
|
||||
*/
|
||||
bool
|
||||
test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose);
|
||||
test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose, bool object_substitution);
|
||||
|
||||
/**
|
||||
* @brief Correct constness if a reference is const and a non-const reference is required
|
||||
|
|
|
|||
|
|
@ -479,9 +479,9 @@ private:
|
|||
VALUE arg = i >= argc ? get_kwarg (*a, kwargs) : argv[i];
|
||||
if (arg == Qundef) {
|
||||
is_valid = a->spec ()->has_default ();
|
||||
} else if (test_arg (*a, arg, false /*strict*/)) {
|
||||
} else if (test_arg (*a, arg, false /*strict*/, false /*with object substitution*/)) {
|
||||
++sc;
|
||||
} else if (test_arg (*a, arg, true /*loose*/)) {
|
||||
} else if (test_arg (*a, arg, true /*loose*/, true /*with object substitution*/)) {
|
||||
// non-scoring match
|
||||
} else {
|
||||
is_valid = false;
|
||||
|
|
|
|||
|
|
@ -1053,7 +1053,7 @@ pull_arg (const gsi::ArgType &atype, Proxy *self, gsi::SerialArgs &aserial, tl::
|
|||
template <class R>
|
||||
struct test_arg_func
|
||||
{
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) {
|
||||
|
||||
|
|
@ -1101,7 +1101,7 @@ struct test_vector
|
|||
unsigned int len = RARRAY_LEN(arr);
|
||||
VALUE *el = RARRAY_PTR(arr);
|
||||
while (len-- > 0) {
|
||||
if (! test_arg (ainner, *el++, loose)) {
|
||||
if (! test_arg (ainner, *el++, loose, true /*issue-1651*/)) {
|
||||
*ret = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1112,7 +1112,7 @@ struct test_vector
|
|||
template <>
|
||||
struct test_arg_func<gsi::VectorType>
|
||||
{
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) {
|
||||
// for pointers to vectors, nil is a valid value
|
||||
|
|
@ -1141,11 +1141,11 @@ struct HashTestKeyValueData
|
|||
static int hash_test_value_key (VALUE key, VALUE value, VALUE a)
|
||||
{
|
||||
HashTestKeyValueData *args = (HashTestKeyValueData *)a;
|
||||
if (! test_arg (*args->ainner_k, key, args->loose)) {
|
||||
if (! test_arg (*args->ainner_k, key, args->loose, true /*issue-1651*/)) {
|
||||
*(args->ret) = false;
|
||||
return ST_STOP;
|
||||
}
|
||||
if (! test_arg (*args->ainner, value, args->loose)) {
|
||||
if (! test_arg (*args->ainner, value, args->loose, true /*issue-1651*/)) {
|
||||
*(args->ret) = false;
|
||||
return ST_STOP;
|
||||
}
|
||||
|
|
@ -1155,7 +1155,7 @@ static int hash_test_value_key (VALUE key, VALUE value, VALUE a)
|
|||
template <>
|
||||
struct test_arg_func<gsi::MapType>
|
||||
{
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) {
|
||||
// for pointers to maps, nil is a valid value
|
||||
|
|
@ -1183,14 +1183,14 @@ struct test_arg_func<gsi::MapType>
|
|||
template <>
|
||||
struct test_arg_func<gsi::ObjectType>
|
||||
{
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose)
|
||||
void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool object_substitution)
|
||||
{
|
||||
if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) {
|
||||
|
||||
// for const X * or X *, nil is an allowed value
|
||||
*ret = true;
|
||||
|
||||
} else if (loose && TYPE (arg) == T_ARRAY) {
|
||||
} else if (object_substitution && TYPE (arg) == T_ARRAY) {
|
||||
|
||||
// we may implicitly convert an array into a constructor call of a target object -
|
||||
// for now we only check whether the number of arguments is compatible with the array given.
|
||||
|
|
@ -1234,10 +1234,10 @@ struct test_arg_func<gsi::ObjectType>
|
|||
};
|
||||
|
||||
bool
|
||||
test_arg (const gsi::ArgType &atype, VALUE arg, bool loose)
|
||||
test_arg (const gsi::ArgType &atype, VALUE arg, bool loose, bool object_substitution)
|
||||
{
|
||||
bool ret = false;
|
||||
gsi::do_on_type<test_arg_func> () (atype.type (), &ret, arg, atype, loose);
|
||||
gsi::do_on_type<test_arg_func> () (atype.type (), &ret, arg, atype, loose, object_substitution);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ void push_arg (const gsi::ArgType &atype, gsi::SerialArgs &aserial, VALUE arg, t
|
|||
* otherwise:
|
||||
* argument must be of the requested type
|
||||
*/
|
||||
bool test_arg (const gsi::ArgType &atype, VALUE arg, bool loose);
|
||||
bool test_arg (const gsi::ArgType &atype, VALUE arg, bool loose, bool object_substitution);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,49 @@ private:
|
|||
rdb::Database::const_item_ref_iterator m_iter;
|
||||
};
|
||||
|
||||
class ItemRefUnwrappingNonConstIterator
|
||||
{
|
||||
public:
|
||||
typedef rdb::Database::const_item_ref_iterator::iterator_category iterator_category;
|
||||
typedef rdb::Database::const_item_ref_iterator::difference_type difference_type;
|
||||
typedef rdb::Item value_type;
|
||||
typedef rdb::Item &reference;
|
||||
typedef rdb::Item *pointer;
|
||||
|
||||
ItemRefUnwrappingNonConstIterator (rdb::Database::item_ref_iterator i)
|
||||
: m_iter (i)
|
||||
{ }
|
||||
|
||||
bool operator== (const ItemRefUnwrappingNonConstIterator &d) const
|
||||
{
|
||||
return m_iter == d.m_iter;
|
||||
}
|
||||
|
||||
bool operator!= (const ItemRefUnwrappingNonConstIterator &d) const
|
||||
{
|
||||
return m_iter != d.m_iter;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator &operator++ ()
|
||||
{
|
||||
++m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rdb::Item &operator* () const
|
||||
{
|
||||
return (*m_iter).operator* ();
|
||||
}
|
||||
|
||||
rdb::Item *operator-> () const
|
||||
{
|
||||
return (*m_iter).operator-> ();
|
||||
}
|
||||
|
||||
private:
|
||||
rdb::Database::item_ref_iterator m_iter;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// rdb::Reference binding
|
||||
|
||||
|
|
@ -105,7 +148,12 @@ Class<rdb::Reference> decl_RdbReference ("rdb", "RdbReference",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method ("trans", &rdb::Reference::trans,
|
||||
gsi::method ("database", (rdb::Database *(rdb::Reference::*)()) &rdb::Reference::database,
|
||||
"@brief Gets the database object that category is associated with (non-const version)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("trans", &rdb::Reference::trans,
|
||||
"@brief Gets the transformation for this reference\n"
|
||||
"The transformation describes the transformation of the child cell into the parent cell. In that sense that is the "
|
||||
"usual transformation of a cell reference.\n"
|
||||
|
|
@ -141,6 +189,16 @@ static rdb::References::const_iterator end_references (const rdb::Cell *cell)
|
|||
return cell->references ().end ();
|
||||
}
|
||||
|
||||
static rdb::References::iterator begin_references_nc (rdb::Cell *cell)
|
||||
{
|
||||
return cell->references ().begin ();
|
||||
}
|
||||
|
||||
static rdb::References::iterator end_references_nc (rdb::Cell *cell)
|
||||
{
|
||||
return cell->references ().end ();
|
||||
}
|
||||
|
||||
static void add_reference (rdb::Cell *cell, const rdb::Reference &ref)
|
||||
{
|
||||
cell->references ().insert (ref);
|
||||
|
|
@ -163,6 +221,18 @@ ItemRefUnwrappingIterator cell_items_end (const rdb::Cell *cell)
|
|||
return cell->database ()->items_by_cell (cell->id ()).second;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator cell_items_begin_non_const (rdb::Cell *cell)
|
||||
{
|
||||
tl_assert (cell->database ());
|
||||
return cell->database ()->items_by_cell (cell->id ()).first;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator cell_items_end_non_const (rdb::Cell *cell)
|
||||
{
|
||||
tl_assert (cell->database ());
|
||||
return cell->database ()->items_by_cell (cell->id ()).second;
|
||||
}
|
||||
|
||||
Class<rdb::Cell> decl_RdbCell ("rdb", "RdbCell",
|
||||
gsi::method ("rdb_id", &rdb::Cell::id,
|
||||
"@brief Gets the cell ID\n"
|
||||
|
|
@ -175,12 +245,22 @@ Class<rdb::Cell> decl_RdbCell ("rdb", "RdbCell",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method ("database", (rdb::Database *(rdb::Cell::*)()) &rdb::Cell::database,
|
||||
"@brief Gets the database object that category is associated with (non-const version)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::iterator_ext ("each_item", &cell_items_begin, &cell_items_end,
|
||||
"@brief Iterates over all items inside the database which are associated with this cell\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method ("name", &rdb::Cell::name,
|
||||
gsi::iterator_ext ("each_item", &cell_items_begin_non_const, &cell_items_end_non_const,
|
||||
"@brief Iterates over all items inside the database which are associated with this cell (non-const version)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("name", &rdb::Cell::name,
|
||||
"@brief Gets the cell name\n"
|
||||
"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 "
|
||||
|
|
@ -215,6 +295,11 @@ Class<rdb::Cell> decl_RdbCell ("rdb", "RdbCell",
|
|||
) +
|
||||
gsi::iterator_ext ("each_reference", &begin_references, &end_references,
|
||||
"@brief Iterates over all references\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_reference", &begin_references_nc, &end_references_nc,
|
||||
"@brief Iterates over all references (non-const version)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
),
|
||||
"@brief A cell inside the report database\n"
|
||||
"This class represents a cell in the report database. There is not necessarily a 1:1 correspondence of RDB cells "
|
||||
|
|
@ -226,12 +311,22 @@ Class<rdb::Cell> decl_RdbCell ("rdb", "RdbCell",
|
|||
// ---------------------------------------------------------------
|
||||
// rdb::Category binding
|
||||
|
||||
static rdb::Categories::iterator begin_sub_categories (rdb::Category *cat)
|
||||
static rdb::Categories::const_iterator begin_sub_categories (const rdb::Category *cat)
|
||||
{
|
||||
return cat->sub_categories ().begin ();
|
||||
}
|
||||
|
||||
static rdb::Categories::iterator end_sub_categories (rdb::Category *cat)
|
||||
static rdb::Categories::const_iterator end_sub_categories (const rdb::Category *cat)
|
||||
{
|
||||
return cat->sub_categories ().end ();
|
||||
}
|
||||
|
||||
static rdb::Categories::iterator begin_sub_categories_non_const (rdb::Category *cat)
|
||||
{
|
||||
return cat->sub_categories ().begin ();
|
||||
}
|
||||
|
||||
static rdb::Categories::iterator end_sub_categories_non_const (rdb::Category *cat)
|
||||
{
|
||||
return cat->sub_categories ().end ();
|
||||
}
|
||||
|
|
@ -248,6 +343,18 @@ ItemRefUnwrappingIterator category_items_end (const rdb::Category *cat)
|
|||
return cat->database ()->items_by_category (cat->id ()).second;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator category_items_begin_non_const (rdb::Category *cat)
|
||||
{
|
||||
tl_assert (cat->database ());
|
||||
return cat->database ()->items_by_category (cat->id ()).first;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator category_items_end_non_const (rdb::Category *cat)
|
||||
{
|
||||
tl_assert (cat->database ());
|
||||
return cat->database ()->items_by_category (cat->id ()).second;
|
||||
}
|
||||
|
||||
static void scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from_cell, int levels, bool with_properties)
|
||||
{
|
||||
rdb::scan_layer (cat, layout, layer, from_cell, levels, with_properties);
|
||||
|
|
@ -299,6 +406,11 @@ Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::iterator_ext ("each_item", &category_items_begin_non_const, &category_items_end_non_const,
|
||||
"@brief Iterates over all items inside the database which are associated with this category (non-const version)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method_ext ("scan_shapes", &scan_shapes, gsi::arg ("iter"), gsi::arg ("flat", false), gsi::arg ("with_properties", true),
|
||||
"@brief Scans the polygon or edge shapes from the shape iterator into the category\n"
|
||||
"Creates RDB items for each polygon or edge shape read from the iterator and puts them into this category.\n"
|
||||
|
|
@ -379,12 +491,23 @@ Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
|
|||
) +
|
||||
gsi::iterator_ext ("each_sub_category", &begin_sub_categories, &end_sub_categories,
|
||||
"@brief Iterates over all sub-categories\n"
|
||||
"\n"
|
||||
"The const version has been added in version 0.29."
|
||||
) +
|
||||
gsi::method ("parent", (rdb::Category *(rdb::Category::*) ()) &rdb::Category::parent,
|
||||
gsi::iterator_ext ("each_sub_category", &begin_sub_categories_non_const, &end_sub_categories_non_const,
|
||||
"@brief Iterates over all sub-categories (non-const version)\n"
|
||||
) +
|
||||
gsi::method ("parent", (const rdb::Category *(rdb::Category::*) () const) &rdb::Category::parent,
|
||||
"@brief Gets the parent category of this category\n"
|
||||
"@return The parent category or nil if this category is a top-level category\n"
|
||||
"\n"
|
||||
"The const version has been added in version 0.29."
|
||||
) +
|
||||
gsi::method ("num_items", &rdb::Category::num_items,
|
||||
gsi::method ("parent", (rdb::Category *(rdb::Category::*) ()) &rdb::Category::parent,
|
||||
"@brief Gets the parent category of this category (non-const version)\n"
|
||||
"@return The parent category or nil if this category is a top-level category\n"
|
||||
) +
|
||||
gsi::method ("num_items", &rdb::Category::num_items,
|
||||
"@brief Gets the number of items in this category\n"
|
||||
"The number of items includes the items in sub-categories of this category.\n"
|
||||
) +
|
||||
|
|
@ -923,6 +1046,16 @@ rdb::Items::const_iterator database_items_end (const rdb::Database *db)
|
|||
return db->items ().end ();
|
||||
}
|
||||
|
||||
rdb::Items::iterator database_items_begin_nc (rdb::Database *db)
|
||||
{
|
||||
return db->items_non_const ().begin ();
|
||||
}
|
||||
|
||||
rdb::Items::iterator database_items_end_nc (rdb::Database *db)
|
||||
{
|
||||
return db->items_non_const ().end ();
|
||||
}
|
||||
|
||||
ItemRefUnwrappingIterator database_items_begin_cell (const rdb::Database *db, rdb::id_type cell_id)
|
||||
{
|
||||
return db->items_by_cell (cell_id).first;
|
||||
|
|
@ -933,6 +1066,16 @@ ItemRefUnwrappingIterator database_items_end_cell (const rdb::Database *db, rdb:
|
|||
return db->items_by_cell (cell_id).second;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator database_items_begin_cell_nc (rdb::Database *db, rdb::id_type cell_id)
|
||||
{
|
||||
return db->items_by_cell (cell_id).first;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator database_items_end_cell_nc (rdb::Database *db, rdb::id_type cell_id)
|
||||
{
|
||||
return db->items_by_cell (cell_id).second;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingIterator database_items_begin_cat (const rdb::Database *db, rdb::id_type cat_id)
|
||||
{
|
||||
return db->items_by_category (cat_id).first;
|
||||
|
|
@ -943,6 +1086,16 @@ ItemRefUnwrappingIterator database_items_end_cat (const rdb::Database *db, rdb::
|
|||
return db->items_by_category (cat_id).second;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator database_items_begin_cat_nc (rdb::Database *db, rdb::id_type cat_id)
|
||||
{
|
||||
return db->items_by_category (cat_id).first;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator database_items_end_cat_nc (rdb::Database *db, rdb::id_type cat_id)
|
||||
{
|
||||
return db->items_by_category (cat_id).second;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingIterator database_items_begin_cc (const rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id)
|
||||
{
|
||||
return db->items_by_cell_and_category (cell_id, cat_id).first;
|
||||
|
|
@ -953,6 +1106,16 @@ ItemRefUnwrappingIterator database_items_end_cc (const rdb::Database *db, rdb::i
|
|||
return db->items_by_cell_and_category (cell_id, cat_id).second;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator database_items_begin_cc_nc (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id)
|
||||
{
|
||||
return db->items_by_cell_and_category (cell_id, cat_id).first;
|
||||
}
|
||||
|
||||
ItemRefUnwrappingNonConstIterator database_items_end_cc_nc (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id)
|
||||
{
|
||||
return db->items_by_cell_and_category (cell_id, cat_id).second;
|
||||
}
|
||||
|
||||
rdb::Categories::const_iterator database_begin_categories (const rdb::Database *db)
|
||||
{
|
||||
return db->categories ().begin ();
|
||||
|
|
@ -963,6 +1126,16 @@ rdb::Categories::const_iterator database_end_categories (const rdb::Database *db
|
|||
return db->categories ().end ();
|
||||
}
|
||||
|
||||
rdb::Categories::iterator database_end_categories_nc (rdb::Database *db)
|
||||
{
|
||||
return db->categories_non_const ().end ();
|
||||
}
|
||||
|
||||
rdb::Categories::iterator database_begin_categories_nc (rdb::Database *db)
|
||||
{
|
||||
return db->categories_non_const ().begin ();
|
||||
}
|
||||
|
||||
rdb::Cells::const_iterator database_begin_cells (const rdb::Database *db)
|
||||
{
|
||||
return db->cells ().begin ();
|
||||
|
|
@ -973,6 +1146,16 @@ rdb::Cells::const_iterator database_end_cells (const rdb::Database *db)
|
|||
return db->cells ().end ();
|
||||
}
|
||||
|
||||
rdb::Cells::iterator database_begin_cells_nc (rdb::Database *db)
|
||||
{
|
||||
return db->cells_non_const ().begin ();
|
||||
}
|
||||
|
||||
rdb::Cells::iterator database_end_cells_nc (rdb::Database *db)
|
||||
{
|
||||
return db->cells_non_const ().end ();
|
||||
}
|
||||
|
||||
const std::string &database_tag_name (const rdb::Database *db, rdb::id_type tag)
|
||||
{
|
||||
return db->tags ().tag (tag).name ();
|
||||
|
|
@ -1121,6 +1304,11 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
|
|||
gsi::iterator_ext ("each_category", &database_begin_categories, &database_end_categories,
|
||||
"@brief Iterates over all top-level categories\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_category", &database_begin_categories_nc, &database_end_categories_nc,
|
||||
"@brief Iterates over all top-level categories (non-const version)\n"
|
||||
"\n"
|
||||
"The non-const variant has been added in version 0.29."
|
||||
) +
|
||||
gsi::method ("create_category", (rdb::Category *(rdb::Database::*) (const std::string &)) &rdb::Database::create_category, gsi::arg ("name"),
|
||||
"@brief Creates a new top level category\n"
|
||||
"@param name The name of the category\n"
|
||||
|
|
@ -1135,10 +1323,23 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
|
|||
"@param path The full path to the category starting from the top level (subcategories separated by dots)\n"
|
||||
"@return The (const) category object or nil if the name is not valid\n"
|
||||
) +
|
||||
gsi::method ("category_by_path", &rdb::Database::category_by_name_non_const, gsi::arg ("path"),
|
||||
"@brief Gets a category by path (non-const version)\n"
|
||||
"@param path The full path to the category starting from the top level (subcategories separated by dots)\n"
|
||||
"@return The (const) category object or nil if the name is not valid\n"
|
||||
"\n"
|
||||
"This non-const variant has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("category_by_id", &rdb::Database::category_by_id, gsi::arg ("id"),
|
||||
"@brief Gets a category by ID\n"
|
||||
"@return The (const) category object or nil if the ID is not valid\n"
|
||||
) +
|
||||
gsi::method ("category_by_id", &rdb::Database::category_by_id_non_const, gsi::arg ("id"),
|
||||
"@brief Gets a category by ID (non-const version)\n"
|
||||
"@return The (const) category object or nil if the ID is not valid\n"
|
||||
"\n"
|
||||
"This non-const variant has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("create_cell", (rdb::Cell *(rdb::Database::*) (const std::string &)) &rdb::Database::create_cell, gsi::arg ("name"),
|
||||
"@brief Creates a new cell\n"
|
||||
"@param name The name of the cell\n"
|
||||
|
|
@ -1158,14 +1359,33 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
|
|||
"@param qname The qualified name of the cell (name plus variant name optionally)\n"
|
||||
"@return The cell object or nil if no such cell exists\n"
|
||||
) +
|
||||
gsi::method ("cell_by_qname", &rdb::Database::cell_by_qname_non_const, gsi::arg ("qname"),
|
||||
"@brief Returns the cell for a given qualified name (non-const version)\n"
|
||||
"@param qname The qualified name of the cell (name plus variant name optionally)\n"
|
||||
"@return The cell object or nil if no such cell exists\n"
|
||||
"\n"
|
||||
"This non-const variant has been added version 0.29."
|
||||
) +
|
||||
gsi::method ("cell_by_id", &rdb::Database::cell_by_id, gsi::arg ("id"),
|
||||
"@brief Returns the cell for a given ID\n"
|
||||
"@param id The ID of the cell\n"
|
||||
"@return The cell object or nil if no cell with that ID exists\n"
|
||||
) +
|
||||
gsi::method ("cell_by_id", &rdb::Database::cell_by_id_non_const, gsi::arg ("id"),
|
||||
"@brief Returns the cell for a given ID (non-const version)\n"
|
||||
"@param id The ID of the cell\n"
|
||||
"@return The cell object or nil if no cell with that ID exists\n"
|
||||
"\n"
|
||||
"This non-const variant has been added version 0.29."
|
||||
) +
|
||||
gsi::iterator_ext ("each_cell", &database_begin_cells, &database_end_cells,
|
||||
"@brief Iterates over all cells\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_cell", &database_begin_cells_nc, &database_end_cells_nc,
|
||||
"@brief Iterates over all cells (non-const version)\n"
|
||||
"\n"
|
||||
"This non-const variant has been added version 0.29."
|
||||
) +
|
||||
gsi::method ("num_items", (size_t (rdb::Database::*) () const) &rdb::Database::num_items,
|
||||
"@brief Returns the number of items inside the database\n"
|
||||
"@return The total number of items\n"
|
||||
|
|
@ -1351,19 +1571,43 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
|
|||
gsi::iterator_ext ("each_item", &database_items_begin, &database_items_end,
|
||||
"@brief Iterates over all items inside the database\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_item", &database_items_begin_nc, &database_items_end_nc,
|
||||
"@brief Iterates over all items inside the database (non-const version)\n"
|
||||
"\n"
|
||||
"This non-const variant has been added in version 0.29."
|
||||
) +
|
||||
gsi::iterator_ext ("each_item_per_cell", &database_items_begin_cell, &database_items_end_cell, gsi::arg ("cell_id"),
|
||||
"@brief Iterates over all items inside the database which are associated with the given cell\n"
|
||||
"@param cell_id The ID of the cell for which all associated items should be retrieved\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_item_per_cell", &database_items_begin_cell_nc, &database_items_end_cell_nc, gsi::arg ("cell_id"),
|
||||
"@brief Iterates over all items inside the database which are associated with the given cell (non-const version)\n"
|
||||
"@param cell_id The ID of the cell for which all associated items should be retrieved\n"
|
||||
"\n"
|
||||
"This non-const variant has been added in version 0.29."
|
||||
) +
|
||||
gsi::iterator_ext ("each_item_per_category", &database_items_begin_cat, &database_items_end_cat, gsi::arg ("category_id"),
|
||||
"@brief Iterates over all items inside the database which are associated with the given category\n"
|
||||
"@param category_id The ID of the category for which all associated items should be retrieved\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_item_per_category", &database_items_begin_cat_nc, &database_items_end_cat_nc, gsi::arg ("category_id"),
|
||||
"@brief Iterates over all items inside the database which are associated with the given category (non-const version)\n"
|
||||
"@param category_id The ID of the category for which all associated items should be retrieved\n"
|
||||
"\n"
|
||||
"This non-const variant has been added in version 0.29."
|
||||
) +
|
||||
gsi::iterator_ext ("each_item_per_cell_and_category", &database_items_begin_cc, &database_items_end_cc, gsi::arg ("cell_id"), gsi::arg ("category_id"),
|
||||
"@brief Iterates over all items inside the database which are associated with the given cell and category\n"
|
||||
"@param cell_id The ID of the cell for which all associated items should be retrieved\n"
|
||||
"@param category_id The ID of the category for which all associated items should be retrieved\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_item_per_cell_and_category", &database_items_begin_cc_nc, &database_items_end_cc_nc, gsi::arg ("cell_id"), gsi::arg ("category_id"),
|
||||
"@brief Iterates over all items inside the database which are associated with the given cell and category\n"
|
||||
"@param cell_id The ID of the cell for which all associated items should be retrieved\n"
|
||||
"@param category_id The ID of the category for which all associated items should be retrieved\n"
|
||||
"\n"
|
||||
"This non-const variant has been added in version 0.29."
|
||||
) +
|
||||
gsi::method ("set_item_visited", &rdb::Database::set_item_visited, gsi::arg ("item"), gsi::arg ("visited"),
|
||||
"@brief Modifies the visited state of an item\n"
|
||||
"@param item The item to modify\n"
|
||||
|
|
|
|||
|
|
@ -23,11 +23,13 @@
|
|||
|
||||
#include "rdb.h"
|
||||
#include "rdbReader.h"
|
||||
#include "rdbUtils.h"
|
||||
#include "tlString.h"
|
||||
#include "tlAssert.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlBase64.h"
|
||||
#include "tlProgress.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbBox.h"
|
||||
#include "dbEdge.h"
|
||||
|
|
@ -35,6 +37,10 @@
|
|||
#include "dbPath.h"
|
||||
#include "dbText.h"
|
||||
#include "dbShape.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
# include <QByteArray>
|
||||
|
|
@ -1488,7 +1494,18 @@ Database::items_by_cell_and_category (id_type cell_id, id_type category_id) cons
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<Database::const_item_ref_iterator, Database::const_item_ref_iterator>
|
||||
std::pair<Database::item_ref_iterator, Database::item_ref_iterator>
|
||||
Database::items_by_cell_and_category (id_type cell_id, id_type category_id)
|
||||
{
|
||||
std::map <std::pair <id_type, id_type>, std::list<ItemRef> >::iterator i = m_items_by_cell_and_category_id.find (std::make_pair (cell_id, category_id));
|
||||
if (i != m_items_by_cell_and_category_id.end ()) {
|
||||
return std::make_pair (i->second.begin (), i->second.end ());
|
||||
} else {
|
||||
return std::make_pair (empty_list.begin (), empty_list.end ());
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Database::const_item_ref_iterator, Database::const_item_ref_iterator>
|
||||
Database::items_by_cell (id_type cell_id) const
|
||||
{
|
||||
std::map <id_type, std::list<ItemRef> >::const_iterator i = m_items_by_cell_id.find (cell_id);
|
||||
|
|
@ -1499,7 +1516,18 @@ Database::items_by_cell (id_type cell_id) const
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<Database::const_item_ref_iterator, Database::const_item_ref_iterator>
|
||||
std::pair<Database::item_ref_iterator, Database::item_ref_iterator>
|
||||
Database::items_by_cell (id_type cell_id)
|
||||
{
|
||||
std::map <id_type, std::list<ItemRef> >::iterator i = m_items_by_cell_id.find (cell_id);
|
||||
if (i != m_items_by_cell_id.end ()) {
|
||||
return std::make_pair (i->second.begin (), i->second.end ());
|
||||
} else {
|
||||
return std::make_pair (empty_list.begin (), empty_list.end ());
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Database::const_item_ref_iterator, Database::const_item_ref_iterator>
|
||||
Database::items_by_category (id_type category_id) const
|
||||
{
|
||||
std::map <id_type, std::list<ItemRef> >::const_iterator i = m_items_by_category_id.find (category_id);
|
||||
|
|
@ -1510,7 +1538,18 @@ Database::items_by_category (id_type category_id) const
|
|||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
std::pair<Database::item_ref_iterator, Database::item_ref_iterator>
|
||||
Database::items_by_category (id_type category_id)
|
||||
{
|
||||
std::map <id_type, std::list<ItemRef> >::iterator i = m_items_by_category_id.find (category_id);
|
||||
if (i != m_items_by_category_id.end ()) {
|
||||
return std::make_pair (i->second.begin (), i->second.end ());
|
||||
} else {
|
||||
return std::make_pair (empty_list.begin (), empty_list.end ());
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
Database::num_items (id_type cell_id, id_type category_id) const
|
||||
{
|
||||
std::map <std::pair <id_type, id_type>, size_t>::const_iterator n = m_num_items_by_cell_and_category.find (std::make_pair (cell_id, category_id));
|
||||
|
|
@ -1566,16 +1605,49 @@ Database::clear ()
|
|||
mp_categories->set_database (this);
|
||||
}
|
||||
|
||||
static void
|
||||
read_db_from_layout (rdb::Database *db, tl::InputStream &is)
|
||||
{
|
||||
// try reading a layout file
|
||||
db::Layout layout;
|
||||
db::Reader reader (is);
|
||||
|
||||
reader.read (layout);
|
||||
|
||||
std::vector<std::pair<unsigned int, std::string> > layers;
|
||||
for (auto l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
||||
layers.push_back (std::make_pair ((*l).first, std::string ()));
|
||||
}
|
||||
|
||||
if (layout.begin_top_down () != layout.end_top_down ()) {
|
||||
db->scan_layout (layout, *layout.begin_top_down (), layers, false /*hierarchical*/);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Database::load (const std::string &fn)
|
||||
{
|
||||
tl::log << "Loading RDB from " << fn;
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
rdb::Reader reader (stream);
|
||||
|
||||
clear ();
|
||||
reader.read (*this);
|
||||
|
||||
tl::InputStream stream (fn);
|
||||
|
||||
bool ok = false;
|
||||
try {
|
||||
// try reading a stream file
|
||||
read_db_from_layout (this, stream);
|
||||
ok = true;
|
||||
} catch (tl::Exception &) {
|
||||
stream.reset ();
|
||||
}
|
||||
|
||||
if (! ok) {
|
||||
// try reading a DB file
|
||||
clear ();
|
||||
rdb::Reader reader (stream);
|
||||
reader.read (*this);
|
||||
}
|
||||
|
||||
set_filename (stream.absolute_path ());
|
||||
set_name (stream.filename ());
|
||||
|
|
@ -1587,5 +1659,128 @@ Database::load (const std::string &fn)
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
tl::AbsoluteProgress progress (tl::to_string (tr ("Shapes To Markers")), 10000);
|
||||
progress.set_format (tl::to_string (tr ("%.0f0000 markers")));
|
||||
progress.set_unit (10000);
|
||||
|
||||
set_name ("Shapes");
|
||||
set_top_cell_name (layout.cell_name (cell_index));
|
||||
rdb::Cell *rdb_top_cell = create_cell (top_cell_name ());
|
||||
|
||||
std::string desc;
|
||||
|
||||
if (layers_and_descriptions.size () == 1) {
|
||||
|
||||
if (flat) {
|
||||
desc = tl::to_string (tr ("Flat shapes of layer "));
|
||||
} else {
|
||||
desc = tl::to_string (tr ("Hierarchical shapes of layer "));
|
||||
}
|
||||
|
||||
desc += layout.get_properties (layers_and_descriptions.front ().first).to_string ();
|
||||
|
||||
} else if (layers_and_descriptions.size () < 4 && layers_and_descriptions.size () > 0) {
|
||||
|
||||
if (flat) {
|
||||
desc = tl::to_string (tr ("Flat shapes of layers "));
|
||||
} else {
|
||||
desc = tl::to_string (tr ("Hierarchical shapes of layers "));
|
||||
}
|
||||
|
||||
for (auto l = layers_and_descriptions.begin (); l != layers_and_descriptions.end (); ++l) {
|
||||
if (l != layers_and_descriptions.begin ()) {
|
||||
desc += ",";
|
||||
}
|
||||
desc += layout.get_properties (l->first).to_string ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (flat) {
|
||||
desc = tl::sprintf (tl::to_string (tr ("Flat shapes of %d layers")), int (layers_and_descriptions.size ()));
|
||||
} else {
|
||||
desc = tl::sprintf (tl::to_string (tr ("Hierarchical shapes of %d layers")), int (layers_and_descriptions.size ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
desc += " ";
|
||||
desc += tl::to_string (tr ("from cell "));
|
||||
desc += layout.cell_name (cell_index);
|
||||
set_description (desc);
|
||||
|
||||
if (flat) {
|
||||
|
||||
for (auto l = layers_and_descriptions.begin (); l != layers_and_descriptions.end (); ++l) {
|
||||
|
||||
rdb::Category *cat = create_category (l->second.empty () ? layout.get_properties (l->first).to_string () : l->second);
|
||||
|
||||
db::RecursiveShapeIterator shape (layout, layout.cell (cell_index), l->first);
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
rdb::create_item_from_shape (this, rdb_top_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()) * shape.trans (), *shape);
|
||||
|
||||
++progress;
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
std::set<db::cell_index_type> called_cells;
|
||||
called_cells.insert (cell_index);
|
||||
layout.cell (cell_index).collect_called_cells (called_cells);
|
||||
|
||||
for (auto l = layers_and_descriptions.begin (); l != layers_and_descriptions.end (); ++l) {
|
||||
|
||||
rdb::Category *cat = create_category (l->second.empty () ? layout.get_properties (l->first).to_string () : l->second);
|
||||
|
||||
for (db::Layout::const_iterator cid = layout.begin (); cid != layout.end (); ++cid) {
|
||||
|
||||
if (called_cells.find (cid->cell_index ()) == called_cells.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const db::Cell &cell = *cid;
|
||||
if (! cell.shapes (l->first).empty ()) {
|
||||
|
||||
std::string cn = layout.cell_name (cell.cell_index ());
|
||||
const rdb::Cell *rdb_cell = cell_by_qname (cn);
|
||||
if (! rdb_cell) {
|
||||
|
||||
rdb::Cell *rdb_cell_nc = create_cell (cn);
|
||||
rdb_cell = rdb_cell_nc;
|
||||
|
||||
std::pair<bool, db::ICplxTrans> ctx = db::find_layout_context (layout, cell.cell_index (), cell_index);
|
||||
if (ctx.first) {
|
||||
db::DCplxTrans t = db::DCplxTrans (layout.dbu ()) * db::DCplxTrans (ctx.second) * db::DCplxTrans (1.0 / layout.dbu ());
|
||||
rdb_cell_nc->references ().insert (Reference (t, rdb_top_cell->id ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (db::ShapeIterator shape = cell.shapes (l->first).begin (db::ShapeIterator::All); ! shape.at_end (); ++shape) {
|
||||
|
||||
rdb::create_item_from_shape (this, rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), *shape);
|
||||
|
||||
++progress;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace rdb
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ namespace tl
|
|||
namespace db
|
||||
{
|
||||
class Shape;
|
||||
class Layout;
|
||||
}
|
||||
|
||||
namespace rdb
|
||||
|
|
@ -2082,6 +2083,14 @@ public:
|
|||
return *mp_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the reference to the categories collection (non-const version)
|
||||
*/
|
||||
Categories &categories_non_const ()
|
||||
{
|
||||
return *mp_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Import categories
|
||||
*
|
||||
|
|
@ -2129,6 +2138,20 @@ public:
|
|||
return const_cast<Database *> (this)->category_by_id_non_const (id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the category pointer for a category name (non-const version)
|
||||
*
|
||||
* This method returns 0 if the category name is invalid.
|
||||
*/
|
||||
Category *category_by_name_non_const (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Get the category pointer for a category id (non-const version)
|
||||
*
|
||||
* This method returns 0 if the category is invalid.
|
||||
*/
|
||||
Category *category_by_id_non_const (id_type id);
|
||||
|
||||
/**
|
||||
* @brief Access to the cell collection (const)
|
||||
*/
|
||||
|
|
@ -2137,6 +2160,14 @@ public:
|
|||
return m_cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to the cell collection
|
||||
*/
|
||||
Cells &cells_non_const ()
|
||||
{
|
||||
return m_cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Import cells
|
||||
*
|
||||
|
|
@ -2190,6 +2221,20 @@ public:
|
|||
return const_cast<Database *> (this)->cell_by_id_non_const (id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the cell pointer for a cell name or name:variant combination (non-const version)
|
||||
*
|
||||
* This method returns 0 if the cell name or name:variant combination is invalid.
|
||||
*/
|
||||
Cell *cell_by_qname_non_const (const std::string &qname);
|
||||
|
||||
/**
|
||||
* @brief Get the cell pointer for a cell id (non-const version)
|
||||
*
|
||||
* This method returns 0 if the cell id is invalid.
|
||||
*/
|
||||
Cell *cell_by_id_non_const (id_type id);
|
||||
|
||||
/**
|
||||
* @brief Report the number of items in total
|
||||
*/
|
||||
|
|
@ -2266,6 +2311,14 @@ public:
|
|||
return *mp_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the items collection (non-const version)
|
||||
*/
|
||||
Items &items_non_const ()
|
||||
{
|
||||
return *mp_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the items collection
|
||||
*
|
||||
|
|
@ -2279,16 +2332,31 @@ public:
|
|||
*/
|
||||
std::pair<const_item_ref_iterator, const_item_ref_iterator> items_by_cell (id_type cell_id) const;
|
||||
|
||||
/**
|
||||
* @brief Get an iterator pair that delivers the non-const items (ItemRef) for a given cell
|
||||
*/
|
||||
std::pair<item_ref_iterator, item_ref_iterator> items_by_cell (id_type cell_id);
|
||||
|
||||
/**
|
||||
* @brief Get an iterator that delivers the const items (ItemRef) for a given category
|
||||
*/
|
||||
std::pair<const_item_ref_iterator, const_item_ref_iterator> items_by_category (id_type category_id) const;
|
||||
|
||||
/**
|
||||
* @brief Get an iterator that delivers the non-const items (ItemRef) for a given category
|
||||
*/
|
||||
std::pair<item_ref_iterator, item_ref_iterator> items_by_category (id_type category_id);
|
||||
|
||||
/**
|
||||
* @brief Get an iterator that delivers the const items (ItemRef) for a given cell and category
|
||||
*/
|
||||
std::pair<const_item_ref_iterator, const_item_ref_iterator> items_by_cell_and_category (id_type cell_id, id_type category_id) const;
|
||||
|
||||
/**
|
||||
* @brief Get an iterator that delivers the non-const items (ItemRef) for a given cell and category
|
||||
*/
|
||||
std::pair<item_ref_iterator, item_ref_iterator> items_by_cell_and_category (id_type cell_id, id_type category_id);
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the database was modified
|
||||
*/
|
||||
|
|
@ -2317,6 +2385,16 @@ public:
|
|||
*/
|
||||
void load (const std::string &filename);
|
||||
|
||||
/**
|
||||
* @brief Scans a layout into this RDB
|
||||
*
|
||||
* @param layout The layout to scan
|
||||
* @param cell_index The top cell to scan
|
||||
* @param layers_and_descriptions The layers and (optional) descriptions/names of the layer to scan
|
||||
* @param flat True, to perform a flat scan
|
||||
*/
|
||||
void 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);
|
||||
|
||||
private:
|
||||
std::string m_generator;
|
||||
std::string m_filename;
|
||||
|
|
@ -2349,14 +2427,6 @@ private:
|
|||
m_modified = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the items collection (non-const version)
|
||||
*/
|
||||
Items &items_non_const ()
|
||||
{
|
||||
return *mp_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the reference to the tags collection (non-const version)
|
||||
*/
|
||||
|
|
@ -2364,50 +2434,6 @@ private:
|
|||
{
|
||||
return m_tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the reference to the categories collection (non-const version)
|
||||
*/
|
||||
Categories &categories_non_const ()
|
||||
{
|
||||
return *mp_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the category pointer for a category name
|
||||
*
|
||||
* This method returns 0 if the category name is invalid.
|
||||
*/
|
||||
Category *category_by_name_non_const (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Get the category pointer for a category id
|
||||
*
|
||||
* This method returns 0 if the category is invalid.
|
||||
*/
|
||||
Category *category_by_id_non_const (id_type id);
|
||||
|
||||
/**
|
||||
* @brief Access to the cell collection
|
||||
*/
|
||||
Cells &cells_non_const ()
|
||||
{
|
||||
return m_cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the cell pointer for a cell name or name:variant combination (non-const version)
|
||||
*
|
||||
* This method returns 0 if the cell name or name:variant combination is invalid.
|
||||
*/
|
||||
Cell *cell_by_qname_non_const (const std::string &qname);
|
||||
|
||||
/**
|
||||
* @brief Get the cell pointer for a cell id (non-const version)
|
||||
*
|
||||
* This method returns 0 if the cell id is invalid.
|
||||
*/
|
||||
Cell *cell_by_id_non_const (id_type id);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@
|
|||
namespace tl
|
||||
{
|
||||
|
||||
extern const nullopt_t nullopt = nullopt_t ();
|
||||
const nullopt_t nullopt = nullopt_t ();
|
||||
|
||||
} // namespace tl
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace tl
|
|||
|
||||
struct nullopt_t {};
|
||||
|
||||
extern const nullopt_t nullopt;
|
||||
extern TL_PUBLIC const nullopt_t nullopt;
|
||||
|
||||
/**
|
||||
* @brief Poor man's partial implementation of C++17's std::optional
|
||||
|
|
|
|||
|
|
@ -322,10 +322,8 @@ static double local_strtod (const char *cp, const char *&cp_new)
|
|||
if (*cp == '-') {
|
||||
s = -1.0;
|
||||
++cp;
|
||||
/*
|
||||
} else if (*cp == '+') {
|
||||
++cp;
|
||||
*/
|
||||
}
|
||||
|
||||
// Extract upper digits
|
||||
|
|
|
|||
|
|
@ -305,6 +305,25 @@ TEST(6)
|
|||
EXPECT_EQ (x3.test (":"), true);
|
||||
}
|
||||
|
||||
TEST(6_double)
|
||||
{
|
||||
Extractor x (" 5.5 -2.5 \n+0.125 (no number)");
|
||||
|
||||
EXPECT_EQ (x.at_end (), false);
|
||||
|
||||
double d = 0.0;
|
||||
|
||||
EXPECT_EQ (x.try_read (d), true);
|
||||
EXPECT_EQ (d, 5.5);
|
||||
|
||||
x.read (d);
|
||||
EXPECT_EQ (d, -2.5);
|
||||
x.read (d);
|
||||
EXPECT_EQ (d, 0.125);
|
||||
|
||||
x.expect ("(");
|
||||
}
|
||||
|
||||
TEST(7)
|
||||
{
|
||||
EXPECT_EQ (tl::to_quoted_string ("a_word!"), "'a_word!'");
|
||||
|
|
|
|||
|
|
@ -746,6 +746,16 @@ class DBPolygonTests(unittest.TestCase):
|
|||
poly = pya.Polygon(hull).insert_hole(hole1).insert_hole(hole2)
|
||||
self.assertEqual(str(poly), "(0,0;0,3000;6000,3000;6000,0/1000,1000;2000,1000;2000,2000;1000,2000/3000,1000;4000,1000;4000,2000;3000,2000)")
|
||||
|
||||
def test_argumentShortcuts(self):
|
||||
|
||||
# implicit conversion to a Point array:
|
||||
poly = pya.Polygon([ (0,0), (0,1000), (1000,1000) ])
|
||||
self.assertEqual(str(poly), "(0,0;0,1000;1000,1000)")
|
||||
|
||||
# issue 1651 - no binding to Box constructor
|
||||
poly = pya.Polygon([ (0,0), (0,1000), (1000,1000), (1000,0) ])
|
||||
self.assertEqual(str(poly), "(0,0;0,1000;1000,1000;1000,0)")
|
||||
|
||||
# run unit tests
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(DBPolygonTests)
|
||||
|
|
|
|||
|
|
@ -146,6 +146,9 @@ class DBBox_TestClass < TestBase
|
|||
assert_equal( a + b, b )
|
||||
assert_equal( (b + c).to_s, "(1,-10;22,22)" )
|
||||
|
||||
assert_equal( b - a, b )
|
||||
assert_equal( (b - c).to_s, "(1,-1;17,22)" )
|
||||
|
||||
assert_equal( a + RBA::DPoint::new( 1, -5 ), RBA::DBox::new( 1, -5, 1, -5 ) )
|
||||
assert_equal( (b + RBA::DPoint::new( 1, -5 )).to_s, "(1,-5;17,22)" )
|
||||
|
||||
|
|
|
|||
|
|
@ -882,6 +882,18 @@ class DBPolygon_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
def test_argumentShortcuts
|
||||
|
||||
# implicit conversion to a Point array:
|
||||
poly = RBA::Polygon.new([ [0,0], [0,1000], [1000,1000] ])
|
||||
assert_equal(poly.to_s, "(0,0;0,1000;1000,1000)")
|
||||
|
||||
# issue 1651 - no binding to Box constructor
|
||||
poly = RBA::Polygon.new([ [0,0], [0,1000], [1000,1000], [1000,0] ])
|
||||
assert_equal(poly.to_s, "(0,0;0,1000;1000,1000;1000,0)")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -322,6 +322,38 @@ END
|
|||
|
||||
end
|
||||
|
||||
def test_3
|
||||
|
||||
l = RBA::Layout.new
|
||||
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
||||
l.insert_layer_at(1, RBA::LayerInfo.new(2, 0))
|
||||
c0 = l.cell(l.add_cell("c0"))
|
||||
c1 = l.cell(l.add_cell("c1"))
|
||||
c2 = l.cell(l.add_cell("c2"))
|
||||
c3 = l.cell(l.add_cell("c3"))
|
||||
|
||||
b = RBA::Box.new(0, 100, 1000, 1200)
|
||||
c0.shapes(0).insert(RBA::Box.new(0, 0, 3000, 2000))
|
||||
c1.shapes(0).insert(b)
|
||||
c2.shapes(0).insert(b)
|
||||
c3.shapes(0).insert(b)
|
||||
|
||||
tt = RBA::Trans.new
|
||||
c0.insert(RBA::CellInstArray.new(c1.cell_index, tt))
|
||||
c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Vector.new(100, -100))))
|
||||
c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1)))
|
||||
c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Vector.new(1100, 0))))
|
||||
|
||||
ii = RBA::RecursiveShapeIterator.new(l, c0, 0)
|
||||
assert_equal(ii.for_merged_input, false)
|
||||
assert_equal(collect(ii, l), "[c0](0,0;3000,2000)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)")
|
||||
|
||||
ii.for_merged_input = true
|
||||
assert_equal(ii.for_merged_input, true)
|
||||
assert_equal(collect(ii, l), "[c0](0,0;3000,2000)/[c3](-1200,0;-100,1000)")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -1066,6 +1066,47 @@ class DBRegion_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# regions from Shapes
|
||||
def test_regions_from_shapes
|
||||
|
||||
shapes = RBA::Shapes::new;
|
||||
|
||||
shapes.insert(RBA::Box::new(0, 0, 100, 200))
|
||||
shapes.insert(RBA::Box::new(50, 50, 150, 250))
|
||||
|
||||
assert_equal(RBA::Region::new(shapes).area, 32500)
|
||||
region = RBA::Region::new(shapes)
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 40000)
|
||||
|
||||
assert_equal(RBA::Region::new(shapes, RBA::ICplxTrans::new(0.5)).area, 8125)
|
||||
region = RBA::Region::new(shapes, RBA::ICplxTrans::new(0.5))
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 10000)
|
||||
|
||||
# for cross-checking: same for RecursiveShapeIterator
|
||||
|
||||
layout = RBA::Layout::new
|
||||
l1 = layout.insert_layer(RBA::LayerInfo::new(1, 0))
|
||||
top = layout.create_cell("TOP")
|
||||
|
||||
top.shapes(l1).insert (RBA::Box::new(0, 0, 100, 200))
|
||||
top.shapes(l1).insert (RBA::Box::new(50, 50, 150, 250))
|
||||
|
||||
si = RBA::RecursiveShapeIterator::new(layout, top, l1)
|
||||
|
||||
assert_equal(RBA::Region::new(si).area, 32500)
|
||||
region = RBA::Region::new(si)
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 40000)
|
||||
|
||||
assert_equal(RBA::Region::new(si, RBA::ICplxTrans::new(0.5)).area, 8125)
|
||||
region = RBA::Region::new(si, RBA::ICplxTrans::new(0.5))
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 10000)
|
||||
|
||||
end
|
||||
|
||||
# deep region tests
|
||||
def test_deep1
|
||||
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].is_polygon?, false )
|
||||
assert_equal( arr[0].is_box?, true )
|
||||
assert_equal( arr[0].box.to_s, "(10,-10;50,40)" )
|
||||
assert_equal( arr[0].rectangle.to_s, "(10,-10;50,40)" )
|
||||
assert_equal( arr[0].bbox.to_s, "(10,-10;50,40)" )
|
||||
|
||||
# edges
|
||||
|
|
@ -198,6 +199,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].edge.to_s, "(-1,2;5,2)" )
|
||||
assert_equal( arr[0].edge_pair.inspect, "nil" )
|
||||
assert_equal( arr[0].box.inspect, "nil" )
|
||||
assert_equal( arr[0].rectangle.inspect, "nil" )
|
||||
assert_equal( arr[0].path.inspect, "nil" )
|
||||
assert_equal( arr[0].text.inspect, "nil" )
|
||||
assert_equal( arr[0].edge == a, true )
|
||||
|
|
@ -533,6 +535,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].dedge.inspect, "nil" )
|
||||
assert_equal( arr[0].dedge_pair.inspect, "nil" )
|
||||
assert_equal( arr[0].dbox.to_s, "(0.01,-0.01;0.05,0.04)" )
|
||||
assert_equal( arr[0].drectangle.to_s, "(0.01,-0.01;0.05,0.04)" )
|
||||
assert_equal( arr[0].dpath.inspect, "nil" )
|
||||
assert_equal( arr[0].dtext.inspect, "nil" )
|
||||
assert_equal( arr[0].is_polygon?, false )
|
||||
|
|
@ -557,6 +560,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].dedge.to_s, "(-0.001,0.002;0.005,0.002)" )
|
||||
assert_equal( arr[0].dedge_pair.inspect, "nil" )
|
||||
assert_equal( arr[0].dbox.inspect, "nil" )
|
||||
assert_equal( arr[0].drectangle.inspect, "nil" )
|
||||
assert_equal( arr[0].dpath.inspect, "nil" )
|
||||
assert_equal( arr[0].dtext.inspect, "nil" )
|
||||
assert_equal( arr[0].dbbox.to_s, "(-0.001,0.002;0.005,0.002)" )
|
||||
|
|
|
|||
|
|
@ -105,10 +105,29 @@ END
|
|||
|
||||
tech.default_grids = []
|
||||
assert_equal(tech.default_grids.collect { |g| "%.12g" % g }.join(","), "")
|
||||
assert_equal("%.12g" % tech.default_grid, "0")
|
||||
tech.default_grids = [0.001, 0.01, 0.2]
|
||||
assert_equal(tech.default_grids.collect { |g| "%.12g" % g }.join(","), "0.001,0.01,0.2")
|
||||
tech.default_grids = [1]
|
||||
assert_equal(tech.default_grids.collect { |g| "%.12g" % g }.join(","), "1")
|
||||
assert_equal("%.12g" % tech.default_grid, "0")
|
||||
|
||||
# setting the default grid
|
||||
tech.set_default_grids([0.01,0.02,0.05], 0.02)
|
||||
assert_equal(tech.default_grids.collect { |g| "%.12g" % g }.join(","), "0.01,0.02,0.05")
|
||||
assert_equal("%.12g" % tech.default_grid, "0.02")
|
||||
|
||||
# default grid must be a member of the default grid list
|
||||
tech.set_default_grids([0.01,0.02,0.05], 0.2)
|
||||
assert_equal(tech.default_grids.collect { |g| "%.12g" % g }.join(","), "0.01,0.02,0.05")
|
||||
assert_equal("%.12g" % tech.default_grid, "0")
|
||||
|
||||
# "default_grids=" resets the default grid
|
||||
tech.set_default_grids([0.01,0.02,0.05], 0.02)
|
||||
assert_equal("%.12g" % tech.default_grid, "0.02")
|
||||
tech.default_grids = [1]
|
||||
assert_equal(tech.default_grids.collect { |g| "%.12g" % g }.join(","), "1")
|
||||
assert_equal("%.12g" % tech.default_grid, "0")
|
||||
|
||||
tech.default_base_path = "/default/path"
|
||||
assert_equal(tech.default_base_path, "/default/path")
|
||||
|
|
|
|||
|
|
@ -935,6 +935,78 @@ class RDB_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
def test_13
|
||||
|
||||
# manipulations
|
||||
rdb = RBA::ReportDatabase::new("")
|
||||
|
||||
_cell = rdb.create_cell("CELL")
|
||||
_cat = rdb.create_category("cat")
|
||||
_subcat = rdb.create_category(_cat, "subcat")
|
||||
_subcat.description = "subcat_d"
|
||||
_item1 = rdb.create_item(_cell.rdb_id, _subcat.rdb_id)
|
||||
_item1.add_value(17.5)
|
||||
_item1.add_value("string")
|
||||
_item2 = rdb.create_item(_cell.rdb_id, _subcat.rdb_id)
|
||||
_item2.add_value("b")
|
||||
_subsubcat = rdb.create_category(_subcat, "subsubcat")
|
||||
_cat2 = rdb.create_category("cat2")
|
||||
|
||||
cell = rdb.cell_by_id(_cell.rdb_id)
|
||||
assert_equal(cell._is_const_object?, false)
|
||||
assert_equal(rdb.each_cell.to_a[0]._is_const_object?, false)
|
||||
|
||||
cell = rdb.cell_by_qname("CELL")
|
||||
assert_equal(cell._is_const_object?, false)
|
||||
|
||||
cat = rdb.category_by_id(_cat.rdb_id)
|
||||
assert_equal(cat._is_const_object?, false)
|
||||
|
||||
cat = rdb.category_by_path("cat")
|
||||
assert_equal(cat._is_const_object?, false)
|
||||
subcat = rdb.category_by_path("cat.subcat")
|
||||
|
||||
assert_equal(rdb.each_category.to_a[0]._is_const_object?, false)
|
||||
assert_equal(rdb.each_category.collect { |c| c.name }.join(","), "cat,cat2")
|
||||
assert_equal(subcat._is_const_object?, false)
|
||||
assert_equal(subcat.database._is_const_object?, false)
|
||||
assert_equal(subcat.name, "subcat")
|
||||
assert_equal(subcat.parent.name, "cat")
|
||||
|
||||
assert_equal(subcat.description, "subcat_d")
|
||||
subcat.description = "changed"
|
||||
assert_equal(subcat.description, "changed")
|
||||
|
||||
assert_equal(rdb.each_item_per_category(subcat.rdb_id).collect { |item| item.each_value.collect { |v| v.to_s }.join("/") }.join(";"), "float: 17.5/text: string;text: b")
|
||||
|
||||
item1 = rdb.each_item_per_category(subcat.rdb_id).to_a[0]
|
||||
assert_equal(item1._is_const_object?, false)
|
||||
item1.clear_values
|
||||
assert_equal(rdb.each_item_per_category(subcat.rdb_id).collect { |item| item.each_value.collect { |v| v.to_s }.join("/") }.join(";"), ";text: b")
|
||||
item1.add_value("x")
|
||||
assert_equal(rdb.each_item_per_category(subcat.rdb_id).collect { |item| item.each_value.collect { |v| v.to_s }.join("/") }.join(";"), "text: x;text: b")
|
||||
item1.add_tag(17)
|
||||
assert_equal(item1.has_tag?(17), true)
|
||||
assert_equal(item1.has_tag?(16), false)
|
||||
|
||||
item1 = rdb.each_item.to_a[0]
|
||||
assert_equal(item1._is_const_object?, false)
|
||||
assert_equal(item1.has_tag?(17), true)
|
||||
|
||||
item1 = rdb.each_item_per_cell(cell.rdb_id).to_a[0]
|
||||
assert_equal(item1._is_const_object?, false)
|
||||
assert_equal(item1.has_tag?(17), true)
|
||||
|
||||
item1 = rdb.each_item_per_cell_and_category(cell.rdb_id, subcat.rdb_id).to_a[0]
|
||||
assert_equal(item1._is_const_object?, false)
|
||||
assert_equal(item1.has_tag?(17), true)
|
||||
|
||||
item1 = cell.each_item.to_a[0]
|
||||
assert_equal(item1._is_const_object?, false)
|
||||
assert_equal(item1.has_tag?(17), true)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue