mirror of https://github.com/KLayout/klayout.git
WIP: refactoring, more property support, DRC integration, bug fixes ...
This commit is contained in:
parent
7ba3133afc
commit
9f27aa9f51
|
|
@ -151,6 +151,7 @@ RegionDelegate *
|
|||
AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const
|
||||
{
|
||||
std::unique_ptr<FlatRegion> region (new FlatRegion ());
|
||||
db::PropertyMapper pm (region->properties_repository (), properties_repository ());
|
||||
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
region->set_merged_semantics (false);
|
||||
|
|
@ -162,8 +163,9 @@ AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &
|
|||
res_polygons.clear ();
|
||||
filter.process (*e, res_polygons);
|
||||
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
|
||||
if (e.prop_id () != 0) {
|
||||
region->insert (db::PolygonWithProperties (*pr, e.prop_id ()));
|
||||
db::properties_id_type prop_id = pm (e.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
region->insert (db::PolygonWithProperties (*pr, prop_id));
|
||||
} else {
|
||||
region->insert (*pr);
|
||||
}
|
||||
|
|
@ -177,6 +179,7 @@ EdgesDelegate *
|
|||
AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const
|
||||
{
|
||||
std::unique_ptr<FlatEdges> edges (new FlatEdges ());
|
||||
db::PropertyMapper pm (edges->properties_repository (), properties_repository ());
|
||||
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
edges->set_merged_semantics (false);
|
||||
|
|
@ -188,8 +191,9 @@ AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter
|
|||
res_edges.clear ();
|
||||
filter.process (*e, res_edges);
|
||||
for (std::vector<db::Edge>::const_iterator pr = res_edges.begin (); pr != res_edges.end (); ++pr) {
|
||||
if (e.prop_id () != 0) {
|
||||
edges->insert (db::EdgeWithProperties (*pr, e.prop_id ()));
|
||||
db::properties_id_type prop_id = pm (e.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
edges->insert (db::EdgeWithProperties (*pr, prop_id));
|
||||
} else {
|
||||
edges->insert (*pr);
|
||||
}
|
||||
|
|
@ -203,10 +207,16 @@ EdgePairsDelegate *
|
|||
AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const
|
||||
{
|
||||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
|
||||
db::PropertyMapper pm (new_edge_pairs->properties_repository (), properties_repository ());
|
||||
|
||||
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
if (filter.selected (*p)) {
|
||||
new_edge_pairs->insert (*p);
|
||||
db::properties_id_type prop_id = pm (p.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
new_edge_pairs->insert (db::EdgePairWithProperties (*p, prop_id));
|
||||
} else {
|
||||
new_edge_pairs->insert (*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,11 +227,17 @@ RegionDelegate *
|
|||
AsIfFlatEdgePairs::polygons (db::Coord e) const
|
||||
{
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
||||
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||
|
||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||
db::Polygon poly = ep->normalized ().to_polygon (e);
|
||||
if (poly.vertices () >= 3) {
|
||||
output->insert (poly);
|
||||
db::properties_id_type prop_id = pm (ep.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
output->insert (db::PolygonWithProperties (poly, prop_id));
|
||||
} else {
|
||||
output->insert (poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,10 +248,17 @@ EdgesDelegate *
|
|||
AsIfFlatEdgePairs::edges () const
|
||||
{
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
||||
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||
|
||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||
output->insert (ep->first ());
|
||||
output->insert (ep->second ());
|
||||
db::properties_id_type prop_id = pm (ep.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
output->insert (db::EdgeWithProperties (ep->first (), prop_id));
|
||||
output->insert (db::EdgeWithProperties (ep->second (), prop_id));
|
||||
} else {
|
||||
output->insert (ep->first ());
|
||||
output->insert (ep->second ());
|
||||
}
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
|
|
@ -245,9 +268,15 @@ EdgesDelegate *
|
|||
AsIfFlatEdgePairs::first_edges () const
|
||||
{
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
||||
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||
|
||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||
output->insert (ep->first ());
|
||||
db::properties_id_type prop_id = pm (ep.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
output->insert (db::EdgeWithProperties (ep->first (), prop_id));
|
||||
} else {
|
||||
output->insert (ep->first ());
|
||||
}
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
|
|
@ -257,9 +286,15 @@ EdgesDelegate *
|
|||
AsIfFlatEdgePairs::second_edges () const
|
||||
{
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
||||
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||
|
||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||
output->insert (ep->second ());
|
||||
db::properties_id_type prop_id = pm (ep.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
output->insert (db::EdgeWithProperties (ep->second (), prop_id));
|
||||
} else {
|
||||
output->insert (ep->second ());
|
||||
}
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
|
|
@ -274,12 +309,19 @@ AsIfFlatEdgePairs::add (const EdgePairs &other) const
|
|||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*other_flat));
|
||||
new_edge_pairs->invalidate_cache ();
|
||||
|
||||
db::PropertyMapper pm (new_edge_pairs->properties_repository (), properties_repository ());
|
||||
|
||||
size_t n = new_edge_pairs->raw_edge_pairs ().size () + count ();
|
||||
|
||||
new_edge_pairs->reserve (n);
|
||||
|
||||
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
db::properties_id_type prop_id = pm (p.prop_id ());
|
||||
if (prop_id) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (db::EdgePairWithProperties (*p, prop_id));
|
||||
} else {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
return new_edge_pairs.release ();
|
||||
|
|
@ -288,15 +330,28 @@ AsIfFlatEdgePairs::add (const EdgePairs &other) const
|
|||
|
||||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
|
||||
|
||||
db::PropertyMapper pm (new_edge_pairs->properties_repository (), properties_repository ());
|
||||
db::PropertyMapper pm_other (new_edge_pairs->properties_repository (), &other.properties_repository ());
|
||||
|
||||
size_t n = count () + other.count ();
|
||||
|
||||
new_edge_pairs->reserve (n);
|
||||
|
||||
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
db::properties_id_type prop_id = pm (p.prop_id ());
|
||||
if (prop_id) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (db::EdgePairWithProperties (*p, prop_id));
|
||||
} else {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
}
|
||||
}
|
||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
db::properties_id_type prop_id = pm_other (p.prop_id ());
|
||||
if (prop_id) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (db::EdgePairWithProperties (*p, prop_id));
|
||||
} else {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
return new_edge_pairs.release ();
|
||||
|
|
@ -352,9 +407,16 @@ AsIfFlatEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, u
|
|||
// improves performance when inserting an original layout into the same layout
|
||||
db::LayoutLocker locker (layout);
|
||||
|
||||
db::PropertyMapper pm (&layout->properties_repository (), properties_repository ());
|
||||
|
||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
|
||||
shapes.insert (*e);
|
||||
db::properties_id_type prop_id = pm (e.prop_id ());
|
||||
if (prop_id) {
|
||||
shapes.insert (db::EdgePairWithProperties (*e, prop_id));
|
||||
} else {
|
||||
shapes.insert (*e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,9 +426,16 @@ AsIfFlatEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type
|
|||
// improves performance when inserting an original layout into the same layout
|
||||
db::LayoutLocker locker (layout);
|
||||
|
||||
db::PropertyMapper pm (&layout->properties_repository (), properties_repository ());
|
||||
|
||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
|
||||
shapes.insert (e->normalized ().to_simple_polygon (enl));
|
||||
db::properties_id_type prop_id = pm (e.prop_id ());
|
||||
if (prop_id) {
|
||||
shapes.insert (db::SimplePolygonWithProperties (e->normalized ().to_simple_polygon (enl), prop_id));
|
||||
} else {
|
||||
shapes.insert (e->normalized ().to_simple_polygon (enl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -480,6 +480,8 @@ AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, c
|
|||
{
|
||||
if (join) {
|
||||
|
||||
// TODO: property support?
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
||||
db::ShapeGenerator sg (output->raw_polygons (), false);
|
||||
JoinEdgesClusterCollector cluster_collector (&sg, ext_b, ext_e, ext_o, ext_i);
|
||||
|
|
@ -502,8 +504,15 @@ AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, c
|
|||
} else {
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
||||
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||
|
||||
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
|
||||
output->insert (extended_edge (*e, ext_b, ext_e, ext_o, ext_i));
|
||||
db::properties_id_type prop_id = pm (e.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
output->insert (db::PolygonWithProperties (extended_edge (*e, ext_b, ext_e, ext_o, ext_i), prop_id));
|
||||
} else {
|
||||
output->insert (extended_edge (*e, ext_b, ext_e, ext_o, ext_i));
|
||||
}
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
|
|
|
|||
|
|
@ -1112,6 +1112,11 @@ AsIfFlatRegion::inside_check (const Region &other, db::Coord d, const RegionChec
|
|||
EdgePairsDelegate *
|
||||
AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
|
||||
{
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (options.prop_constraint == DifferentPropertiesConstraint) {
|
||||
different_polygons = true;
|
||||
}
|
||||
|
||||
bool needs_merged_primary = different_polygons || options.needs_merged ();
|
||||
|
||||
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
|
||||
|
|
@ -1172,7 +1177,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
|
||||
db::check_local_operation_with_properties<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, has_other, other_is_merged, options, output->properties_repository (), subject_pr, intruder_pr);
|
||||
|
||||
db::local_processor<db::PolygonWithProperties, db::PolygonWithProperties, db::EdgePair> proc;
|
||||
db::local_processor<db::PolygonWithProperties, db::PolygonWithProperties, db::EdgePairWithProperties> proc;
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_description (progress_desc ());
|
||||
proc.set_report_progress (report_progress ());
|
||||
|
|
@ -1362,6 +1367,8 @@ AsIfFlatRegion::and_with (const Region &other, PropertyConstraint property_const
|
|||
|
||||
} else if (property_constraint == db::IgnoreProperties && is_box () && other.is_box ()) {
|
||||
|
||||
// @@@ TODO: implement this with property constraints as that is important for the clip implementation!
|
||||
|
||||
// Simplified handling for boxes
|
||||
db::Box b = bbox ();
|
||||
b &= other.bbox ();
|
||||
|
|
@ -1369,6 +1376,8 @@ AsIfFlatRegion::and_with (const Region &other, PropertyConstraint property_const
|
|||
|
||||
} else if (property_constraint == db::IgnoreProperties && is_box () && ! other.strict_handling ()) {
|
||||
|
||||
// @@@ TODO: implement this with property constraints as that is important for the clip implementation!
|
||||
|
||||
// map AND with box to clip ..
|
||||
db::Box b = bbox ();
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
|
@ -1384,6 +1393,8 @@ AsIfFlatRegion::and_with (const Region &other, PropertyConstraint property_const
|
|||
|
||||
} else if (property_constraint == db::IgnoreProperties && other.is_box () && ! strict_handling ()) {
|
||||
|
||||
// @@@ TODO: implement this with property constraints as that is important for the clip implementation!
|
||||
|
||||
// map AND with box to clip ..
|
||||
db::Box b = other.bbox ();
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
|
@ -1794,8 +1805,9 @@ AsIfFlatRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsi
|
|||
|
||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||
for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
if (p.prop_id () != 0) {
|
||||
shapes.insert (db::PolygonWithProperties (*p, pm (p.prop_id ())));
|
||||
db::properties_id_type prop_id = p.prop_id ();
|
||||
if (prop_id != 0) {
|
||||
shapes.insert (db::PolygonWithProperties (*p, pm (prop_id)));
|
||||
} else {
|
||||
shapes.insert (*p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1548,6 +1548,11 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
|
|||
{
|
||||
set_description ("check");
|
||||
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (m_options.prop_constraint == DifferentPropertiesConstraint) {
|
||||
m_different_polygons = true;
|
||||
}
|
||||
|
||||
m_check.set_include_zero (false);
|
||||
m_check.set_whole_edges (options.whole_edges);
|
||||
m_check.set_ignore_angle (options.ignore_angle);
|
||||
|
|
|
|||
|
|
@ -473,7 +473,11 @@ RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const
|
|||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
db::Polygon poly = s->edge_pair ().normalized ().to_polygon (e);
|
||||
if (poly.vertices () >= 3) {
|
||||
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
if (s->prop_id () != 0) {
|
||||
output.insert (db::PolygonRefWithProperties (db::PolygonRef (poly, layout.shape_repository ()), s->prop_id ()));
|
||||
} else {
|
||||
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -491,10 +495,18 @@ EdgesDelegate *DeepEdgePairs::generic_edges (bool first, bool second) const
|
|||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
db::EdgePair ep = s->edge_pair ();
|
||||
if (first) {
|
||||
output.insert (ep.first ());
|
||||
if (s->prop_id () != 0) {
|
||||
output.insert (db::EdgeWithProperties (ep.first (), s->prop_id ()));
|
||||
} else {
|
||||
output.insert (ep.first ());
|
||||
}
|
||||
}
|
||||
if (second) {
|
||||
output.insert (ep.second ());
|
||||
if (s->prop_id () != 0) {
|
||||
output.insert (db::EdgeWithProperties (ep.second (), s->prop_id ()));
|
||||
} else {
|
||||
output.insert (ep.second ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1893,6 +1893,11 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
// force different polygons in the different properties case to skip intra-polygon checks
|
||||
if (options.prop_constraint == DifferentPropertiesConstraint) {
|
||||
different_polygons = true;
|
||||
}
|
||||
|
||||
const db::DeepRegion *other_deep = 0;
|
||||
unsigned int other_layer = 0;
|
||||
bool other_is_merged = true;
|
||||
|
|
@ -1959,9 +1964,9 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
|
||||
db::check_local_operation_with_properties<db::PolygonRef, db::PolygonRef> op (check, different_polygons, primary_is_merged, other_deep != 0, other_is_merged, options, res->properties_repository (), properties_repository (), other_deep ? other_deep->properties_repository () : &polygons.layout ().properties_repository ());
|
||||
|
||||
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::EdgePair> proc (subject_layout, subject_top,
|
||||
intruder_layout, intruder_top,
|
||||
subject_breakout_cells, intruder_breakout_cells);
|
||||
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::EdgePairWithProperties> proc (subject_layout, subject_top,
|
||||
intruder_layout, intruder_top,
|
||||
subject_breakout_cells, intruder_breakout_cells);
|
||||
|
||||
configure_proc (proc);
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
|
|
|
|||
|
|
@ -1300,19 +1300,32 @@ DeepShapeStore::insert_as_polygons (const DeepLayer &deep_layer, db::Layout *int
|
|||
|
||||
if (s->is_edge_pair ()) {
|
||||
|
||||
out.insert (s->edge_pair ().normalized ().to_simple_polygon (enl));
|
||||
if (s->prop_id () != 0) {
|
||||
out.insert (db::SimplePolygonWithProperties (s->edge_pair ().normalized ().to_simple_polygon (enl), s->prop_id ()));
|
||||
} else {
|
||||
out.insert (s->edge_pair ().normalized ().to_simple_polygon (enl));
|
||||
}
|
||||
|
||||
} else if (s->is_path () || s->is_polygon () || s->is_box ()) {
|
||||
|
||||
db::Polygon poly;
|
||||
s->polygon (poly);
|
||||
out.insert (poly);
|
||||
if (s->prop_id () != 0) {
|
||||
out.insert (db::PolygonWithProperties (poly, s->prop_id ()));
|
||||
} else {
|
||||
out.insert (poly);
|
||||
}
|
||||
|
||||
} else if (s->is_text ()) {
|
||||
|
||||
db::Text t;
|
||||
s->text (t);
|
||||
out.insert (db::SimplePolygon (t.box ().enlarged (db::Vector (enl, enl))));
|
||||
db::SimplePolygon sp (t.box ().enlarged (db::Vector (enl, enl)));
|
||||
if (s->prop_id () != 0) {
|
||||
out.insert (db::SimplePolygonWithProperties (sp, s->prop_id ()));
|
||||
} else {
|
||||
out.insert (sp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -409,13 +409,13 @@ public:
|
|||
typedef Iterator const_iterator;
|
||||
|
||||
ShapesToOutputContainerAdaptor ()
|
||||
: mp_shapes (0)
|
||||
: mp_shapes (0), m_prop_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ShapesToOutputContainerAdaptor (db::Shapes &shapes)
|
||||
: mp_shapes (&shapes)
|
||||
ShapesToOutputContainerAdaptor (db::Shapes &shapes, db::properties_id_type prop_id = 0)
|
||||
: mp_shapes (&shapes), m_prop_id (prop_id)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -432,11 +432,16 @@ public:
|
|||
|
||||
void insert (const db::Edge &edge)
|
||||
{
|
||||
mp_shapes->insert (edge);
|
||||
if (m_prop_id != 0) {
|
||||
mp_shapes->insert (db::EdgeWithProperties (edge, m_prop_id));
|
||||
} else {
|
||||
mp_shapes->insert (edge);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
db::Shapes *mp_shapes;
|
||||
db::properties_id_type m_prop_id;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -445,13 +450,13 @@ private:
|
|||
struct DB_PUBLIC EdgeBooleanClusterCollectorToShapes
|
||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor>
|
||||
{
|
||||
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op)
|
||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor> (&m_adaptor, op), m_adaptor (*output)
|
||||
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op, db::properties_id_type prop_id = 0)
|
||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor> (&m_adaptor, op), m_adaptor (*output, prop_id)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op, db::Shapes *output2)
|
||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor> (&m_adaptor, op, &m_adaptor2), m_adaptor (*output), m_adaptor2 (*output2)
|
||||
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op, db::Shapes *output2, db::properties_id_type prop_id = 0)
|
||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor> (&m_adaptor, op, &m_adaptor2), m_adaptor (*output, prop_id), m_adaptor2 (*output2, prop_id)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ Box FlatEdgePairs::compute_bbox () const
|
|||
EdgePairsDelegate *
|
||||
FlatEdgePairs::filter_in_place (const EdgePairFilterBase &filter)
|
||||
{
|
||||
// TODO: implement property support
|
||||
|
||||
db::Shapes &ep = *mp_edge_pairs;
|
||||
|
||||
edge_pair_iterator_type pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin ();
|
||||
|
|
@ -121,22 +123,22 @@ EdgePairsDelegate *FlatEdgePairs::add (const EdgePairs &other) const
|
|||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*this));
|
||||
new_edge_pairs->invalidate_cache ();
|
||||
|
||||
db::PropertyMapper pm (new_edge_pairs->properties_repository (), &other.properties_repository ());
|
||||
|
||||
const FlatEdgePairs *other_flat = dynamic_cast<const FlatEdgePairs *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
new_edge_pairs->raw_edge_pairs ().insert (other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (), other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().end ());
|
||||
new_edge_pairs->raw_edge_pairs ().insert (other_flat->raw_edge_pairs (), pm);
|
||||
|
||||
} else {
|
||||
|
||||
size_t n = new_edge_pairs->raw_edge_pairs ().size ();
|
||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
++n;
|
||||
}
|
||||
|
||||
new_edge_pairs->raw_edge_pairs ().reserve (db::EdgePair::tag (), n);
|
||||
|
||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
db::properties_id_type prop_id = pm (p.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (db::EdgePairWithProperties (*p, prop_id));
|
||||
} else {
|
||||
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -150,22 +152,22 @@ EdgePairsDelegate *FlatEdgePairs::add_in_place (const EdgePairs &other)
|
|||
|
||||
db::Shapes &ep = *mp_edge_pairs;
|
||||
|
||||
db::PropertyMapper pm (properties_repository (), &other.properties_repository ());
|
||||
|
||||
const FlatEdgePairs *other_flat = dynamic_cast<const FlatEdgePairs *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
ep.insert (other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().begin (), other_flat->raw_edge_pairs ().get_layer<db::EdgePair, db::unstable_layer_tag> ().end ());
|
||||
ep.insert (other_flat->raw_edge_pairs (), pm);
|
||||
|
||||
} else {
|
||||
|
||||
size_t n = ep.size ();
|
||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
++n;
|
||||
}
|
||||
|
||||
ep.reserve (db::EdgePair::tag (), n);
|
||||
|
||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
ep.insert (*p);
|
||||
db::properties_id_type prop_id = pm (p.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
ep.insert (db::EdgePairWithProperties (*p, prop_id));
|
||||
} else {
|
||||
ep.insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -211,8 +213,15 @@ void
|
|||
FlatEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
db::Shapes &out = layout->cell (into_cell).shapes (into_layer);
|
||||
db::PropertyMapper pm (&layout->properties_repository (), properties_repository ());
|
||||
|
||||
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
out.insert (p->normalized ().to_simple_polygon (enl));
|
||||
db::properties_id_type prop_id = pm (p.prop_id ());
|
||||
if (prop_id != 0) {
|
||||
out.insert (db::SimplePolygonWithProperties (p->normalized ().to_simple_polygon (enl), prop_id));
|
||||
} else {
|
||||
out.insert (p->normalized ().to_simple_polygon (enl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,19 +110,62 @@ FlatEdges::ensure_merged_edges_valid () const
|
|||
|
||||
mp_merged_edges->clear ();
|
||||
|
||||
db::Shapes tmp (false);
|
||||
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr);
|
||||
|
||||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve (mp_edges->size ());
|
||||
|
||||
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
|
||||
if (! e->is_degenerate ()) {
|
||||
scanner.insert (&*e, 0);
|
||||
// count edges and reserve memory
|
||||
size_t n = 0;
|
||||
db::properties_id_type prop_id = 0;
|
||||
bool need_split_props = false;
|
||||
for (EdgesIterator s (begin ()); ! s.at_end (); ++s, ++n) {
|
||||
if (n == 0) {
|
||||
prop_id = s.prop_id ();
|
||||
} else if (! need_split_props && prop_id != s.prop_id ()) {
|
||||
need_split_props = true;
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
|
||||
db::Shapes tmp (false);
|
||||
|
||||
if (! need_split_props) {
|
||||
|
||||
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr);
|
||||
|
||||
scanner.reserve (mp_edges->size ());
|
||||
|
||||
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
|
||||
if (! e->is_degenerate ()) {
|
||||
scanner.insert (&*e, 0);
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
} else {
|
||||
|
||||
std::map<db::properties_id_type, std::vector<const db::Edge *> > edges_by_props;
|
||||
|
||||
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
|
||||
if (! e->is_degenerate ()) {
|
||||
edges_by_props [e.prop_id ()].push_back (e.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto s2p = edges_by_props.begin (); s2p != edges_by_props.end (); ++s2p) {
|
||||
|
||||
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr, s2p->first);
|
||||
|
||||
scanner.clear ();
|
||||
scanner.reserve (s2p->second.size ());
|
||||
|
||||
for (auto s = s2p->second.begin (); s != s2p->second.end (); ++s) {
|
||||
scanner.insert (*s, 0);
|
||||
}
|
||||
|
||||
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mp_merged_edges->swap (tmp);
|
||||
m_merged_edges_valid = true;
|
||||
|
|
|
|||
|
|
@ -419,6 +419,17 @@ OriginalLayerRegion::init ()
|
|||
m_merged_polygons_valid = false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct AssignProp
|
||||
{
|
||||
AssignProp () : prop_id (0) { }
|
||||
db::properties_id_type operator() (db::properties_id_type) { return prop_id; }
|
||||
db::properties_id_type prop_id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
OriginalLayerRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
|
|
@ -438,8 +449,11 @@ OriginalLayerRegion::insert_into (Layout *layout, db::cell_index_type into_cell,
|
|||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (layout);
|
||||
AssignProp ap;
|
||||
for (db::RecursiveShapeIterator i = m_iter; !i.at_end (); ++i) {
|
||||
sh.insert (*i, i.trans (), pm);
|
||||
db::properties_id_type prop_id = i.prop_id ();
|
||||
ap.prop_id = (prop_id != 0 ? pm (prop_id) : 0);
|
||||
sh.insert (*i, i.trans (), ap);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ check_local_operation_with_properties<TS, TI>::check_local_operation_with_proper
|
|||
|
||||
template <class TS, class TI>
|
||||
void
|
||||
check_local_operation_with_properties<TS, TI>::do_compute_local (db::Layout *layout, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
check_local_operation_with_properties<TS, TI>::do_compute_local (db::Layout *layout, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::EdgePairWithProperties> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
|
||||
|
|
@ -781,7 +781,9 @@ check_local_operation_with_properties<TS, TI>::do_compute_local (db::Layout *lay
|
|||
check_local_operation_base<TS, TI>::apply_rectangle_filter (subjects, result);
|
||||
}
|
||||
|
||||
results.front ().insert (result.begin (), result.end ());
|
||||
for (auto r = result.begin (); r != result.end (); ++r) {
|
||||
results.front ().insert (db::EdgePairWithProperties (*r, s2p->first));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ public:
|
|||
|
||||
template <class TS, class TI>
|
||||
class check_local_operation_with_properties
|
||||
: public local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::EdgePair>, public check_local_operation_base<TS, TI>
|
||||
: public local_operation<db::object_with_properties<TS>, db::object_with_properties<TI>, db::EdgePairWithProperties>, public check_local_operation_base<TS, TI>
|
||||
{
|
||||
public:
|
||||
check_local_operation_with_properties (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options, db::PropertiesRepository *target_pr, const db::PropertiesRepository *subject_pr, const db::PropertiesRepository *intruder_pr);
|
||||
|
|
@ -268,7 +268,7 @@ public:
|
|||
virtual bool requests_single_subjects () const { return true; }
|
||||
virtual std::string description () const;
|
||||
|
||||
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
|
||||
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::object_with_properties<TS>, db::object_with_properties<TI> > &interactions, std::vector<std::unordered_set<db::EdgePairWithProperties> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
|
||||
|
||||
private:
|
||||
mutable db::PropertyMapper m_pms, m_pmi;
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ shape_collection_processed_impl (const db::DeepLayer &input, const shape_collect
|
|||
}
|
||||
|
||||
shape_collection_processor_delivery<Result> delivery (&layout, st);
|
||||
shape_collection_processor_delivery<db::object_with_properties<Result> > delivery_wp (&layout, st);
|
||||
|
||||
const db::ICplxTrans &tr = v->first;
|
||||
db::ICplxTrans trinv = tr.inverted ();
|
||||
|
|
@ -220,7 +221,11 @@ shape_collection_processed_impl (const db::DeepLayer &input, const shape_collect
|
|||
heap.clear ();
|
||||
filter.process (s, heap);
|
||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||
delivery.put (i->transformed (trinv));
|
||||
if (si->prop_id ()) {
|
||||
delivery_wp.put (db::object_with_properties<Result> (i->transformed (trinv), si->prop_id ()));
|
||||
} else {
|
||||
delivery.put (i->transformed (trinv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -230,6 +235,7 @@ shape_collection_processed_impl (const db::DeepLayer &input, const shape_collect
|
|||
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
shape_collection_processor_delivery<Result> delivery (&layout, &st);
|
||||
shape_collection_processor_delivery<db::object_with_properties<Result> > delivery_wp (&layout, &st);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
Shape s;
|
||||
|
|
@ -237,7 +243,11 @@ shape_collection_processed_impl (const db::DeepLayer &input, const shape_collect
|
|||
heap.clear ();
|
||||
filter.process (s, heap);
|
||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||
delivery.put (*i);
|
||||
if (si->prop_id ()) {
|
||||
delivery_wp.put (db::object_with_properties<Result> (*i, si->prop_id ()));
|
||||
} else {
|
||||
delivery.put (*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1405,47 +1405,15 @@ static db::Pin *create_pin (db::Circuit *circuit, const std::string &name)
|
|||
}
|
||||
|
||||
static std::vector<db::Net *>
|
||||
nets_by_name (db::Circuit *circuit, const std::string &name_pattern)
|
||||
nets_non_const (const std::vector<const db::Net *> &nc)
|
||||
{
|
||||
std::vector<db::Net *> res;
|
||||
if (! circuit) {
|
||||
return res;
|
||||
std::vector<db::Net *> n;
|
||||
n.reserve (nc.size ());
|
||||
for (auto i = nc.begin (); i != nc.end (); ++i) {
|
||||
n.push_back (const_cast<db::Net *> (*i));
|
||||
}
|
||||
|
||||
tl::GlobPattern glob (name_pattern);
|
||||
if (circuit->netlist ()) {
|
||||
glob.set_case_sensitive (circuit->netlist ()->is_case_sensitive ());
|
||||
}
|
||||
for (db::Circuit::net_iterator n = circuit->begin_nets (); n != circuit->end_nets (); ++n) {
|
||||
db::Net *net = n.operator-> ();
|
||||
if (glob.match (net->name ())) {
|
||||
res.push_back (net);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::vector<db::Net *>
|
||||
nets_by_name_from_netlist (db::Netlist *netlist, const std::string &name_pattern)
|
||||
{
|
||||
std::vector<db::Net *> res;
|
||||
if (! netlist) {
|
||||
return res;
|
||||
}
|
||||
|
||||
tl::GlobPattern glob (name_pattern);
|
||||
glob.set_case_sensitive (netlist->is_case_sensitive ());
|
||||
for (auto c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
|
||||
for (auto n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
db::Net *net = n.operator-> ();
|
||||
if (glob.match (net->name ())) {
|
||||
res.push_back (net);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
return n;
|
||||
}
|
||||
|
||||
static std::vector<const db::Net *>
|
||||
|
|
@ -1470,6 +1438,12 @@ nets_by_name_const (const db::Circuit *circuit, const std::string &name_pattern)
|
|||
return res;
|
||||
}
|
||||
|
||||
static std::vector<db::Net *>
|
||||
nets_by_name (db::Circuit *circuit, const std::string &name_pattern)
|
||||
{
|
||||
return nets_non_const (nets_by_name_const (circuit, name_pattern));
|
||||
}
|
||||
|
||||
static std::vector<const db::Net *>
|
||||
nets_by_name_const_from_netlist (const db::Netlist *netlist, const std::string &name_pattern)
|
||||
{
|
||||
|
|
@ -1483,7 +1457,8 @@ nets_by_name_const_from_netlist (const db::Netlist *netlist, const std::string &
|
|||
for (auto c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
|
||||
for (auto n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||
const db::Net *net = n.operator-> ();
|
||||
if (glob.match (net->name ())) {
|
||||
// NOTE: we only pick root nets (pin_count == 0)
|
||||
if (net->pin_count () == 0 && glob.match (net->name ())) {
|
||||
res.push_back (net);
|
||||
}
|
||||
}
|
||||
|
|
@ -1492,6 +1467,12 @@ nets_by_name_const_from_netlist (const db::Netlist *netlist, const std::string &
|
|||
return res;
|
||||
}
|
||||
|
||||
static std::vector<db::Net *>
|
||||
nets_by_name_from_netlist (db::Netlist *netlist, const std::string &name_pattern)
|
||||
{
|
||||
return nets_non_const (nets_by_name_const_from_netlist (netlist, name_pattern));
|
||||
}
|
||||
|
||||
Class<db::Circuit> decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
|
||||
gsi::method_ext ("create_pin", &create_pin, gsi::arg ("name"),
|
||||
"@brief Creates a new \\Pin object inside the circuit\n"
|
||||
|
|
|
|||
|
|
@ -524,22 +524,6 @@ static db::EdgePairs width2 (const db::Region *r, db::Region::distance_type d, b
|
|||
);
|
||||
}
|
||||
|
||||
static db::EdgePairs space2 (const db::Region *r, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
|
||||
{
|
||||
// @@@ TODO: space intra-polygon with different properties constraint?? -> revert to "isolated"?
|
||||
return r->space_check (d, db::RegionCheckOptions (whole_edges,
|
||||
metrics,
|
||||
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
|
||||
min_projection.is_nil () ? db::Region::distance_type (0) : min_projection.to<db::Region::distance_type> (),
|
||||
max_projection.is_nil () ? std::numeric_limits<db::Region::distance_type>::max () : max_projection.to<db::Region::distance_type> (),
|
||||
shielded,
|
||||
opposite,
|
||||
rect_filter,
|
||||
negative,
|
||||
prop_constraint)
|
||||
);
|
||||
}
|
||||
|
||||
static db::EdgePairs notch2 (const db::Region *r, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, bool negative)
|
||||
{
|
||||
return r->notch_check (d, db::RegionCheckOptions (whole_edges,
|
||||
|
|
@ -569,6 +553,21 @@ static db::EdgePairs isolated2 (const db::Region *r, db::Region::distance_type d
|
|||
);
|
||||
}
|
||||
|
||||
static db::EdgePairs space2 (const db::Region *r, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
|
||||
{
|
||||
return r->space_check (d, db::RegionCheckOptions (whole_edges,
|
||||
metrics,
|
||||
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
|
||||
min_projection.is_nil () ? db::Region::distance_type (0) : min_projection.to<db::Region::distance_type> (),
|
||||
max_projection.is_nil () ? std::numeric_limits<db::Region::distance_type>::max () : max_projection.to<db::Region::distance_type> (),
|
||||
shielded,
|
||||
opposite,
|
||||
rect_filter,
|
||||
negative,
|
||||
prop_constraint)
|
||||
);
|
||||
}
|
||||
|
||||
static db::EdgePairs inside2 (const db::Region *r, const db::Region &other, db::Region::distance_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite, db::RectFilter rect_filter, bool negative, db::PropertyConstraint prop_constraint)
|
||||
{
|
||||
return r->inside_check (other, d, db::RegionCheckOptions (whole_edges,
|
||||
|
|
|
|||
|
|
@ -149,22 +149,23 @@ TEST(0_Basic)
|
|||
reg_copy.reset (0);
|
||||
|
||||
std::unique_ptr<db::Region> reg2 (l2n.make_layer ());
|
||||
EXPECT_EQ (l2n.name (1u), "");
|
||||
EXPECT_EQ (l2n.name (*reg2), "");
|
||||
EXPECT_EQ (l2n.name (1u), "$1");
|
||||
EXPECT_EQ (l2n.name (*reg2), "$1");
|
||||
EXPECT_EQ (l2n.layer_of (*reg2), 1u);
|
||||
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), true);
|
||||
reg2.reset (0);
|
||||
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), false);
|
||||
// NOTE: deleting the region does not free the layer as we hold it internally inside LayoutToNetlist
|
||||
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), true);
|
||||
|
||||
std::unique_ptr<db::Region> reg3 (l2n.make_layer ("l3"));
|
||||
EXPECT_EQ (l2n.name (*reg3), "l3");
|
||||
EXPECT_EQ (l2n.layer_of (*reg3), 1u);
|
||||
EXPECT_EQ (l2n.layer_of (*reg3), 2u);
|
||||
|
||||
std::string s;
|
||||
for (db::LayoutToNetlist::layer_iterator l = l2n.begin_layers (); l != l2n.end_layers (); ++l) {
|
||||
s += tl::to_string (l->first) + ":" + l->second + ";";
|
||||
}
|
||||
EXPECT_EQ (s, "0:l1;1:l3;");
|
||||
EXPECT_EQ (s, "0:l1;1:$1;2:l3;");
|
||||
}
|
||||
|
||||
TEST(1_BasicExtraction)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module DRC
|
|||
# %DRC%
|
||||
# @name drc
|
||||
# @brief Provides a generic DRC function for use with \DRC# expressions
|
||||
# @synopsis layer.drc(expression)
|
||||
# @synopsis layer.drc(expression [, prop_constraint ])
|
||||
#
|
||||
# This method implements the universal DRC which offers enhanced abilities,
|
||||
# improved performance in some applications and better readability.
|
||||
|
|
@ -378,6 +378,24 @@ module DRC
|
|||
# or the boolean operation. But when the "drc" function executes the loop over the primaries it will
|
||||
# only compute the area once per primary as it is represented by the same Ruby object.
|
||||
#
|
||||
# @h3 Properties constraints @/h3
|
||||
#
|
||||
# The method can be given a properties constraint so that it is only performed
|
||||
# between shapes with the same or different user properties. Note that properties
|
||||
# have to be enabled or generated (e.g. through the \nets method) before they can
|
||||
# be used.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# @code
|
||||
# connect(metal1, via1)
|
||||
# ...
|
||||
#
|
||||
# space_not_connected = metal1.nets.drc(space < 0.4.um, props_ne)
|
||||
# @code
|
||||
#
|
||||
# See \global#prop_eq, \global#prop_ne and \global#prop_copy for details.
|
||||
#
|
||||
# @h3 Outlook @/h3
|
||||
#
|
||||
# DRC expressions are quite rich and powerful. They provide a more intuitive way of
|
||||
|
|
@ -386,10 +404,11 @@ module DRC
|
|||
#
|
||||
# More formal details about the bits and pieces can be found in the "\DRC" class documentation.
|
||||
|
||||
def drc(op)
|
||||
def drc(op, prop_constraint = DRCPropertiesConstraint::new(RBA::Region::IgnoreProperties))
|
||||
@engine._context("drc") do
|
||||
requires_region
|
||||
op.is_a?(DRCOpNode) || raise("A DRC expression is required for the argument (got #{op.inspect})")
|
||||
prop_constraint.is_a?(DRCPropertiesConstraint) || raise("A properties constraint is required for the second argument (got #{prop_constraint.inspect})")
|
||||
node = op.create_node({})
|
||||
result_cls = nil
|
||||
if node.result_type == RBA::CompoundRegionOperationNode::ResultType::Region
|
||||
|
|
@ -400,7 +419,7 @@ module DRC
|
|||
result_cls = RBA::EdgePairs
|
||||
end
|
||||
if result_cls
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, node.distance, result_cls, :complex_op, node))
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, node.distance, result_cls, :complex_op, node, prop_constraint.value))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -241,6 +241,85 @@ module DRC
|
|||
DRCRectangleErrorFilter::new(RBA::Region::FourSidesAllowed)
|
||||
end
|
||||
|
||||
def prop(k)
|
||||
self._context("prop") do
|
||||
DRCPropertyName::new(k)
|
||||
end
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @brief Specifies "same properties" for operations supporting user properties constraints
|
||||
# @name props_eq
|
||||
#
|
||||
# Some operations such as boolean AND support properties constraints. By giving
|
||||
# a "props_eq" constraint, the operation is performed only on shapes with the same
|
||||
# properties, where "properties" stands for the full set of key/value pairs.
|
||||
#
|
||||
# Note that you have to enable properties explicitly or generate properties (e.g.
|
||||
# with the \DRCLayer#nets method).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# @code
|
||||
# connect(metal1, via1)
|
||||
# connect(via1, metal2)
|
||||
# ... further connect statements
|
||||
#
|
||||
# m1m2_overlap_connected = metal1.nets.and(metal2, props_eq)
|
||||
# @/code
|
||||
#
|
||||
# See also \props_ne.
|
||||
|
||||
# %DRC%
|
||||
# @brief Specifies "different properties" for operations supporting user properties constraints
|
||||
# @name props_ne
|
||||
#
|
||||
# Some operations such as boolean AND support properties constraints. By giving
|
||||
# a "props_ne" constraint, the operation is performed only on shapes with different
|
||||
# properties, where "properties" stands for the full set of key/value pairs.
|
||||
#
|
||||
# Note that you have to enable properties explicitly or generate properties (e.g.
|
||||
# with the \DRCLayer#nets method).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# @code
|
||||
# connect(metal1, via1)
|
||||
# connect(via1, metal2)
|
||||
# ... further connect statements
|
||||
#
|
||||
# m1m2_overlap_not_connected = metal1.nets.and(metal2, props_ne)
|
||||
# @/code
|
||||
#
|
||||
# See also \props_eq.
|
||||
|
||||
# %DRC%
|
||||
# @brief Specifies "copy properties" on operations supporting user properties constraints
|
||||
# @name props_copy
|
||||
#
|
||||
# This properties constraint does not constrain the operation, but instructs it to
|
||||
# attach the properties from the primary input to the output objects.
|
||||
#
|
||||
# See also \props_ne and \props_eq.
|
||||
|
||||
def props_eq
|
||||
self._context("props_eq") do
|
||||
DRCPropertiesConstraint::new(RBA::Region::SamePropertiesConstraint)
|
||||
end
|
||||
end
|
||||
|
||||
def props_ne
|
||||
self._context("props_ne") do
|
||||
DRCPropertiesConstraint::new(RBA::Region::DifferentPropertiesConstraint)
|
||||
end
|
||||
end
|
||||
|
||||
def props_copy
|
||||
self._context("props_copy") do
|
||||
DRCPropertiesConstraint::new(RBA::Region::NoPropertyConstraint)
|
||||
end
|
||||
end
|
||||
|
||||
def pattern(p)
|
||||
self._context("pattern") do
|
||||
DRCPattern::new(true, p)
|
||||
|
|
@ -2596,6 +2675,10 @@ CODE
|
|||
@dss
|
||||
end
|
||||
|
||||
def _default_netter
|
||||
@netter
|
||||
end
|
||||
|
||||
def _netter
|
||||
@netter ||= DRC::DRCNetter::new(self)
|
||||
end
|
||||
|
|
@ -2775,7 +2858,8 @@ CODE
|
|||
if cls == RBA::Region && clip && box
|
||||
# HACK: deep regions will always clip in the constructor, so skip this
|
||||
if ! @deep
|
||||
r &= RBA::Region::new(box)
|
||||
# NOTE: NoPropertyConstraint will copy the original properties
|
||||
r.and(RBA::Region::new(box), RBA::Region::NoPropertyConstraint)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1744,9 +1744,10 @@ CODE
|
|||
# %DRC%
|
||||
# @name and
|
||||
# @brief Boolean AND operation
|
||||
# @synopsis layer.and(other)
|
||||
# @synopsis layer.and(other [, prop_constraint ])
|
||||
# The method computes a boolean AND between self and other.
|
||||
# It is an alias for the "&" operator.
|
||||
# It is an alias for the "&" operator which lacks the ability
|
||||
# to specify a properties constraint.
|
||||
#
|
||||
# This method is available for polygon and edge layers.
|
||||
# If the first operand is an edge layer and the second is a polygon layer, the
|
||||
|
|
@ -1773,17 +1774,19 @@ CODE
|
|||
# @td @img(/images/drc_textpoly1.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
|
||||
def and(other)
|
||||
@engine._context("and") do
|
||||
self & other
|
||||
end
|
||||
end
|
||||
#
|
||||
# When a properties constraint is given, the operation is performed
|
||||
# only between shapes with the given relation. Together with the
|
||||
# ability to provide net-annotated shapes through the \nets method, this
|
||||
# allows constraining the boolean operation to shapes from the same or
|
||||
# from different nets.
|
||||
#
|
||||
# See \global#prop_eq, \global#prop_ne and \global#prop_copy for details.
|
||||
|
||||
# %DRC%
|
||||
# @name not
|
||||
# @brief Boolean NOT operation
|
||||
# @synopsis layer.not(other)
|
||||
# @synopsis layer.not(other [, prop_constraint ])
|
||||
# The method computes a boolean NOT between self and other.
|
||||
# It is an alias for the "-" operator.
|
||||
#
|
||||
|
|
@ -1812,10 +1815,42 @@ CODE
|
|||
# @td @img(/images/drc_textpoly2.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# When a properties constraint is given, the operation is performed
|
||||
# only between shapes with the given relation. Together with the
|
||||
# ability to provide net-annotated shapes through the \nets method, this
|
||||
# allows constraining the boolean operation to shapes from the same or
|
||||
# from different nets.
|
||||
#
|
||||
# See \global#prop_eq, \global#prop_ne and \global#prop_copy for details.
|
||||
|
||||
def not(other)
|
||||
@engine._context("not") do
|
||||
self - other
|
||||
def and(other, prop_constraint = nil)
|
||||
if prop_constraint
|
||||
@engine._context("and") do
|
||||
prop_constraint.is_a?(DRCPropertiesConstraint) || raise("The properties constraint needs to be prop_eq, prop_ne or prop_copy")
|
||||
# currently only available for regions
|
||||
requires_region
|
||||
check_is_layer(other)
|
||||
other.requires_region
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :and, other.data, prop_constraint.value))
|
||||
end
|
||||
else
|
||||
self & other
|
||||
end
|
||||
end
|
||||
|
||||
def not(other, prop_constraint = nil)
|
||||
if prop_constraint
|
||||
@engine._context("not") do
|
||||
prop_constraint.is_a?(DRCPropertiesConstraint) || raise("The properties constraint needs to be prop_eq, prop_ne or prop_copy")
|
||||
# currently only available for regions
|
||||
requires_region
|
||||
check_is_layer(other)
|
||||
other.requires_region
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :not, other.data, prop_constraint.value))
|
||||
end
|
||||
else
|
||||
self - other
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -3654,6 +3689,8 @@ CODE
|
|||
# Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0". @/li
|
||||
# @li @b transparent @/b: performs the check without shielding (polygon layers only) @/li
|
||||
# @li @b shielded @/b: performs the check with shielding (polygon layers only) @/li
|
||||
# @li @b props_eq @/b, @b props_ne @/b, @b props_copy @/b: (does not apply to width check) -
|
||||
# see "Properties constraints" below.
|
||||
# @/ul
|
||||
#
|
||||
# Note that without the angle_limit, acute corners will always be reported, since two
|
||||
|
|
@ -3716,6 +3753,36 @@ CODE
|
|||
# because B features which are identical to A features will shield those entirely.
|
||||
#
|
||||
# Shielding is enabled by default, but can be switched off with the "transparent" option.
|
||||
#
|
||||
# @h3 Properties constraints (available on intra-polygon checks such as \space, \sep etc.) @/h3
|
||||
#
|
||||
# This feature is listed here, because this documentation is generic and used for other checks
|
||||
# as well. It is not available on 'width' as it applies to intra-polygon checks - when
|
||||
# pairs of different polygons are involved - something that width does not apply to.
|
||||
#
|
||||
# With properties constraints, the check is performed between shapes with the same
|
||||
# or different properties. "properties" refers to the full set of key/value pairs
|
||||
# attached to a shape.
|
||||
#
|
||||
# Property constraints are specified by adding \props_eq or \props_ne to the arguments.
|
||||
# If these literals are present, only shapes with same of different properties are
|
||||
# involved in the check. In connection with the net annotation feature this allows
|
||||
# checking space between connected or disconnected shapes for example:
|
||||
#
|
||||
# @code
|
||||
# connect(metal1, via1)
|
||||
# ...
|
||||
#
|
||||
# # attaches net identity as properties
|
||||
# metal1_nets = metal1.nets
|
||||
#
|
||||
# space_not_connected = metal1_nets.space(0.4.um, props_ne)
|
||||
# space_connected = metal1_nets.space(0.4.um, props_eq)
|
||||
# @code
|
||||
#
|
||||
# \props_copy is a special properties constraint that does not alter the behaviour of
|
||||
# the checks, but copies the primary shape's properties to the output markers
|
||||
# (a behaviour that is implied by \props_eq and \props_ne, but not there by default).
|
||||
|
||||
# %DRC%
|
||||
# @name space
|
||||
|
|
@ -3754,7 +3821,6 @@ CODE
|
|||
# @td @img(/images/drc_space1.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
|
||||
# %DRC%
|
||||
# @name isolated
|
||||
|
|
@ -4044,6 +4110,7 @@ CODE
|
|||
shielded = nil
|
||||
opposite_filter = RBA::Region::NoOppositeFilter
|
||||
rect_filter = RBA::Region::NoRectFilter
|
||||
prop_constraint = RBA::Region::IgnoreProperties
|
||||
|
||||
n = 1
|
||||
args.each do |a|
|
||||
|
|
@ -4051,6 +4118,8 @@ CODE
|
|||
metrics = a.value
|
||||
elsif a.is_a?(DRCWholeEdges)
|
||||
whole_edges = a.value
|
||||
elsif a.is_a?(DRCPropertiesConstraint)
|
||||
prop_constraint = a.value
|
||||
elsif a.is_a?(DRCOppositeErrorFilter)
|
||||
opposite_filter = a.value
|
||||
elsif a.is_a?(DRCRectangleErrorFilter)
|
||||
|
|
@ -4083,10 +4152,14 @@ CODE
|
|||
if :#{f} != :width && :#{f} != :notch
|
||||
args << opposite_filter
|
||||
args << rect_filter
|
||||
args << false # negative
|
||||
args << prop_constraint
|
||||
elsif opposite_filter != RBA::Region::NoOppositeFilter
|
||||
raise("An opposite error filter cannot be used with this check")
|
||||
elsif rect_filter != RBA::Region::NoRectFilter
|
||||
raise("A rectangle error filter cannot be used with this check")
|
||||
elsif prop_constraint != RBA::Region::IgnoreProperties
|
||||
raise("A properties constraint cannot be used with this check")
|
||||
end
|
||||
elsif shielded != nil
|
||||
raise("Shielding can only be used for polygon layers")
|
||||
|
|
@ -4699,6 +4772,209 @@ CODE
|
|||
end
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name select_props
|
||||
# @brief Enables or selects properties from original or property-annotated layers
|
||||
# @synopsis layer.select_props
|
||||
# @synopsis layer.select_props(keys)
|
||||
#
|
||||
# This method will enable user properties or select specific property keys
|
||||
# from layers. It returns a new layer with properties enabled. The
|
||||
# original layer is not modified.
|
||||
#
|
||||
# When used on original layers, this method will enable properties on input.
|
||||
# By default, properties are not read:
|
||||
#
|
||||
# @code
|
||||
# layer1 = input(1, 0)
|
||||
# layer1_with_props = input(1, 0).select_props
|
||||
# @/code
|
||||
#
|
||||
# You can specify the user property keys (names) to use. As user properties
|
||||
# in general are a set of key/value pairs and may carry multiple information
|
||||
# under different keys, this feature can be handy to filter out a specific
|
||||
# aspect. To get only the values from key 1 (integer), use:
|
||||
#
|
||||
# @code
|
||||
# layer1_with_props = input(1, 0).select_props(1)
|
||||
# @/code
|
||||
#
|
||||
# To get the combined key 1 and 2 properties, use:
|
||||
#
|
||||
# @code
|
||||
# layer1_with_props = input(1, 0).select_props(1, 2)
|
||||
# @/code
|
||||
#
|
||||
# \map_props is a way to change property keys and \remove_props
|
||||
# will entirely remove all user properties.
|
||||
|
||||
# %DRC%
|
||||
# @name map_props
|
||||
# @brief Selects properties with certain keys and allows key mapping
|
||||
# @synopsis layer.map_props({ key => key_new, .. })
|
||||
#
|
||||
# Similar to \select_props, this method will enable user properties
|
||||
# and take the values from certain keys. In addition, this method allows
|
||||
# mapping keys to new keys. Specify a hash argument with old to new keys.
|
||||
#
|
||||
# Property values with keys not listed in the hash are removed.
|
||||
#
|
||||
# Note that this method returns a new layer with the new properties. The
|
||||
# original layer will not be touched.
|
||||
#
|
||||
# For example to map key 2 to 1 (integer name keys) and ignore other keys,
|
||||
# use:
|
||||
#
|
||||
# @code
|
||||
# layer1_with_props = input(1, 0).map_props({ 2 => 1 })
|
||||
# @/code
|
||||
#
|
||||
# See also \select_props and \remove_props.
|
||||
|
||||
# %DRC%
|
||||
# @name remove_props
|
||||
# @brief Returns a new layer with all properties removed
|
||||
# @synopsis layer.remove_props
|
||||
#
|
||||
# This method will drop all user properties from the layer.
|
||||
# Note that a new layer without properties is returned. The
|
||||
# original layer stays untouched.
|
||||
#
|
||||
# See also \select_props and \map_props.
|
||||
|
||||
def select_props(*args)
|
||||
@engine._context("select_props") do
|
||||
keys = args.flatten
|
||||
if keys.empty?
|
||||
DRC::DRCLayer::new(@engine, self.data.dup.enable_properties)
|
||||
else
|
||||
DRC::DRCLayer::new(@engine, self.data.dup.filter_properties(keys))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remove_props
|
||||
@engine._context("remove_props") do
|
||||
DRC::DRCLayer::new(@engine, self.data.dup.remove_properties)
|
||||
end
|
||||
end
|
||||
|
||||
def map_props(arg)
|
||||
@engine._context("map_props") do
|
||||
arg.is_a?(Hash) || raise("Argument of 'map_props' needs to be a mapping hash")
|
||||
DRC::DRCLayer::new(@engine, self.data.dup.map_properties(arg))
|
||||
end
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name net
|
||||
# @brief Pulls net shapes from selected or all nets, optionally annotating nets with properties
|
||||
# @synopsis layer.nets
|
||||
# @synopsis layer.nets(net_filter)
|
||||
# @synopsis layer.nets(circuit_filter, net_filter)
|
||||
# @synopsis layer.nets(netter, ...)
|
||||
# @synopsis layer.nets(prop(key), ...)
|
||||
# @synopsis layer.nets(prop(key), ...)
|
||||
#
|
||||
# This method needs a layer that has been used in a connect statement.
|
||||
# It will take the shapes corresponding to this layer for all or selected nets
|
||||
# and attach the net identity in form of a user property.
|
||||
#
|
||||
# This way, the resulting shapes can be used in property-constrained boolean operations
|
||||
# or DRC checks to implement operations in connected or non-connected mode.
|
||||
#
|
||||
# A glob-style name pattern can be supplied to filter nets. Nets are always
|
||||
# complete - subnets from subcircuits are not selected. The net name is taken from
|
||||
# the net's home circuit (to topmost location where all net connections are formed).
|
||||
# You can specify a circuit filter to select nets from certain circuits only or
|
||||
# give a RBA::Circuit object explicitly.
|
||||
#
|
||||
# @code
|
||||
# connect(metal1, via1)
|
||||
# connect(via1, metal2)
|
||||
#
|
||||
# metal1_all_nets = metal1.nets
|
||||
# metal1_vdd = metal1.nets("VDD")
|
||||
# metal1_vdd = metal1.nets("TOPLEVEL", "VDD")
|
||||
# @/code
|
||||
#
|
||||
# By default, the property key used for the net identity is numerical 0 (integer). You
|
||||
# can change the key by giving a property key with the "prop" qualifier. Using "nil" for the key
|
||||
# will disable properties:
|
||||
#
|
||||
# @code
|
||||
# metal1_vdd = metal1.nets("VDD", prop(1))
|
||||
# # disables properties:
|
||||
# metal1_vdd = metal1.nets("VDD", prop(nil))
|
||||
# @/code
|
||||
#
|
||||
# If a custom netter object has been used for the construction of the
|
||||
# connectivity, pass it to the "nets" method among the other arguments.
|
||||
|
||||
def nets(*args)
|
||||
|
||||
@engine._context("nets") do
|
||||
|
||||
# parse arguments
|
||||
filters = nil
|
||||
circuits = nil
|
||||
prop_id = 0
|
||||
netter = nil
|
||||
args.each do |a|
|
||||
if a.is_a?(String)
|
||||
filters ||= []
|
||||
filters << a
|
||||
elsif a.is_a?(1.class)
|
||||
prop_id = a
|
||||
elsif a.is_a?(RBA::Circuit)
|
||||
circuits ||= []
|
||||
circuits << a
|
||||
elsif a.is_a?(DRCPropertyName)
|
||||
prop_id = a.value
|
||||
elsif a.is_a?(DRCNetter)
|
||||
netter = a
|
||||
else
|
||||
raise("Invalid argument type for #{a.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
# get netter and netlist
|
||||
netter ||= @engine._default_netter
|
||||
if ! netter
|
||||
raise("No netlist extractor available - did you forget 'connect' statements?")
|
||||
end
|
||||
netlist = netter.netlist
|
||||
if ! netlist
|
||||
raise("No netlist available - extraction failed?")
|
||||
end
|
||||
|
||||
# create list of nets
|
||||
circuit_filter = nil
|
||||
if filters && filters.size > 1
|
||||
circuit_filter = filters.shift
|
||||
end
|
||||
if circuit_filter
|
||||
circuits ||= []
|
||||
circuits += netlist.circuits_by_name(circuit_filter)
|
||||
end
|
||||
nets = nil
|
||||
if !circuits
|
||||
if filters
|
||||
nets = filters.collect { |f| netlist.nets_by_name(f) }.flatten
|
||||
end
|
||||
else
|
||||
nets = circuits.collect do |circuit|
|
||||
(filters || ["*"]).collect { |f| circuit.nets_by_name(f) }.flatten
|
||||
end.flatten
|
||||
end
|
||||
|
||||
# pulls the net shapes
|
||||
DRCLayer::new(@engine, @engine._cmd(self.data, :nets, netter._l2n_data, prop_id, nets))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name output
|
||||
# @brief Outputs the content of the layer
|
||||
|
|
|
|||
|
|
@ -134,6 +134,24 @@ module DRC
|
|||
self.pattern = p
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for a property name
|
||||
# Use "prop(key)" to generate this tag.
|
||||
class DRCPropertyName
|
||||
attr_accessor :value
|
||||
def initialize(k)
|
||||
self.value = k
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for a property constraint
|
||||
# Use "props_eq", "props_ne" or "props_copy" to generate this tag.
|
||||
class DRCPropertiesConstraint
|
||||
attr_accessor :value
|
||||
def initialize(v)
|
||||
self.value = v
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for a pair of limit values
|
||||
# This class is used to identify projection limits for DRC
|
||||
|
|
|
|||
|
|
@ -1396,3 +1396,8 @@ TEST(60d_issue1216)
|
|||
{
|
||||
run_test (_this, "60", true);
|
||||
}
|
||||
|
||||
TEST(70_props)
|
||||
{
|
||||
run_test (_this, "70", false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
# Moved implementation
|
||||
|
||||
source($drc_test_source)
|
||||
target($drc_test_target)
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
l4 = input(4, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
l4.output(4, 0)
|
||||
|
||||
l3_wp = l3.select_props
|
||||
l3_wp1 = l3.select_props(1)
|
||||
l3_wp2as1 = l3.map_props({ 2 => 1 })
|
||||
l3_nowp = l3_wp.remove_props
|
||||
|
||||
l4_wp = l4.select_props
|
||||
|
||||
l3_wp.output(10, 0)
|
||||
l3_wp1.output(11, 0)
|
||||
l3_wp2as1.output(12, 0)
|
||||
l3_nowp.output(13, 0)
|
||||
l4_wp.output(14, 0)
|
||||
|
||||
l3_wp.and(l4_wp, props_eq).output(20, 0)
|
||||
l3_wp1.and(l4_wp, props_eq).output(21, 0)
|
||||
l3_wp2as1.and(l4_wp, props_eq).output(22, 0)
|
||||
l3_nowp.and(l4_wp, props_eq).output(23, 0)
|
||||
|
||||
l3_wp.and(l4_wp, props_ne).output(30, 0)
|
||||
l3_wp1.and(l4_wp, props_ne).output(31, 0)
|
||||
l3_wp2as1.and(l4_wp, props_ne).output(32, 0)
|
||||
l3_nowp.and(l4_wp, props_ne).output(33, 0)
|
||||
|
||||
l3_wp.and(l4_wp, props_copy).output(40, 0)
|
||||
l3_wp1.and(l4_wp, props_copy).output(41, 0)
|
||||
l3_wp2as1.and(l4_wp, props_copy).output(42, 0)
|
||||
l3_nowp.and(l4_wp, props_copy).output(43, 0)
|
||||
|
||||
l3_wp.and(l4_wp).output(50, 0)
|
||||
l3_wp1.and(l4_wp).output(51, 0)
|
||||
l3_wp2as1.and(l4_wp).output(52, 0)
|
||||
l3_nowp.and(l4_wp).output(53, 0)
|
||||
|
||||
|
||||
connect(l1, l2)
|
||||
|
||||
l1.nets.output(100, 0)
|
||||
l1.nets(self._netter).output(101, 0)
|
||||
l1.nets(prop(1)).output(102, 0)
|
||||
l1.nets(prop(nil)).output(103, 0)
|
||||
|
||||
l1.nets("X").output(110, 0)
|
||||
l1.nets("TOP", "X").output(111, 0)
|
||||
l1.nets("TOP", "NOTEXIST").output(112, 0)
|
||||
l1.nets("NOTEXIST", "NOTEXIST").output(113, 0)
|
||||
|
||||
|
||||
# checks with property constraints
|
||||
|
||||
l1_nets = l1.nets
|
||||
|
||||
l1_nets.space(1.0.um, projection).polygons.output(200, 0)
|
||||
l1_nets.space(1.0.um, projection, props_eq).polygons.output(201, 0)
|
||||
l1_nets.space(1.0.um, projection, props_ne).polygons.output(202, 0)
|
||||
l1_nets.space(1.0.um, projection, props_copy).polygons.output(203, 0)
|
||||
|
||||
l1_nets.drc(space(projection) < 1.0.um).polygons.output(210, 0)
|
||||
l1_nets.drc(space(projection) < 1.0.um, props_eq).polygons.output(211, 0)
|
||||
l1_nets.drc(space(projection) < 1.0.um, props_ne).polygons.output(212, 0)
|
||||
l1_nets.drc(space(projection) < 1.0.um, props_copy).polygons.output(213, 0)
|
||||
|
||||
# edge pair to edge/polygon conversion with properties
|
||||
|
||||
l1_nets.space(1.0.um, projection, props_copy).output(220, 0)
|
||||
l1_nets.space(1.0.um, projection, props_copy).first_edges.output(221, 0)
|
||||
l1_nets.space(1.0.um, projection, props_copy).second_edges.output(222, 0)
|
||||
l1_nets.space(1.0.um, projection, props_copy).edges.output(223, 0)
|
||||
l1_nets.space(1.0.um, projection, props_copy).edges.extended_in(10.nm).output(224, 0)
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue