mirror of https://github.com/KLayout/klayout.git
commit
14a16f8461
|
|
@ -680,13 +680,17 @@ bool run_tiled_xor (const XORData &xor_data)
|
|||
if (ll->second.first < 0) {
|
||||
proc.input (in_a, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_a, db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first));
|
||||
db::RecursiveShapeIterator si (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
|
||||
si.set_for_merged_input (true);
|
||||
proc.input (in_a, si);
|
||||
}
|
||||
|
||||
if (ll->second.second < 0) {
|
||||
proc.input (in_b, db::RecursiveShapeIterator ());
|
||||
} else {
|
||||
proc.input (in_b, db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second));
|
||||
db::RecursiveShapeIterator si (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
|
||||
si.set_for_merged_input (true);
|
||||
proc.input (in_b, si);
|
||||
}
|
||||
|
||||
std::string expr = "var x=" + in_a + "^" + in_b + "; ";
|
||||
|
|
@ -805,10 +809,12 @@ bool run_deep_xor (const XORData &xor_data)
|
|||
|
||||
if (ll->second.first >= 0) {
|
||||
ri_a = db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
|
||||
ri_a.set_for_merged_input (true);
|
||||
}
|
||||
|
||||
if (ll->second.second >= 0) {
|
||||
ri_b = db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
|
||||
ri_b.set_for_merged_input (true);
|
||||
}
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (xor_data.layout_a->dbu () / dbu));
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ AsIfFlatRegion::area (const db::Box &box) const
|
|||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
if (box.empty () || p->box ().inside (box)) {
|
||||
a += p->area ();
|
||||
} else if (p->is_box ()) {
|
||||
a += (p->box () & box).area ();
|
||||
} else {
|
||||
std::vector<db::Polygon> clipped;
|
||||
clip_poly (*p, box, clipped);
|
||||
|
|
|
|||
|
|
@ -254,6 +254,27 @@ struct DB_PUBLIC_TEMPLATE box
|
|||
*/
|
||||
box<C, R> &operator+= (const point<C> &p);
|
||||
|
||||
/**
|
||||
* @brief Subtraction of boxes.
|
||||
*
|
||||
* The -= operator subtracts the argument box from *this.
|
||||
* Subtraction leaves the bounding box of the region resulting
|
||||
* from the geometrical NOT of *this and the argument box.
|
||||
* Subtracting a box from itself gives an empty box.
|
||||
* Subtracting a box that does not cover a full side of
|
||||
* *this will not modify the box.
|
||||
*
|
||||
* @param b The box to subtract from *this.
|
||||
*
|
||||
* @return The result box.
|
||||
*/
|
||||
box<C, R> &operator-= (const box<C, R> &b);
|
||||
|
||||
/**
|
||||
* @brief A method version for operator- (mainly for automation purposes)
|
||||
*/
|
||||
box<C, R> subtracted (const box<C, R> &b) const;
|
||||
|
||||
/**
|
||||
* @brief Intersection of boxes.
|
||||
*
|
||||
|
|
@ -784,6 +805,50 @@ box<C, R>::operator+= (const point<C> &p)
|
|||
return *this;
|
||||
}
|
||||
|
||||
template <class C, class R>
|
||||
inline box<C, R>
|
||||
box<C, R>::subtracted (const box<C, R> &b) const
|
||||
{
|
||||
box<C, R> r (*this);
|
||||
r -= b;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class C, class R>
|
||||
inline box<C, R> &
|
||||
box<C, R>::operator-= (const box<C, R> &bx)
|
||||
{
|
||||
if (bx.empty () || empty ()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
coord_type l = m_p1.x (), r = m_p2.x ();
|
||||
coord_type b = m_p1.y (), t = m_p2.y ();
|
||||
|
||||
if (bx.bottom () <= bottom () && bx.top () >= top ()) {
|
||||
if (bx.left () <= left ()) {
|
||||
l = std::max (bx.right (), left ());
|
||||
}
|
||||
if (bx.right () >= right ()) {
|
||||
r = std::min (bx.left (), right ());
|
||||
}
|
||||
}
|
||||
|
||||
if (bx.left () <= left () && bx.right () >= right ()) {
|
||||
if (bx.bottom () <= bottom ()) {
|
||||
b = std::max (bx.top (), bottom ());
|
||||
}
|
||||
if (bx.top () >= top ()) {
|
||||
t = std::min (bx.bottom (), top ());
|
||||
}
|
||||
}
|
||||
|
||||
m_p1 = point_type (l, b);
|
||||
m_p2 = point_type (r, t);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class C, class R>
|
||||
inline box<C, R> &
|
||||
box<C, R>::operator&= (const box<C, R> &b)
|
||||
|
|
@ -1363,6 +1428,23 @@ operator+ (const box<C> &b1, const box<C> &b2)
|
|||
return bb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Box subtraction mapped on the - operator
|
||||
*
|
||||
* @param b1 The first box
|
||||
* @param b2 The second box to subtract from the first
|
||||
*
|
||||
* @return The bounding box of the region formed but subtracting b2 from b1
|
||||
*/
|
||||
template <class C>
|
||||
inline box<C>
|
||||
operator- (const box<C> &b1, const box<C> &b2)
|
||||
{
|
||||
box<C> bb (b1);
|
||||
bb -= b2;
|
||||
return bb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief "Folding" of two boxes
|
||||
*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#include "dbOriginalLayerEdgePairs.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include "tlVariant.h"
|
||||
|
||||
|
|
@ -93,6 +96,23 @@ EdgePairs::EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
|||
mp_delegate = new DeepEdgePairs (si, dss, trans);
|
||||
}
|
||||
|
||||
void
|
||||
EdgePairs::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("EDGE_PAIRS"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
template <class Sh>
|
||||
void EdgePairs::insert (const Sh &shape)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -185,6 +185,14 @@ public:
|
|||
*/
|
||||
explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Writes the edge pair collection to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -251,6 +251,13 @@ struct CutPoints
|
|||
|
||||
}
|
||||
|
||||
// do not insert points twice
|
||||
for (auto c = cut_points.begin (); c != cut_points.end (); ++c) {
|
||||
if (*c == p) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cut_points.push_back (p);
|
||||
|
||||
}
|
||||
|
|
@ -1057,6 +1064,12 @@ EdgeProcessor::reserve (size_t n)
|
|||
mp_work_edges->reserve (n);
|
||||
}
|
||||
|
||||
size_t
|
||||
EdgeProcessor::count () const
|
||||
{
|
||||
return mp_work_edges->size ();
|
||||
}
|
||||
|
||||
void
|
||||
EdgeProcessor::insert (const db::Edge &e, EdgeProcessor::property_type p)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -695,6 +695,11 @@ public:
|
|||
*/
|
||||
void reserve (size_t n);
|
||||
|
||||
/**
|
||||
* @brief Reports the number of edges stored in the processor
|
||||
*/
|
||||
size_t count () const;
|
||||
|
||||
/**
|
||||
* @brief Insert an edge
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
#include "dbFlatEdges.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -141,6 +144,23 @@ Edges::set_delegate (EdgesDelegate *delegate, bool keep_attributes)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Edges::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("EDGES"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
void
|
||||
Edges::clear ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -833,6 +833,14 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes the edge collection to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Intersections with other edges
|
||||
* Intersections are similar to "AND", but will also report
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ FlatRegion::FlatRegion (const FlatRegion &other)
|
|||
: MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons), mp_properties_repository (other.mp_properties_repository)
|
||||
{
|
||||
init ();
|
||||
|
||||
m_is_merged = other.m_is_merged;
|
||||
m_merged_polygons_valid = other.m_merged_polygons_valid;
|
||||
}
|
||||
|
|
@ -52,15 +51,22 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged)
|
|||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
|
||||
{
|
||||
init ();
|
||||
|
||||
m_is_merged = is_merged;
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
|
||||
{
|
||||
init ();
|
||||
m_is_merged = is_merged;
|
||||
transform_generic (trans);
|
||||
set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
||||
FlatRegion::FlatRegion (bool is_merged)
|
||||
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
|
||||
{
|
||||
init ();
|
||||
|
||||
m_is_merged = is_merged;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ public:
|
|||
typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type;
|
||||
|
||||
FlatRegion ();
|
||||
FlatRegion (const db::Shapes &polygons, bool is_merged);
|
||||
FlatRegion (const db::Shapes &polygons, bool is_merged = false);
|
||||
FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false);
|
||||
FlatRegion (bool is_merged);
|
||||
|
||||
FlatRegion (const FlatRegion &other);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
mp_shape_prop_sel = d.mp_shape_prop_sel;
|
||||
m_shape_inv_prop_sel = d.m_shape_inv_prop_sel;
|
||||
m_overlapping = d.m_overlapping;
|
||||
m_for_merged_input = d.m_for_merged_input;
|
||||
|
||||
m_start = d.m_start;
|
||||
m_stop = d.m_stop;
|
||||
|
||||
|
|
@ -80,6 +82,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
m_cells = d.m_cells;
|
||||
m_local_complex_region_stack = d.m_local_complex_region_stack;
|
||||
m_local_region_stack = d.m_local_region_stack;
|
||||
m_skip_shapes_stack = d.m_skip_shapes_stack;
|
||||
m_needs_reinit = d.m_needs_reinit;
|
||||
m_inst_quad_id = d.m_inst_quad_id;
|
||||
m_inst_quad_id_stack = d.m_inst_quad_id_stack;
|
||||
|
|
@ -99,6 +102,7 @@ RecursiveShapeIterator::RecursiveShapeIterator ()
|
|||
mp_cell = 0;
|
||||
m_current_layer = 0;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = false;
|
||||
m_max_depth = std::numeric_limits<int>::max (); // all
|
||||
m_min_depth = 0;
|
||||
m_shape_flags = shape_iterator::All;
|
||||
|
|
@ -116,6 +120,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes)
|
|||
mp_shapes = &shapes;
|
||||
mp_top_cell = 0;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = false;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
|
@ -127,6 +132,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
|
|||
mp_shapes = &shapes;
|
||||
mp_top_cell = 0;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = false;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
|
@ -138,11 +144,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
|
|||
mp_shapes = &shapes;
|
||||
mp_top_cell = 0;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = false;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout, layer)
|
||||
{
|
||||
m_layer = layer;
|
||||
|
|
@ -151,11 +158,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout, layer)
|
||||
{
|
||||
m_layer = layer;
|
||||
|
|
@ -164,11 +172,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input)
|
||||
: m_box_convert (layout, layer)
|
||||
{
|
||||
m_layer = layer;
|
||||
|
|
@ -177,11 +186,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -191,11 +201,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -205,11 +216,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -219,11 +231,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -233,11 +246,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -247,11 +261,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = overlapping;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (region);
|
||||
}
|
||||
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input)
|
||||
: m_box_convert (layout)
|
||||
{
|
||||
m_layer = 0;
|
||||
|
|
@ -261,6 +276,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
|
|||
mp_shapes = 0;
|
||||
mp_top_cell = &cell;
|
||||
m_overlapping = false;
|
||||
m_for_merged_input = for_merged_input;
|
||||
init ();
|
||||
init_region (box_type::world ());
|
||||
}
|
||||
|
|
@ -447,6 +463,8 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
m_local_region_stack.clear ();
|
||||
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
|
||||
m_skip_shapes_stack.clear ();
|
||||
m_skip_shapes_stack.push_back (false);
|
||||
|
||||
m_local_complex_region_stack.clear ();
|
||||
if (mp_complex_region.get ()) {
|
||||
|
|
@ -723,11 +741,21 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
if (is_empty) {
|
||||
|
||||
// skip entire cell
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
|
||||
} else {
|
||||
down (receiver);
|
||||
} else if (!down (receiver)) {
|
||||
|
||||
// skip this instance array member
|
||||
++m_inst_array;
|
||||
new_inst_member (receiver);
|
||||
|
||||
if (m_inst_array.at_end ()) {
|
||||
++m_inst;
|
||||
new_inst (receiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -755,9 +783,42 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
||||
{
|
||||
bool skip_shapes = false;
|
||||
|
||||
if (m_for_merged_input && ! m_skip_shapes_stack.back () && (! m_has_layers || m_layers.size () == 1)) {
|
||||
|
||||
// Try some optimization: if the instance we're looking at is entirely covered
|
||||
// by a rectangle (other objects are too expensive to check), then we skip it
|
||||
//
|
||||
// We check 10 shapes max.
|
||||
|
||||
box_type inst_bx;
|
||||
if (m_inst->size () == 1) {
|
||||
inst_bx = m_inst->bbox (m_box_convert);
|
||||
} else {
|
||||
inst_bx = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ());
|
||||
}
|
||||
|
||||
unsigned int l = m_has_layers ? m_layers.front () : m_layer;
|
||||
auto si = cell ()->shapes (l).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
size_t nmax = 10;
|
||||
while (! si.at_end () && nmax-- > 0) {
|
||||
if (inst_bx.inside (si->rectangle ())) {
|
||||
skip_shapes = true;
|
||||
break;
|
||||
}
|
||||
++si;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (skip_shapes && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tl_assert (mp_layout);
|
||||
|
||||
m_trans_stack.push_back (m_trans);
|
||||
|
|
@ -779,11 +840,13 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
box_type new_region = box_type::world ();
|
||||
|
||||
// compute the region inside the new cell
|
||||
if (new_region != m_region) {
|
||||
new_region = m_trans.inverted () * m_region;
|
||||
if (new_region != m_local_region_stack.back ()) {
|
||||
new_region = m_inst->complex_trans (*m_inst_array).inverted () * m_local_region_stack.back ();
|
||||
new_region &= cell_bbox (cell_index ());
|
||||
}
|
||||
|
||||
m_local_region_stack.push_back (new_region);
|
||||
m_skip_shapes_stack.push_back (m_skip_shapes_stack.back () || skip_shapes);
|
||||
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
|
||||
|
|
@ -817,11 +880,25 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
}
|
||||
|
||||
if (receiver) {
|
||||
receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
|
||||
}
|
||||
// do not descend if the box is empty
|
||||
|
||||
new_cell (receiver);
|
||||
if (m_local_region_stack.back ().empty ()) {
|
||||
|
||||
pop ();
|
||||
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
if (receiver) {
|
||||
receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
|
||||
}
|
||||
|
||||
new_cell (receiver);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -831,6 +908,12 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
|
|||
receiver->leave_cell (this, cell ());
|
||||
}
|
||||
|
||||
pop ();
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::pop () const
|
||||
{
|
||||
m_shape = shape_iterator ();
|
||||
m_shape_quad_id = 0;
|
||||
|
||||
|
|
@ -846,6 +929,7 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
|
|||
mp_cell = m_cells.back ();
|
||||
m_cells.pop_back ();
|
||||
m_local_region_stack.pop_back ();
|
||||
m_skip_shapes_stack.pop_back ();
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
m_local_complex_region_stack.pop_back ();
|
||||
}
|
||||
|
|
@ -870,7 +954,7 @@ RecursiveShapeIterator::start_shapes () const
|
|||
void
|
||||
RecursiveShapeIterator::new_layer () const
|
||||
{
|
||||
if (int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
if (m_skip_shapes_stack.back () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
|
||||
m_shape = shape_iterator ();
|
||||
} else if (! m_overlapping) {
|
||||
m_shape = cell ()->shapes (m_layer).begin_touching (m_local_region_stack.back (), m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
|
||||
|
|
@ -901,12 +985,16 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
new_layer ();
|
||||
|
||||
m_inst = cell ()->begin_touching (m_local_region_stack.back ());
|
||||
if (m_overlapping) {
|
||||
m_inst = cell ()->begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1)));
|
||||
} else {
|
||||
m_inst = cell ()->begin_touching (m_local_region_stack.back ());
|
||||
}
|
||||
|
||||
m_inst_quad_id = 0;
|
||||
|
||||
// skip instance quad if possible
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
skip_inst_iter_for_complex_region ();
|
||||
}
|
||||
|
||||
|
|
@ -922,7 +1010,7 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
|||
while (! m_inst.at_end ()) {
|
||||
|
||||
// skip instance quad if possible
|
||||
if (! m_local_complex_region_stack.empty ()) {
|
||||
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
|
||||
skip_inst_iter_for_complex_region ();
|
||||
if (m_inst.at_end ()) {
|
||||
break;
|
||||
|
|
@ -950,7 +1038,11 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
|||
// a singular iterator
|
||||
m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false);
|
||||
} else if (with_region) {
|
||||
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
|
||||
if (m_overlapping) {
|
||||
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1)), m_box_convert);
|
||||
} else {
|
||||
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
|
||||
}
|
||||
} else {
|
||||
m_inst_array = m_inst->cell_inst ().begin ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,12 +122,13 @@ public:
|
|||
* @param layer The layer from which to deliver the shapes
|
||||
* @param region The region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor
|
||||
|
|
@ -137,13 +138,14 @@ public:
|
|||
* @param layer The layer from which to deliver the shapes
|
||||
* @param region The complex region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit. It allows specification of a complex
|
||||
* search region.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor for "world" iteration
|
||||
|
|
@ -153,8 +155,9 @@ public:
|
|||
* @param layout The layout from which to get the cell hierarchy
|
||||
* @param cell The starting cell
|
||||
* @param layer The layer from which to deliver the shapes
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -164,12 +167,13 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -179,13 +183,14 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The complex region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit. It allows specification of a complex
|
||||
* search region.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -195,12 +200,13 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor with a layer selection
|
||||
|
|
@ -210,13 +216,14 @@ public:
|
|||
* @param layers The layers from which to deliver the shapes
|
||||
* @param region The complex region from which to select the shapes
|
||||
* @param overlapping Specify overlapping mode
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*
|
||||
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
|
||||
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
|
||||
* overlap the given region by at least one database unit. It allows specification of a complex
|
||||
* search region.
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, bool overlapping = false, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor for "world" iteration with a layer set
|
||||
|
|
@ -226,8 +233,9 @@ public:
|
|||
* @param layout The layout from which to get the cell hierarchy
|
||||
* @param cell The starting cell
|
||||
* @param layers The layers from which to deliver the shapes
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Standard constructor for "world" iteration with a layer set
|
||||
|
|
@ -237,8 +245,9 @@ public:
|
|||
* @param layout The layout from which to get the cell hierarchy
|
||||
* @param cell The starting cell
|
||||
* @param layers The layers from which to deliver the shapes
|
||||
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
|
||||
*/
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input = false);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -427,6 +436,25 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether optimizing for merged input
|
||||
*/
|
||||
bool for_merged_input () const
|
||||
{
|
||||
return m_for_merged_input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether optimizing for merged input
|
||||
*/
|
||||
void set_for_merged_input (bool f)
|
||||
{
|
||||
if (m_for_merged_input != f) {
|
||||
m_for_merged_input = f;
|
||||
m_needs_reinit = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a global transformation
|
||||
*
|
||||
|
|
@ -812,7 +840,7 @@ private:
|
|||
unsigned int m_shape_flags;
|
||||
const shape_iterator::property_selector *mp_shape_prop_sel;
|
||||
bool m_shape_inv_prop_sel;
|
||||
bool m_overlapping;
|
||||
bool m_overlapping, m_for_merged_input;
|
||||
std::set<db::cell_index_type> m_start, m_stop;
|
||||
cplx_trans_type m_global_trans;
|
||||
db::PropertiesTranslator m_property_translator;
|
||||
|
|
@ -839,6 +867,7 @@ private:
|
|||
mutable std::vector<const cell_type *> m_cells;
|
||||
mutable std::vector<box_tree_type> m_local_complex_region_stack;
|
||||
mutable std::vector<box_type> m_local_region_stack;
|
||||
mutable std::vector<bool> m_skip_shapes_stack;
|
||||
mutable bool m_needs_reinit;
|
||||
mutable size_t m_inst_quad_id;
|
||||
mutable std::vector<size_t> m_inst_quad_id_stack;
|
||||
|
|
@ -858,7 +887,8 @@ private:
|
|||
void new_cell (RecursiveShapeReceiver *receiver) const;
|
||||
void new_layer () const;
|
||||
void up (RecursiveShapeReceiver *receiver) const;
|
||||
void down (RecursiveShapeReceiver *receiver) const;
|
||||
bool down (RecursiveShapeReceiver *receiver) const;
|
||||
void pop () const;
|
||||
|
||||
bool is_outside_complex_region (const db::Box &box) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
#include "dbFlatEdges.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "dbCompoundOperation.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
// NOTE: include this to provide the symbols for "make_variant"
|
||||
|
|
@ -74,14 +77,42 @@ Region &Region::operator= (const Region &other)
|
|||
return *this;
|
||||
}
|
||||
|
||||
Region::Region (const RecursiveShapeIterator &si)
|
||||
Region::Region (const RecursiveShapeIterator &si, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
mp_delegate = new OriginalLayerRegion (si);
|
||||
mp_delegate = new OriginalLayerRegion (si, db::ICplxTrans (), merged_semantics, is_merged);
|
||||
}
|
||||
|
||||
Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics)
|
||||
Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics);
|
||||
mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics, is_merged);
|
||||
}
|
||||
|
||||
Region::Region (const Shapes &shapes, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
db::FlatRegion *flat_region = new FlatRegion (is_merged);
|
||||
flat_region->reserve (shapes.size (db::ShapeIterator::Regions));
|
||||
|
||||
// NOTE: we need to normalize the shapes to polygons because this is what the flat region expects
|
||||
for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) {
|
||||
flat_region->insert (*s);
|
||||
}
|
||||
|
||||
mp_delegate = flat_region;
|
||||
mp_delegate->set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
||||
Region::Region (const Shapes &shapes, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
|
||||
{
|
||||
db::FlatRegion *flat_region = new FlatRegion (is_merged);
|
||||
flat_region->reserve (shapes.size (db::ShapeIterator::Regions));
|
||||
|
||||
// NOTE: we need to normalize the shapes to polygons because this is what the flat region expects
|
||||
for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) {
|
||||
flat_region->insert (*s, trans);
|
||||
}
|
||||
|
||||
mp_delegate = flat_region;
|
||||
mp_delegate->set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
||||
Region::Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
|
|
@ -101,6 +132,23 @@ Region::Region (DeepShapeStore &dss)
|
|||
mp_delegate = new db::DeepRegion (db::DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||
}
|
||||
|
||||
void
|
||||
Region::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("REGION"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator &
|
||||
Region::iter () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ public:
|
|||
* Creates a region from a recursive shape iterator. This allows feeding a region
|
||||
* from a hierarchy of cells.
|
||||
*/
|
||||
explicit Region (const RecursiveShapeIterator &si);
|
||||
explicit Region (const RecursiveShapeIterator &si, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator with a transformation
|
||||
|
|
@ -208,7 +208,23 @@ public:
|
|||
* from a hierarchy of cells. The transformation is useful to scale to a specific
|
||||
* DBU for example.
|
||||
*/
|
||||
explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true);
|
||||
explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a Shapes container
|
||||
*
|
||||
* Creates a region from a shapes container.
|
||||
*/
|
||||
explicit Region (const Shapes &si, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a Shapes container with a transformation
|
||||
*
|
||||
* Creates a region from a recursive shape iterator. This allows feeding a region
|
||||
* from a hierarchy of cells. The transformation is useful to scale to a specific
|
||||
* DBU for example.
|
||||
*/
|
||||
explicit Region (const Shapes &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator providing a deep representation
|
||||
|
|
@ -232,6 +248,14 @@ public:
|
|||
*/
|
||||
explicit Region (DeepShapeStore &dss);
|
||||
|
||||
/**
|
||||
* @brief Writes the region to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -807,6 +807,61 @@ Shape::box_type Shape::bbox () const
|
|||
}
|
||||
}
|
||||
|
||||
Shape::box_type Shape::rectangle () const
|
||||
{
|
||||
if (is_box ()) {
|
||||
return box ();
|
||||
}
|
||||
|
||||
switch (m_type) {
|
||||
case db::Shape::Polygon:
|
||||
return polygon ().is_box () ? polygon ().box () : box_type ();
|
||||
case db::Shape::PolygonRef:
|
||||
case db::Shape::PolygonPtrArrayMember:
|
||||
return polygon_ref ().is_box () ? polygon_ref ().box () : box_type ();
|
||||
case db::Shape::SimplePolygon:
|
||||
return simple_polygon ().is_box () ? simple_polygon ().box () : box_type ();
|
||||
case db::Shape::SimplePolygonRef:
|
||||
case db::Shape::SimplePolygonPtrArrayMember:
|
||||
return simple_polygon_ref ().is_box () ? simple_polygon_ref ().box () : box_type ();
|
||||
case db::Shape::Path:
|
||||
{
|
||||
const path_type &p = path ();
|
||||
if (! p.round () && p.points () <= 2 && p.points () > 0) {
|
||||
point_type p1 = *p.begin ();
|
||||
point_type p2 = p1;
|
||||
if (p.points () == 2) {
|
||||
p2 = *++p.begin ();
|
||||
}
|
||||
if (p1.x () == p2.x () || p1.y () == p2.y ()) {
|
||||
return p.box ();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case db::Shape::PathRef:
|
||||
case db::Shape::PathPtrArrayMember:
|
||||
{
|
||||
const path_ref_type &p = path_ref ();
|
||||
if (! p.ptr ()->round () && p.ptr ()->points () <= 2 && p.ptr ()->points () > 0) {
|
||||
point_type p1 = *p.begin ();
|
||||
point_type p2 = p1;
|
||||
if (p.ptr ()->points () == 2) {
|
||||
p2 = *++p.begin ();
|
||||
}
|
||||
if (p1.x () == p2.x () || p1.y () == p2.y ()) {
|
||||
return p.box ();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return box_type ();
|
||||
}
|
||||
|
||||
std::string
|
||||
Shape::to_string () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2651,6 +2651,16 @@ public:
|
|||
*/
|
||||
box_type bbox () const;
|
||||
|
||||
/**
|
||||
* @brief Returns the box if the object represents a rectangle or an empty box if not
|
||||
*
|
||||
* This method returns the rectangle (aka box) the shape represents a polygon
|
||||
* that is a rectangle, a path with two points and no rounded ends or an actual box.
|
||||
*
|
||||
* If not, an empty box is returned.
|
||||
*/
|
||||
box_type rectangle () const;
|
||||
|
||||
/**
|
||||
* @brief Compute the area of the shape
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -53,6 +53,12 @@ ShapeProcessor::reserve (size_t n)
|
|||
m_processor.reserve (n);
|
||||
}
|
||||
|
||||
size_t
|
||||
ShapeProcessor::count () const
|
||||
{
|
||||
return m_processor.count ();
|
||||
}
|
||||
|
||||
void
|
||||
ShapeProcessor::process (db::EdgeSink &es, EdgeEvaluatorBase &op)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -196,6 +196,11 @@ public:
|
|||
*/
|
||||
void reserve (size_t n);
|
||||
|
||||
/**
|
||||
* @brief Reports the number of edges stored in the processor
|
||||
*/
|
||||
size_t count () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the base verbosity of the processor (see EdgeProcessor::set_base_verbosity for details)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@
|
|||
#include "dbOriginalLayerTexts.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlVariant.h"
|
||||
|
||||
#include <sstream>
|
||||
|
|
@ -90,6 +92,23 @@ Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::I
|
|||
mp_delegate = new DeepTexts (si, dss, trans);
|
||||
}
|
||||
|
||||
void
|
||||
Texts::write (const std::string &fn) const
|
||||
{
|
||||
// method provided for debugging purposes
|
||||
|
||||
db::Layout layout;
|
||||
const db::Cell &top = layout.cell (layout.add_cell ("TEXTS"));
|
||||
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
|
||||
insert_into (&layout, top.cell_index (), li);
|
||||
|
||||
tl::OutputStream os (fn);
|
||||
db::SaveLayoutOptions opt;
|
||||
opt.set_format_from_filename (fn);
|
||||
db::Writer writer (opt);
|
||||
writer.write (layout, os);
|
||||
}
|
||||
|
||||
template <class Sh>
|
||||
void Texts::insert (const Sh &shape)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -181,6 +181,14 @@ public:
|
|||
*/
|
||||
explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Writes the text collection to a file
|
||||
*
|
||||
* This method is provided for debugging purposes. A flat image of the
|
||||
* region is written to a layout file with a single top cell on layer 0/0.
|
||||
*/
|
||||
void write (const std::string &fn) const;
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -324,6 +324,21 @@ struct box_defs
|
|||
"\n"
|
||||
"@return The joined box\n"
|
||||
) +
|
||||
method ("-", &C::subtracted, gsi::arg ("box"),
|
||||
"@brief Subtraction of boxes\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"The - operator subtracts the argument box from self.\n"
|
||||
"This will return the bounding box of the are covered by self, but not by argument box. "
|
||||
"Subtracting a box from itself will render an empty box. Subtracting another box from "
|
||||
"self will modify the first box only if the argument box covers one side entirely.\n"
|
||||
"\n"
|
||||
"@param box The box to subtract from this box.\n"
|
||||
"\n"
|
||||
"@return The result box\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.29."
|
||||
) +
|
||||
method ("&", &C::intersection, gsi::arg ("box"),
|
||||
"@brief Returns the intersection of this box with another box\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -602,6 +602,12 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
"\n"
|
||||
"This constructor has been introduced in version 0.26."
|
||||
) +
|
||||
method ("write", &db::EdgePairs::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
method ("insert_into", &db::EdgePairs::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
|
||||
"@brief Inserts this edge pairs into the given layout, below the given cell and into the given layer.\n"
|
||||
"If the edge pair collection is a hierarchical one, a suitable hierarchy will be built below the top cell or "
|
||||
|
|
|
|||
|
|
@ -1567,6 +1567,12 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"\n"
|
||||
"This method has been added in version 0.28.\n"
|
||||
) +
|
||||
method ("write", &db::Edges::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
method ("clear", &db::Edges::clear,
|
||||
"@brief Clears the edge collection\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -476,13 +476,29 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("region"),
|
||||
gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether overlapping shapes are selected when a region is used\n"
|
||||
"\n"
|
||||
"If this flag is false, shapes touching the search region are returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("for_merged_input?", &db::RecursiveShapeIterator::for_merged_input,
|
||||
"@brief Gets a flag indicating whether iterator optimizes for merged input\n"
|
||||
"\n"
|
||||
"see \\for_merged_input= for details of this attribute.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("for_merged_input=", &db::RecursiveShapeIterator::set_for_merged_input, gsi::arg ("flag"),
|
||||
"@brief Sets a flag indicating whether iterator optimizes for merged input\n"
|
||||
"\n"
|
||||
"If this flag is set to true, the iterator is allowed to skip shapes it deems irrelevant "
|
||||
"because they are covered entirely by other shapes. This allows shortcutting hierarchy traversal in "
|
||||
"some cases.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.\n"
|
||||
) +
|
||||
gsi::method ("unselect_all_cells", &db::RecursiveShapeIterator::unselect_all_cells,
|
||||
"@brief Unselects all cells.\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -270,15 +270,6 @@ static db::Region *new_path (const db::Path &o)
|
|||
return new db::Region (o);
|
||||
}
|
||||
|
||||
static db::Region *new_shapes (const db::Shapes &s)
|
||||
{
|
||||
db::Region *r = new db::Region ();
|
||||
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::All); !i.at_end (); ++i) {
|
||||
r->insert (*i);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static db::Region *new_texts_as_boxes1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern, db::Coord enl)
|
||||
{
|
||||
return new db::Region (db::Region (si).texts_as_boxes (pat, pattern, enl));
|
||||
|
|
@ -329,16 +320,26 @@ static db::Region *new_si (const db::RecursiveShapeIterator &si)
|
|||
return new db::Region (si);
|
||||
}
|
||||
|
||||
static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
{
|
||||
return new db::Region (si, dss, area_ratio, max_vertex_count);
|
||||
}
|
||||
|
||||
static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
return new db::Region (si, trans);
|
||||
}
|
||||
|
||||
static db::Region *new_sis (const db::Shapes &si)
|
||||
{
|
||||
return new db::Region (si);
|
||||
}
|
||||
|
||||
static db::Region *new_sis2 (const db::Shapes &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
return new db::Region (si, trans);
|
||||
}
|
||||
|
||||
static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
{
|
||||
return new db::Region (si, dss, area_ratio, max_vertex_count);
|
||||
}
|
||||
|
||||
static db::Region *new_sid2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const db::ICplxTrans &trans, double area_ratio, size_t max_vertex_count)
|
||||
{
|
||||
return new db::Region (si, dss, trans, true, area_ratio, max_vertex_count);
|
||||
|
|
@ -1088,13 +1089,6 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This constructor creates a region from a path.\n"
|
||||
) +
|
||||
constructor ("new", &new_shapes, gsi::arg ("shapes"),
|
||||
"@brief Shapes constructor\n"
|
||||
"\n"
|
||||
"This constructor creates a region from a \\Shapes collection.\n"
|
||||
"\n"
|
||||
"This constructor has been introduced in version 0.25."
|
||||
) +
|
||||
constructor ("new", &new_si, gsi::arg ("shape_iterator"),
|
||||
"@brief Constructor from a hierarchical shape set\n"
|
||||
"\n"
|
||||
|
|
@ -1126,6 +1120,24 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
constructor ("new", &new_sis, gsi::arg ("shapes"),
|
||||
"@brief Constructor from a shapes container\n"
|
||||
"\n"
|
||||
"This constructor creates a region from the shapes container.\n"
|
||||
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
|
||||
"This method allows feeding the shapes from a hierarchy of cells into the region.\n"
|
||||
"\n"
|
||||
"This constructor has been introduced in version 0.25 and extended in version 0.29."
|
||||
) +
|
||||
constructor ("new", &new_sis2, gsi::arg ("shapes"), gsi::arg ("trans"),
|
||||
"@brief Constructor from a shapes container with a transformation\n"
|
||||
"\n"
|
||||
"This constructor creates a region from the shapes container after applying the transformation.\n"
|
||||
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
|
||||
"This method allows feeding the shapes from a hierarchy of cells into the region.\n"
|
||||
"\n"
|
||||
"This constructor variant has been introduced in version 0.29."
|
||||
) +
|
||||
constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("deep_shape_store"), gsi::arg ("area_ratio", 0.0), gsi::arg ("max_vertex_count", size_t (0)),
|
||||
"@brief Constructor for a deep region from a hierarchical shape set\n"
|
||||
"\n"
|
||||
|
|
@ -1209,6 +1221,12 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.26."
|
||||
) +
|
||||
method ("write", &db::Region::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
factory_ext ("texts", &texts_as_boxes1, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true), gsi::arg ("enl", 1),
|
||||
"@hide\n"
|
||||
"This method is provided for DRC implementation only."
|
||||
|
|
|
|||
|
|
@ -669,6 +669,26 @@ static tl::Variant get_dbox (const db::Shape *s)
|
|||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_rectangle (const db::Shape *s)
|
||||
{
|
||||
db::Shape::box_type b = s->rectangle ();
|
||||
if (! b.empty ()) {
|
||||
return tl::Variant (b);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_drectangle (const db::Shape *s)
|
||||
{
|
||||
db::Shape::box_type b = s->rectangle ();
|
||||
if (! b.empty ()) {
|
||||
return tl::Variant (db::CplxTrans (shape_dbu (s)) * b);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
static tl::Variant get_edge (const db::Shape *s)
|
||||
{
|
||||
db::Shape::edge_type p;
|
||||
|
|
@ -1982,6 +2002,22 @@ Class<db::Shape> decl_Shape ("db", "Shape",
|
|||
"\n"
|
||||
"This method has been added in version 0.25.\n"
|
||||
) +
|
||||
gsi::method_ext ("rectangle", &get_rectangle,
|
||||
"@brief Gets the rectangle if the object represents one or nil if not\n"
|
||||
"\n"
|
||||
"If the shape represents a rectangle - i.e. a box or box polygon, a path with two points and no round ends - "
|
||||
"this method returns the box. If not, nil is returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method_ext ("drectangle", &get_drectangle,
|
||||
"@brief Gets the rectangle in micron units if the object represents one or nil if not\n"
|
||||
"\n"
|
||||
"If the shape represents a rectangle - i.e. a box or box polygon, a path with two points and no round ends - "
|
||||
"this method returns the box. If not, nil is returned.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
gsi::method ("is_user_object?", &db::Shape::is_user_object,
|
||||
"@brief Returns true if the shape is a user defined object\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -436,6 +436,12 @@ Class<db::Texts> decl_Texts (decl_dbShapeCollection, "db", "Texts",
|
|||
"r = RBA::Texts::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
method ("write", &db::Texts::write, gsi::arg ("filename"),
|
||||
"@brief Writes the region to a file\n"
|
||||
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29."
|
||||
) +
|
||||
method ("insert_into", &db::Texts::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
|
||||
"@brief Inserts this texts into the given layout, below the given cell and into the given layer.\n"
|
||||
"If the text collection is a hierarchical one, a suitable hierarchy will be built below the top cell or "
|
||||
|
|
|
|||
|
|
@ -49,6 +49,17 @@ TEST(2)
|
|||
EXPECT_EQ (b & db::Box (110, 220, 120, 250), empty);
|
||||
EXPECT_EQ (b & db::Box (50, 100, 120, 250), db::Box (50, 100, 100, 200));
|
||||
EXPECT_EQ (b & db::Box (50, 100, 60, 120), db::Box (50, 100, 60, 120));
|
||||
EXPECT_EQ (b - b, db::Box ());
|
||||
EXPECT_EQ (b - db::Box (), b);
|
||||
EXPECT_EQ (db::Box () - b, db::Box ());
|
||||
EXPECT_EQ (db::Box () - db::Box (), db::Box ());
|
||||
EXPECT_EQ (b - db::Box (0, 0, 50, 50), b);
|
||||
EXPECT_EQ (b - db::Box (0, 0, 50, 200), db::Box (50, 0, 100, 200));
|
||||
EXPECT_EQ (b - db::Box (50, 0, 100, 200), db::Box (0, 0, 50, 200));
|
||||
EXPECT_EQ (b - db::Box (0, 0, 100, 100), db::Box (0, 100, 100, 200));
|
||||
EXPECT_EQ (b - db::Box (0, 100, 100, 200), db::Box (0, 0, 100, 100));
|
||||
EXPECT_EQ (db::Box::world () - b, db::Box::world ());
|
||||
EXPECT_EQ (b - db::Box::world (), db::Box ());
|
||||
|
||||
empty.move (db::Vector (10, 20));
|
||||
EXPECT_EQ (empty == db::Box (), true);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "dbHierProcessor.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbReader.h"
|
||||
|
|
@ -32,6 +33,9 @@
|
|||
#include "dbLocalOperationUtils.h"
|
||||
#include "dbRegionLocalOperations.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbRecursiveInstanceIterator.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
static std::string testdata (const std::string &fn)
|
||||
{
|
||||
|
|
@ -1284,3 +1288,87 @@ TEST(Arrays)
|
|||
run_test_bool2 (_this, "hlp18.oas", TMNot, 100);
|
||||
}
|
||||
|
||||
TEST(XORTool)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
||||
std::string fna (tl::combine_path (tl::testdata_private (), "xor/a.gds.gz"));
|
||||
std::string fnb (tl::combine_path (tl::testdata_private (), "xor/b.gds.gz"));
|
||||
std::string fn_au (tl::combine_path (tl::testdata_private (), "xor/xor_au.oas.gz"));
|
||||
|
||||
db::Layout lya, lyb;
|
||||
|
||||
unsigned int l1, l2;
|
||||
|
||||
db::LayerMap lmap;
|
||||
|
||||
lmap.map (db::LDPair (1, 0), l1 = lya.insert_layer ());
|
||||
lyb.insert_layer ();
|
||||
|
||||
lmap.map (db::LDPair (2, 0), l2 = lya.insert_layer ());
|
||||
lyb.insert_layer ();
|
||||
|
||||
{
|
||||
tl::InputStream stream (fna);
|
||||
db::Reader reader (stream);
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
reader.read (lya, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream stream (fnb);
|
||||
db::Reader reader (stream);
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
|
||||
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
|
||||
reader.read (lyb, options);
|
||||
}
|
||||
|
||||
db::Layout ly_out;
|
||||
db::cell_index_type top_out = ly_out.add_cell ("TOP");
|
||||
unsigned int l1_out = ly_out.insert_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2_out = ly_out.insert_layer (db::LayerProperties (2, 0));
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_wants_all_cells (true); // saves time for less cell mapping operations
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator ri_a, ri_b;
|
||||
|
||||
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l1);
|
||||
ri_a.set_for_merged_input (true);
|
||||
|
||||
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l1);
|
||||
ri_b.set_for_merged_input (true);
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
|
||||
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
|
||||
|
||||
db::Region xor_res = in_a ^ in_b;
|
||||
EXPECT_EQ (xor_res.count (), size_t (12));
|
||||
|
||||
xor_res.insert_into (&ly_out, top_out, l1_out);
|
||||
}
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator ri_a, ri_b;
|
||||
|
||||
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l2);
|
||||
ri_a.set_for_merged_input (true);
|
||||
|
||||
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l2);
|
||||
ri_b.set_for_merged_input (true);
|
||||
|
||||
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
|
||||
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
|
||||
|
||||
db::Region xor_res = in_a ^ in_b;
|
||||
EXPECT_EQ (xor_res.count (), size_t (15984));
|
||||
|
||||
xor_res.insert_into (&ly_out, top_out, l2_out);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, ly_out, fn_au, db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
#include "dbLayoutDiff.h"
|
||||
#include "tlString.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlStream.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbWriter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -1554,3 +1558,225 @@ TEST(11_LayoutIsWeakPointer)
|
|||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "");
|
||||
}
|
||||
|
||||
TEST(12_ForMerged)
|
||||
{
|
||||
std::unique_ptr<db::Layout> g (new db::Layout ());
|
||||
g->insert_layer (0);
|
||||
g->insert_layer (1);
|
||||
db::Cell &c0 (g->cell (g->add_cell ()));
|
||||
db::Cell &c1 (g->cell (g->add_cell ()));
|
||||
db::Cell &c2 (g->cell (g->add_cell ()));
|
||||
db::Cell &c3 (g->cell (g->add_cell ()));
|
||||
|
||||
db::Box b (0, 100, 1000, 1200);
|
||||
c0.shapes (0).insert (db::Box (0, 0, 3000, 2000));
|
||||
c1.shapes (0).insert (b);
|
||||
c2.shapes (0).insert (b);
|
||||
c3.shapes (0).insert (b);
|
||||
|
||||
db::Trans tt;
|
||||
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
|
||||
c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100))));
|
||||
c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1)));
|
||||
c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0))));
|
||||
|
||||
std::string x;
|
||||
|
||||
db::RecursiveShapeIterator i1 (*g, c0, 0);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
std::vector<unsigned int> lv;
|
||||
lv.push_back (0);
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, lv);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
lv.push_back (1); // empty, but kills "for merged" optimization
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, lv);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
// no longer optimized
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-100, 0, 100, 50));
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-101, 0, 100, 50));
|
||||
i1.set_overlapping (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
|
||||
i1.set_for_merged_input (true);
|
||||
x = collect(i1, *g);
|
||||
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
|
||||
}
|
||||
|
||||
|
||||
TEST(13_ForMergedPerformance)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
||||
std::string fn (tl::combine_path (tl::testdata_private (), "oasis/caravel.oas.gz"));
|
||||
|
||||
db::Layout ly;
|
||||
|
||||
{
|
||||
tl::InputStream is (fn);
|
||||
db::Reader reader (is);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
unsigned l1 = ly.get_layer (db::LayerProperties (66, 20));
|
||||
unsigned l2 = ly.get_layer (db::LayerProperties (235, 4));
|
||||
|
||||
db::RecursiveShapeIterator si1 (ly, ly.cell (*ly.begin_top_down ()), l1);
|
||||
db::RecursiveShapeIterator si2 (ly, ly.cell (*ly.begin_top_down ()), l2);
|
||||
|
||||
size_t n1_expected_full = db::default_editable_mode () ? 1203072 : 1203078;
|
||||
size_t n2_expected_full = 10;
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (1218378));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (57462));
|
||||
}
|
||||
|
||||
si1.set_for_merged_input (true);
|
||||
si2.set_for_merged_input (true);
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (n1_expected_full));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (n2_expected_full));
|
||||
}
|
||||
|
||||
si1.set_for_merged_input (false);
|
||||
si1.set_region (db::Box (0, 0, 1000000, 1000000));
|
||||
si2.set_for_merged_input (false);
|
||||
si2.set_region (db::Box (0, 0, 1000000, 1000000));
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (218823));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("Standard loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (2578));
|
||||
}
|
||||
|
||||
si1.set_for_merged_input (true);
|
||||
si2.set_for_merged_input (true);
|
||||
|
||||
size_t n1_expected = db::default_editable_mode () ? 218068 : 218069;
|
||||
size_t n2_expected = 2;
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 66/20");
|
||||
size_t n = 0;
|
||||
while (! si1.at_end ()) {
|
||||
++si1;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 66/20";
|
||||
EXPECT_EQ (n, size_t (n1_expected));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("'for_merged' loop on 235/4");
|
||||
size_t n = 0;
|
||||
while (! si2.at_end ()) {
|
||||
++si2;
|
||||
++n;
|
||||
}
|
||||
tl::info << "Counted " << n << " shapes on 235/4";
|
||||
EXPECT_EQ (n, size_t (n2_expected));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("XOR on tile of 66/20");
|
||||
si1.set_for_merged_input (false);
|
||||
db::Region r1 (si1);
|
||||
si1.set_for_merged_input (true);
|
||||
db::Region r2 (si1);
|
||||
|
||||
EXPECT_EQ (r1.count (), size_t (218823));
|
||||
EXPECT_EQ (r2.count (), size_t (n1_expected));
|
||||
EXPECT_EQ ((r1 ^ r2).count (), size_t (0));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("XOR on tile of 235/4");
|
||||
si2.set_for_merged_input (false);
|
||||
db::Region r1 (si2);
|
||||
si2.set_for_merged_input (true);
|
||||
db::Region r2 (si2);
|
||||
|
||||
EXPECT_EQ (r1.count (), size_t (2578));
|
||||
EXPECT_EQ (r2.count (), size_t (n2_expected));
|
||||
EXPECT_EQ ((r1 ^ r2).count (), size_t (0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2537,6 +2537,35 @@ TEST(55_PropertiesFilterFlat)
|
|||
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
|
||||
}
|
||||
|
||||
TEST(56_RegionsFromShapes)
|
||||
{
|
||||
db::Shapes shapes;
|
||||
|
||||
shapes.insert (db::Box (0, 0, 100, 200));
|
||||
shapes.insert (db::Box (50, 50, 150, 250));
|
||||
|
||||
EXPECT_EQ (db::Region (shapes).area (), 32500);
|
||||
EXPECT_EQ (db::Region (shapes, false).area (), 40000);
|
||||
EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5)).area (), 8125);
|
||||
EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5), false).area (), 10000);
|
||||
|
||||
// for cross-checking: same for RecursiveShapeIterator
|
||||
|
||||
db::Layout layout;
|
||||
unsigned int l1 = layout.insert_layer ();
|
||||
db::Cell &top = layout.cell (layout.add_cell ("TOP"));
|
||||
|
||||
top.shapes (l1).insert (db::Box (0, 0, 100, 200));
|
||||
top.shapes (l1).insert (db::Box (50, 50, 150, 250));
|
||||
|
||||
db::RecursiveShapeIterator si (layout, top, l1);
|
||||
|
||||
EXPECT_EQ (db::Region (si).area (), 32500);
|
||||
EXPECT_EQ (db::Region (si, false).area (), 40000);
|
||||
EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5)).area (), 8125);
|
||||
EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5), false).area (), 10000);
|
||||
}
|
||||
|
||||
TEST(100_Processors)
|
||||
{
|
||||
db::Region r;
|
||||
|
|
|
|||
|
|
@ -948,3 +948,89 @@ TEST(9)
|
|||
EXPECT_EQ (si.at_end (), true);
|
||||
}
|
||||
|
||||
// Rectangle
|
||||
TEST(10)
|
||||
{
|
||||
db::Manager m (true);
|
||||
db::Shapes s (&m, 0, db::default_editable_mode ());
|
||||
db::ShapeIterator si;
|
||||
|
||||
s.insert (db::Point (100, 200));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Edge (db::Point (100, 200), db::Point (200, 400)));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::EdgePair (db::Edge (db::Point (100, 200), db::Point (200, 400)), db::Edge (db::Point (0, 300), db::Point (100, 500))));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Box (0, 0, 1000, 2000));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::ShortBox (0, 0, 1000, 2000));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Polygon (db::Box (0, 0, 1000, 2000)));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Polygon ());
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::SimplePolygon ());
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path ());
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
db::Point pts1 [1] = { db::Point (0, 0) };
|
||||
db::Point pts2 [2] = { db::Point (0, 0), db::Point (1000, 0) };
|
||||
db::Point pts2b [2] = { db::Point (0, 0), db::Point (1000, 1000) };
|
||||
db::Point pts3 [3] = { db::Point (0, 0), db::Point (1000, 0), db::Point (1000, 1000) };
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts1 + 0, pts1 + 1, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (-500, -500, 500, 500));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts2 + 0, pts2 + 2, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle (), db::Box (-500, -500, 1500, 500));
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts2 + 0, pts2 + 2, 1000, 500, 500, true));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts2b + 0, pts2b + 2, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
|
||||
s.clear ();
|
||||
s.insert (db::Path (pts3 + 0, pts3 + 3, 1000, 500, 500));
|
||||
si = s.begin (db::ShapeIterator::All);
|
||||
EXPECT_EQ (si->rectangle ().empty (), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@
|
|||
namespace tl
|
||||
{
|
||||
|
||||
extern const nullopt_t nullopt = nullopt_t ();
|
||||
const nullopt_t nullopt = nullopt_t ();
|
||||
|
||||
} // namespace tl
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace tl
|
|||
|
||||
struct nullopt_t {};
|
||||
|
||||
extern const nullopt_t nullopt;
|
||||
extern TL_PUBLIC const nullopt_t nullopt;
|
||||
|
||||
/**
|
||||
* @brief Poor man's partial implementation of C++17's std::optional
|
||||
|
|
|
|||
|
|
@ -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)" )
|
||||
|
||||
|
|
|
|||
|
|
@ -322,6 +322,38 @@ END
|
|||
|
||||
end
|
||||
|
||||
def test_3
|
||||
|
||||
l = RBA::Layout.new
|
||||
l.insert_layer_at(0, RBA::LayerInfo.new(1, 0))
|
||||
l.insert_layer_at(1, RBA::LayerInfo.new(2, 0))
|
||||
c0 = l.cell(l.add_cell("c0"))
|
||||
c1 = l.cell(l.add_cell("c1"))
|
||||
c2 = l.cell(l.add_cell("c2"))
|
||||
c3 = l.cell(l.add_cell("c3"))
|
||||
|
||||
b = RBA::Box.new(0, 100, 1000, 1200)
|
||||
c0.shapes(0).insert(RBA::Box.new(0, 0, 3000, 2000))
|
||||
c1.shapes(0).insert(b)
|
||||
c2.shapes(0).insert(b)
|
||||
c3.shapes(0).insert(b)
|
||||
|
||||
tt = RBA::Trans.new
|
||||
c0.insert(RBA::CellInstArray.new(c1.cell_index, tt))
|
||||
c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Vector.new(100, -100))))
|
||||
c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1)))
|
||||
c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Vector.new(1100, 0))))
|
||||
|
||||
ii = RBA::RecursiveShapeIterator.new(l, c0, 0)
|
||||
assert_equal(ii.for_merged_input, false)
|
||||
assert_equal(collect(ii, l), "[c0](0,0;3000,2000)/[c1](0,100;1000,1200)/[c2](100,0;1100,1100)/[c3](1200,0;2200,1100)/[c3](-1200,0;-100,1000)")
|
||||
|
||||
ii.for_merged_input = true
|
||||
assert_equal(ii.for_merged_input, true)
|
||||
assert_equal(collect(ii, l), "[c0](0,0;3000,2000)/[c3](-1200,0;-100,1000)")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -1066,6 +1066,47 @@ class DBRegion_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# regions from Shapes
|
||||
def test_regions_from_shapes
|
||||
|
||||
shapes = RBA::Shapes::new;
|
||||
|
||||
shapes.insert(RBA::Box::new(0, 0, 100, 200))
|
||||
shapes.insert(RBA::Box::new(50, 50, 150, 250))
|
||||
|
||||
assert_equal(RBA::Region::new(shapes).area, 32500)
|
||||
region = RBA::Region::new(shapes)
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 40000)
|
||||
|
||||
assert_equal(RBA::Region::new(shapes, RBA::ICplxTrans::new(0.5)).area, 8125)
|
||||
region = RBA::Region::new(shapes, RBA::ICplxTrans::new(0.5))
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 10000)
|
||||
|
||||
# for cross-checking: same for RecursiveShapeIterator
|
||||
|
||||
layout = RBA::Layout::new
|
||||
l1 = layout.insert_layer(RBA::LayerInfo::new(1, 0))
|
||||
top = layout.create_cell("TOP")
|
||||
|
||||
top.shapes(l1).insert (RBA::Box::new(0, 0, 100, 200))
|
||||
top.shapes(l1).insert (RBA::Box::new(50, 50, 150, 250))
|
||||
|
||||
si = RBA::RecursiveShapeIterator::new(layout, top, l1)
|
||||
|
||||
assert_equal(RBA::Region::new(si).area, 32500)
|
||||
region = RBA::Region::new(si)
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 40000)
|
||||
|
||||
assert_equal(RBA::Region::new(si, RBA::ICplxTrans::new(0.5)).area, 8125)
|
||||
region = RBA::Region::new(si, RBA::ICplxTrans::new(0.5))
|
||||
region.merged_semantics = false
|
||||
assert_equal(region.area, 10000)
|
||||
|
||||
end
|
||||
|
||||
# deep region tests
|
||||
def test_deep1
|
||||
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].is_polygon?, false )
|
||||
assert_equal( arr[0].is_box?, true )
|
||||
assert_equal( arr[0].box.to_s, "(10,-10;50,40)" )
|
||||
assert_equal( arr[0].rectangle.to_s, "(10,-10;50,40)" )
|
||||
assert_equal( arr[0].bbox.to_s, "(10,-10;50,40)" )
|
||||
|
||||
# edges
|
||||
|
|
@ -198,6 +199,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].edge.to_s, "(-1,2;5,2)" )
|
||||
assert_equal( arr[0].edge_pair.inspect, "nil" )
|
||||
assert_equal( arr[0].box.inspect, "nil" )
|
||||
assert_equal( arr[0].rectangle.inspect, "nil" )
|
||||
assert_equal( arr[0].path.inspect, "nil" )
|
||||
assert_equal( arr[0].text.inspect, "nil" )
|
||||
assert_equal( arr[0].edge == a, true )
|
||||
|
|
@ -533,6 +535,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].dedge.inspect, "nil" )
|
||||
assert_equal( arr[0].dedge_pair.inspect, "nil" )
|
||||
assert_equal( arr[0].dbox.to_s, "(0.01,-0.01;0.05,0.04)" )
|
||||
assert_equal( arr[0].drectangle.to_s, "(0.01,-0.01;0.05,0.04)" )
|
||||
assert_equal( arr[0].dpath.inspect, "nil" )
|
||||
assert_equal( arr[0].dtext.inspect, "nil" )
|
||||
assert_equal( arr[0].is_polygon?, false )
|
||||
|
|
@ -557,6 +560,7 @@ class DBShapes_TestClass < TestBase
|
|||
assert_equal( arr[0].dedge.to_s, "(-0.001,0.002;0.005,0.002)" )
|
||||
assert_equal( arr[0].dedge_pair.inspect, "nil" )
|
||||
assert_equal( arr[0].dbox.inspect, "nil" )
|
||||
assert_equal( arr[0].drectangle.inspect, "nil" )
|
||||
assert_equal( arr[0].dpath.inspect, "nil" )
|
||||
assert_equal( arr[0].dtext.inspect, "nil" )
|
||||
assert_equal( arr[0].dbbox.to_s, "(-0.001,0.002;0.005,0.002)" )
|
||||
|
|
|
|||
Loading…
Reference in New Issue