Merge branch 'master' of github.com:KLayout/klayout

This commit is contained in:
Matthias Koefferlein 2024-03-29 13:51:55 +01:00
commit bdb8389420
72 changed files with 2391 additions and 440 deletions

View File

@ -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));

View File

@ -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);

View File

@ -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
*

View File

@ -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 ());

View File

@ -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 ();

View File

@ -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)
{

View File

@ -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
*/

View File

@ -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)
{

View File

@ -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
*/

View File

@ -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 ()
{

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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 &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, 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 &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, 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 &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, 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 &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, 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 &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, 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 &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, 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 ();
}

View File

@ -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 &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, 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 &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, 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 &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, 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 &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, 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 &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, 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 &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, 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;

View File

@ -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
{

View File

@ -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
*/

View File

@ -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
{

View File

@ -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
*/

View File

@ -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)
{

View File

@ -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)
*/

View File

@ -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

View File

@ -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 ();
};
/**

View File

@ -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 ()
{

View File

@ -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
*/

View File

@ -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)
{

View File

@ -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
*/

View File

@ -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"

View File

@ -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 "

View File

@ -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"
) +

View File

@ -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"

View File

@ -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."

View File

@ -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"
) +

View File

@ -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"

View File

@ -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 "

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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 ());
}

View File

@ -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 &quot;View&quot; 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>&lt;html&gt;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. &quot;0.01!,0.02,0.05&quot;.
&lt;br/&gt;&lt;b&gt;Note&lt;/b&gt;: the general default grids can be overridden by technology specific default grids.&lt;/html&gt;</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>

View File

@ -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 &quot;View&quot; menu</string>
<string>These grids are available for selection from the &quot;View&quot; 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. &quot;0.01!,0.02,0.05&quot;.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>

View File

@ -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 {

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);
};
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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"

View File

@ -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

View File

@ -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);
};
}

View File

@ -25,6 +25,6 @@
namespace tl
{
extern const nullopt_t nullopt = nullopt_t ();
const nullopt_t nullopt = nullopt_t ();
} // namespace tl

View File

@ -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

View File

@ -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

View File

@ -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!'");

View File

@ -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)

View File

@ -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)" )

View File

@ -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")

View File

@ -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")

View File

@ -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

View File

@ -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)" )

View File

@ -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")

View File

@ -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")