Merge pull request #1646 from KLayout/xor-performance

Xor performance
This commit is contained in:
Matthias Köfferlein 2024-03-29 08:56:44 +01:00 committed by GitHub
commit 14a16f8461
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1218 additions and 114 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

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

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

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

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

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

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

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