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
|
AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<FlatRegion> region (new FlatRegion ());
|
std::unique_ptr<FlatRegion> region (new FlatRegion ());
|
||||||
|
db::PropertyMapper pm (region->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
if (filter.result_must_not_be_merged ()) {
|
if (filter.result_must_not_be_merged ()) {
|
||||||
region->set_merged_semantics (false);
|
region->set_merged_semantics (false);
|
||||||
|
|
@ -162,8 +163,9 @@ AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &
|
||||||
res_polygons.clear ();
|
res_polygons.clear ();
|
||||||
filter.process (*e, res_polygons);
|
filter.process (*e, res_polygons);
|
||||||
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
|
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
|
||||||
if (e.prop_id () != 0) {
|
db::properties_id_type prop_id = pm (e.prop_id ());
|
||||||
region->insert (db::PolygonWithProperties (*pr, e.prop_id ()));
|
if (prop_id != 0) {
|
||||||
|
region->insert (db::PolygonWithProperties (*pr, prop_id));
|
||||||
} else {
|
} else {
|
||||||
region->insert (*pr);
|
region->insert (*pr);
|
||||||
}
|
}
|
||||||
|
|
@ -177,6 +179,7 @@ EdgesDelegate *
|
||||||
AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const
|
AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<FlatEdges> edges (new FlatEdges ());
|
std::unique_ptr<FlatEdges> edges (new FlatEdges ());
|
||||||
|
db::PropertyMapper pm (edges->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
if (filter.result_must_not_be_merged ()) {
|
if (filter.result_must_not_be_merged ()) {
|
||||||
edges->set_merged_semantics (false);
|
edges->set_merged_semantics (false);
|
||||||
|
|
@ -188,8 +191,9 @@ AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter
|
||||||
res_edges.clear ();
|
res_edges.clear ();
|
||||||
filter.process (*e, res_edges);
|
filter.process (*e, res_edges);
|
||||||
for (std::vector<db::Edge>::const_iterator pr = res_edges.begin (); pr != res_edges.end (); ++pr) {
|
for (std::vector<db::Edge>::const_iterator pr = res_edges.begin (); pr != res_edges.end (); ++pr) {
|
||||||
if (e.prop_id () != 0) {
|
db::properties_id_type prop_id = pm (e.prop_id ());
|
||||||
edges->insert (db::EdgeWithProperties (*pr, e.prop_id ()));
|
if (prop_id != 0) {
|
||||||
|
edges->insert (db::EdgeWithProperties (*pr, prop_id));
|
||||||
} else {
|
} else {
|
||||||
edges->insert (*pr);
|
edges->insert (*pr);
|
||||||
}
|
}
|
||||||
|
|
@ -203,12 +207,18 @@ EdgePairsDelegate *
|
||||||
AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const
|
AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
|
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) {
|
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||||
if (filter.selected (*p)) {
|
if (filter.selected (*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);
|
new_edge_pairs->insert (*p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new_edge_pairs.release ();
|
return new_edge_pairs.release ();
|
||||||
}
|
}
|
||||||
|
|
@ -217,13 +227,19 @@ RegionDelegate *
|
||||||
AsIfFlatEdgePairs::polygons (db::Coord e) const
|
AsIfFlatEdgePairs::polygons (db::Coord e) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
||||||
|
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||||
db::Polygon poly = ep->normalized ().to_polygon (e);
|
db::Polygon poly = ep->normalized ().to_polygon (e);
|
||||||
if (poly.vertices () >= 3) {
|
if (poly.vertices () >= 3) {
|
||||||
|
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);
|
output->insert (poly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return output.release ();
|
return output.release ();
|
||||||
}
|
}
|
||||||
|
|
@ -232,11 +248,18 @@ EdgesDelegate *
|
||||||
AsIfFlatEdgePairs::edges () const
|
AsIfFlatEdgePairs::edges () const
|
||||||
{
|
{
|
||||||
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
||||||
|
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||||
|
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->first ());
|
||||||
output->insert (ep->second ());
|
output->insert (ep->second ());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return output.release ();
|
return output.release ();
|
||||||
}
|
}
|
||||||
|
|
@ -245,10 +268,16 @@ EdgesDelegate *
|
||||||
AsIfFlatEdgePairs::first_edges () const
|
AsIfFlatEdgePairs::first_edges () const
|
||||||
{
|
{
|
||||||
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
||||||
|
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||||
|
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 ());
|
output->insert (ep->first ());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return output.release ();
|
return output.release ();
|
||||||
}
|
}
|
||||||
|
|
@ -257,10 +286,16 @@ EdgesDelegate *
|
||||||
AsIfFlatEdgePairs::second_edges () const
|
AsIfFlatEdgePairs::second_edges () const
|
||||||
{
|
{
|
||||||
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
std::unique_ptr<FlatEdges> output (new FlatEdges ());
|
||||||
|
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
for (EdgePairsIterator ep (begin ()); ! ep.at_end (); ++ep) {
|
||||||
|
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 ());
|
output->insert (ep->second ());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return output.release ();
|
return output.release ();
|
||||||
}
|
}
|
||||||
|
|
@ -274,13 +309,20 @@ AsIfFlatEdgePairs::add (const EdgePairs &other) const
|
||||||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*other_flat));
|
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*other_flat));
|
||||||
new_edge_pairs->invalidate_cache ();
|
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 ();
|
size_t n = new_edge_pairs->raw_edge_pairs ().size () + count ();
|
||||||
|
|
||||||
new_edge_pairs->reserve (n);
|
new_edge_pairs->reserve (n);
|
||||||
|
|
||||||
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++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);
|
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new_edge_pairs.release ();
|
return new_edge_pairs.release ();
|
||||||
|
|
||||||
|
|
@ -288,16 +330,29 @@ AsIfFlatEdgePairs::add (const EdgePairs &other) const
|
||||||
|
|
||||||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
|
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 ();
|
size_t n = count () + other.count ();
|
||||||
|
|
||||||
new_edge_pairs->reserve (n);
|
new_edge_pairs->reserve (n);
|
||||||
|
|
||||||
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++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);
|
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++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);
|
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new_edge_pairs.release ();
|
return new_edge_pairs.release ();
|
||||||
|
|
||||||
|
|
@ -352,10 +407,17 @@ AsIfFlatEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, u
|
||||||
// improves performance when inserting an original layout into the same layout
|
// improves performance when inserting an original layout into the same layout
|
||||||
db::LayoutLocker locker (layout);
|
db::LayoutLocker locker (layout);
|
||||||
|
|
||||||
|
db::PropertyMapper pm (&layout->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||||
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
|
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++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);
|
shapes.insert (*e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -364,10 +426,17 @@ AsIfFlatEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type
|
||||||
// improves performance when inserting an original layout into the same layout
|
// improves performance when inserting an original layout into the same layout
|
||||||
db::LayoutLocker locker (layout);
|
db::LayoutLocker locker (layout);
|
||||||
|
|
||||||
|
db::PropertyMapper pm (&layout->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||||
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
|
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
|
||||||
|
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));
|
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) {
|
if (join) {
|
||||||
|
|
||||||
|
// TODO: property support?
|
||||||
|
|
||||||
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
||||||
db::ShapeGenerator sg (output->raw_polygons (), false);
|
db::ShapeGenerator sg (output->raw_polygons (), false);
|
||||||
JoinEdgesClusterCollector cluster_collector (&sg, ext_b, ext_e, ext_o, ext_i);
|
JoinEdgesClusterCollector cluster_collector (&sg, ext_b, ext_e, ext_o, ext_i);
|
||||||
|
|
@ -502,9 +504,16 @@ AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, c
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
std::unique_ptr<FlatRegion> output (new FlatRegion ());
|
||||||
|
db::PropertyMapper pm (output->properties_repository (), properties_repository ());
|
||||||
|
|
||||||
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
|
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
|
||||||
|
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));
|
output->insert (extended_edge (*e, ext_b, ext_e, ext_o, ext_i));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return output.release ();
|
return output.release ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1112,6 +1112,11 @@ AsIfFlatRegion::inside_check (const Region &other, db::Coord d, const RegionChec
|
||||||
EdgePairsDelegate *
|
EdgePairsDelegate *
|
||||||
AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
|
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 ();
|
bool needs_merged_primary = different_polygons || options.needs_merged ();
|
||||||
|
|
||||||
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
|
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::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_base_verbosity (base_verbosity ());
|
||||||
proc.set_description (progress_desc ());
|
proc.set_description (progress_desc ());
|
||||||
proc.set_report_progress (report_progress ());
|
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 ()) {
|
} 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
|
// Simplified handling for boxes
|
||||||
db::Box b = bbox ();
|
db::Box b = bbox ();
|
||||||
b &= other.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 ()) {
|
} 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 ..
|
// map AND with box to clip ..
|
||||||
db::Box b = bbox ();
|
db::Box b = bbox ();
|
||||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (false));
|
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 ()) {
|
} 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 ..
|
// map AND with box to clip ..
|
||||||
db::Box b = other.bbox ();
|
db::Box b = other.bbox ();
|
||||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (false));
|
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);
|
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||||
for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
|
for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
|
||||||
if (p.prop_id () != 0) {
|
db::properties_id_type prop_id = p.prop_id ();
|
||||||
shapes.insert (db::PolygonWithProperties (*p, pm (p.prop_id ())));
|
if (prop_id != 0) {
|
||||||
|
shapes.insert (db::PolygonWithProperties (*p, pm (prop_id)));
|
||||||
} else {
|
} else {
|
||||||
shapes.insert (*p);
|
shapes.insert (*p);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1548,6 +1548,11 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
|
||||||
{
|
{
|
||||||
set_description ("check");
|
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_include_zero (false);
|
||||||
m_check.set_whole_edges (options.whole_edges);
|
m_check.set_whole_edges (options.whole_edges);
|
||||||
m_check.set_ignore_angle (options.ignore_angle);
|
m_check.set_ignore_angle (options.ignore_angle);
|
||||||
|
|
|
||||||
|
|
@ -473,10 +473,14 @@ 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) {
|
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);
|
db::Polygon poly = s->edge_pair ().normalized ().to_polygon (e);
|
||||||
if (poly.vertices () >= 3) {
|
if (poly.vertices () >= 3) {
|
||||||
|
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 ()));
|
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new db::DeepRegion (new_layer);
|
return new db::DeepRegion (new_layer);
|
||||||
}
|
}
|
||||||
|
|
@ -491,13 +495,21 @@ 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) {
|
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 ();
|
db::EdgePair ep = s->edge_pair ();
|
||||||
if (first) {
|
if (first) {
|
||||||
|
if (s->prop_id () != 0) {
|
||||||
|
output.insert (db::EdgeWithProperties (ep.first (), s->prop_id ()));
|
||||||
|
} else {
|
||||||
output.insert (ep.first ());
|
output.insert (ep.first ());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (second) {
|
if (second) {
|
||||||
|
if (s->prop_id () != 0) {
|
||||||
|
output.insert (db::EdgeWithProperties (ep.second (), s->prop_id ()));
|
||||||
|
} else {
|
||||||
output.insert (ep.second ());
|
output.insert (ep.second ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new db::DeepEdges (new_layer);
|
return new db::DeepEdges (new_layer);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1893,6 +1893,11 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
||||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
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;
|
const db::DeepRegion *other_deep = 0;
|
||||||
unsigned int other_layer = 0;
|
unsigned int other_layer = 0;
|
||||||
bool other_is_merged = true;
|
bool other_is_merged = true;
|
||||||
|
|
@ -1959,7 +1964,7 @@ 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::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,
|
db::local_processor<db::PolygonRefWithProperties, db::PolygonRefWithProperties, db::EdgePairWithProperties> proc (subject_layout, subject_top,
|
||||||
intruder_layout, intruder_top,
|
intruder_layout, intruder_top,
|
||||||
subject_breakout_cells, intruder_breakout_cells);
|
subject_breakout_cells, intruder_breakout_cells);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1300,19 +1300,32 @@ DeepShapeStore::insert_as_polygons (const DeepLayer &deep_layer, db::Layout *int
|
||||||
|
|
||||||
if (s->is_edge_pair ()) {
|
if (s->is_edge_pair ()) {
|
||||||
|
|
||||||
|
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));
|
out.insert (s->edge_pair ().normalized ().to_simple_polygon (enl));
|
||||||
|
}
|
||||||
|
|
||||||
} else if (s->is_path () || s->is_polygon () || s->is_box ()) {
|
} else if (s->is_path () || s->is_polygon () || s->is_box ()) {
|
||||||
|
|
||||||
db::Polygon poly;
|
db::Polygon poly;
|
||||||
s->polygon (poly);
|
s->polygon (poly);
|
||||||
|
if (s->prop_id () != 0) {
|
||||||
|
out.insert (db::PolygonWithProperties (poly, s->prop_id ()));
|
||||||
|
} else {
|
||||||
out.insert (poly);
|
out.insert (poly);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (s->is_text ()) {
|
} else if (s->is_text ()) {
|
||||||
|
|
||||||
db::Text t;
|
db::Text t;
|
||||||
s->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;
|
typedef Iterator const_iterator;
|
||||||
|
|
||||||
ShapesToOutputContainerAdaptor ()
|
ShapesToOutputContainerAdaptor ()
|
||||||
: mp_shapes (0)
|
: mp_shapes (0), m_prop_id (0)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapesToOutputContainerAdaptor (db::Shapes &shapes)
|
ShapesToOutputContainerAdaptor (db::Shapes &shapes, db::properties_id_type prop_id = 0)
|
||||||
: mp_shapes (&shapes)
|
: mp_shapes (&shapes), m_prop_id (prop_id)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -432,11 +432,16 @@ public:
|
||||||
|
|
||||||
void insert (const db::Edge &edge)
|
void insert (const db::Edge &edge)
|
||||||
{
|
{
|
||||||
|
if (m_prop_id != 0) {
|
||||||
|
mp_shapes->insert (db::EdgeWithProperties (edge, m_prop_id));
|
||||||
|
} else {
|
||||||
mp_shapes->insert (edge);
|
mp_shapes->insert (edge);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
db::Shapes *mp_shapes;
|
db::Shapes *mp_shapes;
|
||||||
|
db::properties_id_type m_prop_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -445,13 +450,13 @@ private:
|
||||||
struct DB_PUBLIC EdgeBooleanClusterCollectorToShapes
|
struct DB_PUBLIC EdgeBooleanClusterCollectorToShapes
|
||||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor>
|
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor>
|
||||||
{
|
{
|
||||||
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op)
|
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op, db::properties_id_type prop_id = 0)
|
||||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor> (&m_adaptor, op), m_adaptor (*output)
|
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor> (&m_adaptor, op), m_adaptor (*output, prop_id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op, db::Shapes *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), m_adaptor2 (*output2)
|
: 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 *
|
EdgePairsDelegate *
|
||||||
FlatEdgePairs::filter_in_place (const EdgePairFilterBase &filter)
|
FlatEdgePairs::filter_in_place (const EdgePairFilterBase &filter)
|
||||||
{
|
{
|
||||||
|
// TODO: implement property support
|
||||||
|
|
||||||
db::Shapes &ep = *mp_edge_pairs;
|
db::Shapes &ep = *mp_edge_pairs;
|
||||||
|
|
||||||
edge_pair_iterator_type pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin ();
|
edge_pair_iterator_type pw = ep.get_layer<db::EdgePair, db::unstable_layer_tag> ().begin ();
|
||||||
|
|
@ -121,23 +123,23 @@ EdgePairsDelegate *FlatEdgePairs::add (const EdgePairs &other) const
|
||||||
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*this));
|
std::unique_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (*this));
|
||||||
new_edge_pairs->invalidate_cache ();
|
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 ());
|
const FlatEdgePairs *other_flat = dynamic_cast<const FlatEdgePairs *> (other.delegate ());
|
||||||
if (other_flat) {
|
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 {
|
} 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) {
|
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++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);
|
new_edge_pairs->raw_edge_pairs ().insert (*p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,23 +152,23 @@ EdgePairsDelegate *FlatEdgePairs::add_in_place (const EdgePairs &other)
|
||||||
|
|
||||||
db::Shapes &ep = *mp_edge_pairs;
|
db::Shapes &ep = *mp_edge_pairs;
|
||||||
|
|
||||||
|
db::PropertyMapper pm (properties_repository (), &other.properties_repository ());
|
||||||
|
|
||||||
const FlatEdgePairs *other_flat = dynamic_cast<const FlatEdgePairs *> (other.delegate ());
|
const FlatEdgePairs *other_flat = dynamic_cast<const FlatEdgePairs *> (other.delegate ());
|
||||||
if (other_flat) {
|
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 {
|
} 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) {
|
for (EdgePairsIterator p (other.begin ()); ! p.at_end (); ++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);
|
ep.insert (*p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,9 +213,16 @@ void
|
||||||
FlatEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
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::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) {
|
for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||||
|
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));
|
out.insert (p->normalized ().to_simple_polygon (enl));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -110,10 +110,26 @@ FlatEdges::ensure_merged_edges_valid () const
|
||||||
|
|
||||||
mp_merged_edges->clear ();
|
mp_merged_edges->clear ();
|
||||||
|
|
||||||
|
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
db::Shapes tmp (false);
|
db::Shapes tmp (false);
|
||||||
|
|
||||||
|
if (! need_split_props) {
|
||||||
|
|
||||||
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr);
|
EdgeBooleanClusterCollectorToShapes cluster_collector (&tmp, EdgeOr);
|
||||||
|
|
||||||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
|
||||||
scanner.reserve (mp_edges->size ());
|
scanner.reserve (mp_edges->size ());
|
||||||
|
|
||||||
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
|
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
|
||||||
|
|
@ -124,6 +140,33 @@ FlatEdges::ensure_merged_edges_valid () const
|
||||||
|
|
||||||
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
|
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);
|
mp_merged_edges->swap (tmp);
|
||||||
m_merged_edges_valid = true;
|
m_merged_edges_valid = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -419,6 +419,17 @@ OriginalLayerRegion::init ()
|
||||||
m_merged_polygons_valid = false;
|
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
|
void
|
||||||
OriginalLayerRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
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
|
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||||
// lock the layout against updates while inserting
|
// lock the layout against updates while inserting
|
||||||
db::LayoutLocker locker (layout);
|
db::LayoutLocker locker (layout);
|
||||||
|
AssignProp ap;
|
||||||
for (db::RecursiveShapeIterator i = m_iter; !i.at_end (); ++i) {
|
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>
|
template <class TS, class TI>
|
||||||
void
|
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);
|
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);
|
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>
|
template <class TS, class TI>
|
||||||
class check_local_operation_with_properties
|
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:
|
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);
|
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 bool requests_single_subjects () const { return true; }
|
||||||
virtual std::string description () const;
|
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:
|
private:
|
||||||
mutable db::PropertyMapper m_pms, m_pmi;
|
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<Result> delivery (&layout, st);
|
||||||
|
shape_collection_processor_delivery<db::object_with_properties<Result> > delivery_wp (&layout, st);
|
||||||
|
|
||||||
const db::ICplxTrans &tr = v->first;
|
const db::ICplxTrans &tr = v->first;
|
||||||
db::ICplxTrans trinv = tr.inverted ();
|
db::ICplxTrans trinv = tr.inverted ();
|
||||||
|
|
@ -220,9 +221,13 @@ shape_collection_processed_impl (const db::DeepLayer &input, const shape_collect
|
||||||
heap.clear ();
|
heap.clear ();
|
||||||
filter.process (s, heap);
|
filter.process (s, heap);
|
||||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||||
|
if (si->prop_id ()) {
|
||||||
|
delivery_wp.put (db::object_with_properties<Result> (i->transformed (trinv), si->prop_id ()));
|
||||||
|
} else {
|
||||||
delivery.put (i->transformed (trinv));
|
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 ());
|
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||||
shape_collection_processor_delivery<Result> delivery (&layout, &st);
|
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) {
|
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||||
Shape s;
|
Shape s;
|
||||||
|
|
@ -237,9 +243,13 @@ shape_collection_processed_impl (const db::DeepLayer &input, const shape_collect
|
||||||
heap.clear ();
|
heap.clear ();
|
||||||
filter.process (s, heap);
|
filter.process (s, heap);
|
||||||
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
|
||||||
|
if (si->prop_id ()) {
|
||||||
|
delivery_wp.put (db::object_with_properties<Result> (*i, si->prop_id ()));
|
||||||
|
} else {
|
||||||
delivery.put (*i);
|
delivery.put (*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1405,47 +1405,15 @@ static db::Pin *create_pin (db::Circuit *circuit, const std::string &name)
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<db::Net *>
|
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;
|
std::vector<db::Net *> n;
|
||||||
if (! circuit) {
|
n.reserve (nc.size ());
|
||||||
return res;
|
for (auto i = nc.begin (); i != nc.end (); ++i) {
|
||||||
|
n.push_back (const_cast<db::Net *> (*i));
|
||||||
}
|
}
|
||||||
|
|
||||||
tl::GlobPattern glob (name_pattern);
|
return n;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<const db::Net *>
|
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;
|
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 *>
|
static std::vector<const db::Net *>
|
||||||
nets_by_name_const_from_netlist (const db::Netlist *netlist, const std::string &name_pattern)
|
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 c = netlist->begin_circuits (); c != netlist->end_circuits (); ++c) {
|
||||||
for (auto n = c->begin_nets (); n != c->end_nets (); ++n) {
|
for (auto n = c->begin_nets (); n != c->end_nets (); ++n) {
|
||||||
const db::Net *net = n.operator-> ();
|
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);
|
res.push_back (net);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1492,6 +1467,12 @@ nets_by_name_const_from_netlist (const db::Netlist *netlist, const std::string &
|
||||||
return res;
|
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",
|
Class<db::Circuit> decl_dbCircuit (decl_dbNetlistObject, "db", "Circuit",
|
||||||
gsi::method_ext ("create_pin", &create_pin, gsi::arg ("name"),
|
gsi::method_ext ("create_pin", &create_pin, gsi::arg ("name"),
|
||||||
"@brief Creates a new \\Pin object inside the circuit\n"
|
"@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)
|
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,
|
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)
|
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,
|
return r->inside_check (other, d, db::RegionCheckOptions (whole_edges,
|
||||||
|
|
|
||||||
|
|
@ -149,22 +149,23 @@ TEST(0_Basic)
|
||||||
reg_copy.reset (0);
|
reg_copy.reset (0);
|
||||||
|
|
||||||
std::unique_ptr<db::Region> reg2 (l2n.make_layer ());
|
std::unique_ptr<db::Region> reg2 (l2n.make_layer ());
|
||||||
EXPECT_EQ (l2n.name (1u), "");
|
EXPECT_EQ (l2n.name (1u), "$1");
|
||||||
EXPECT_EQ (l2n.name (*reg2), "");
|
EXPECT_EQ (l2n.name (*reg2), "$1");
|
||||||
EXPECT_EQ (l2n.layer_of (*reg2), 1u);
|
EXPECT_EQ (l2n.layer_of (*reg2), 1u);
|
||||||
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), true);
|
EXPECT_EQ (l2n.internal_layout ()->is_valid_layer (1), true);
|
||||||
reg2.reset (0);
|
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"));
|
std::unique_ptr<db::Region> reg3 (l2n.make_layer ("l3"));
|
||||||
EXPECT_EQ (l2n.name (*reg3), "l3");
|
EXPECT_EQ (l2n.name (*reg3), "l3");
|
||||||
EXPECT_EQ (l2n.layer_of (*reg3), 1u);
|
EXPECT_EQ (l2n.layer_of (*reg3), 2u);
|
||||||
|
|
||||||
std::string s;
|
std::string s;
|
||||||
for (db::LayoutToNetlist::layer_iterator l = l2n.begin_layers (); l != l2n.end_layers (); ++l) {
|
for (db::LayoutToNetlist::layer_iterator l = l2n.begin_layers (); l != l2n.end_layers (); ++l) {
|
||||||
s += tl::to_string (l->first) + ":" + l->second + ";";
|
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)
|
TEST(1_BasicExtraction)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module DRC
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name drc
|
# @name drc
|
||||||
# @brief Provides a generic DRC function for use with \DRC# expressions
|
# @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,
|
# This method implements the universal DRC which offers enhanced abilities,
|
||||||
# improved performance in some applications and better readability.
|
# 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
|
# 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.
|
# 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
|
# @h3 Outlook @/h3
|
||||||
#
|
#
|
||||||
# DRC expressions are quite rich and powerful. They provide a more intuitive way of
|
# 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.
|
# 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
|
@engine._context("drc") do
|
||||||
requires_region
|
requires_region
|
||||||
op.is_a?(DRCOpNode) || raise("A DRC expression is required for the argument (got #{op.inspect})")
|
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({})
|
node = op.create_node({})
|
||||||
result_cls = nil
|
result_cls = nil
|
||||||
if node.result_type == RBA::CompoundRegionOperationNode::ResultType::Region
|
if node.result_type == RBA::CompoundRegionOperationNode::ResultType::Region
|
||||||
|
|
@ -400,7 +419,7 @@ module DRC
|
||||||
result_cls = RBA::EdgePairs
|
result_cls = RBA::EdgePairs
|
||||||
end
|
end
|
||||||
if result_cls
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,85 @@ module DRC
|
||||||
DRCRectangleErrorFilter::new(RBA::Region::FourSidesAllowed)
|
DRCRectangleErrorFilter::new(RBA::Region::FourSidesAllowed)
|
||||||
end
|
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)
|
def pattern(p)
|
||||||
self._context("pattern") do
|
self._context("pattern") do
|
||||||
DRCPattern::new(true, p)
|
DRCPattern::new(true, p)
|
||||||
|
|
@ -2596,6 +2675,10 @@ CODE
|
||||||
@dss
|
@dss
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def _default_netter
|
||||||
|
@netter
|
||||||
|
end
|
||||||
|
|
||||||
def _netter
|
def _netter
|
||||||
@netter ||= DRC::DRCNetter::new(self)
|
@netter ||= DRC::DRCNetter::new(self)
|
||||||
end
|
end
|
||||||
|
|
@ -2775,7 +2858,8 @@ CODE
|
||||||
if cls == RBA::Region && clip && box
|
if cls == RBA::Region && clip && box
|
||||||
# HACK: deep regions will always clip in the constructor, so skip this
|
# HACK: deep regions will always clip in the constructor, so skip this
|
||||||
if ! @deep
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1744,9 +1744,10 @@ CODE
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name and
|
# @name and
|
||||||
# @brief Boolean AND operation
|
# @brief Boolean AND operation
|
||||||
# @synopsis layer.and(other)
|
# @synopsis layer.and(other [, prop_constraint ])
|
||||||
# The method computes a boolean AND between self and other.
|
# 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.
|
# 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
|
# 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
|
# @td @img(/images/drc_textpoly1.png) @/td
|
||||||
# @/tr
|
# @/tr
|
||||||
# @/table
|
# @/table
|
||||||
|
#
|
||||||
def and(other)
|
# When a properties constraint is given, the operation is performed
|
||||||
@engine._context("and") do
|
# only between shapes with the given relation. Together with the
|
||||||
self & other
|
# ability to provide net-annotated shapes through the \nets method, this
|
||||||
end
|
# allows constraining the boolean operation to shapes from the same or
|
||||||
end
|
# from different nets.
|
||||||
|
#
|
||||||
|
# See \global#prop_eq, \global#prop_ne and \global#prop_copy for details.
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name not
|
# @name not
|
||||||
# @brief Boolean NOT operation
|
# @brief Boolean NOT operation
|
||||||
# @synopsis layer.not(other)
|
# @synopsis layer.not(other [, prop_constraint ])
|
||||||
# The method computes a boolean NOT between self and other.
|
# The method computes a boolean NOT between self and other.
|
||||||
# It is an alias for the "-" operator.
|
# It is an alias for the "-" operator.
|
||||||
#
|
#
|
||||||
|
|
@ -1812,9 +1815,41 @@ CODE
|
||||||
# @td @img(/images/drc_textpoly2.png) @/td
|
# @td @img(/images/drc_textpoly2.png) @/td
|
||||||
# @/tr
|
# @/tr
|
||||||
# @/table
|
# @/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)
|
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
|
@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
|
self - other
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -3654,6 +3689,8 @@ CODE
|
||||||
# Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0". @/li
|
# 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 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 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
|
# @/ul
|
||||||
#
|
#
|
||||||
# Note that without the angle_limit, acute corners will always be reported, since two
|
# 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.
|
# 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.
|
# 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%
|
# %DRC%
|
||||||
# @name space
|
# @name space
|
||||||
|
|
@ -3754,7 +3821,6 @@ CODE
|
||||||
# @td @img(/images/drc_space1.png) @/td
|
# @td @img(/images/drc_space1.png) @/td
|
||||||
# @/tr
|
# @/tr
|
||||||
# @/table
|
# @/table
|
||||||
#
|
|
||||||
|
|
||||||
# %DRC%
|
# %DRC%
|
||||||
# @name isolated
|
# @name isolated
|
||||||
|
|
@ -4044,6 +4110,7 @@ CODE
|
||||||
shielded = nil
|
shielded = nil
|
||||||
opposite_filter = RBA::Region::NoOppositeFilter
|
opposite_filter = RBA::Region::NoOppositeFilter
|
||||||
rect_filter = RBA::Region::NoRectFilter
|
rect_filter = RBA::Region::NoRectFilter
|
||||||
|
prop_constraint = RBA::Region::IgnoreProperties
|
||||||
|
|
||||||
n = 1
|
n = 1
|
||||||
args.each do |a|
|
args.each do |a|
|
||||||
|
|
@ -4051,6 +4118,8 @@ CODE
|
||||||
metrics = a.value
|
metrics = a.value
|
||||||
elsif a.is_a?(DRCWholeEdges)
|
elsif a.is_a?(DRCWholeEdges)
|
||||||
whole_edges = a.value
|
whole_edges = a.value
|
||||||
|
elsif a.is_a?(DRCPropertiesConstraint)
|
||||||
|
prop_constraint = a.value
|
||||||
elsif a.is_a?(DRCOppositeErrorFilter)
|
elsif a.is_a?(DRCOppositeErrorFilter)
|
||||||
opposite_filter = a.value
|
opposite_filter = a.value
|
||||||
elsif a.is_a?(DRCRectangleErrorFilter)
|
elsif a.is_a?(DRCRectangleErrorFilter)
|
||||||
|
|
@ -4083,10 +4152,14 @@ CODE
|
||||||
if :#{f} != :width && :#{f} != :notch
|
if :#{f} != :width && :#{f} != :notch
|
||||||
args << opposite_filter
|
args << opposite_filter
|
||||||
args << rect_filter
|
args << rect_filter
|
||||||
|
args << false # negative
|
||||||
|
args << prop_constraint
|
||||||
elsif opposite_filter != RBA::Region::NoOppositeFilter
|
elsif opposite_filter != RBA::Region::NoOppositeFilter
|
||||||
raise("An opposite error filter cannot be used with this check")
|
raise("An opposite error filter cannot be used with this check")
|
||||||
elsif rect_filter != RBA::Region::NoRectFilter
|
elsif rect_filter != RBA::Region::NoRectFilter
|
||||||
raise("A rectangle error filter cannot be used with this check")
|
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
|
end
|
||||||
elsif shielded != nil
|
elsif shielded != nil
|
||||||
raise("Shielding can only be used for polygon layers")
|
raise("Shielding can only be used for polygon layers")
|
||||||
|
|
@ -4699,6 +4772,209 @@ CODE
|
||||||
end
|
end
|
||||||
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%
|
# %DRC%
|
||||||
# @name output
|
# @name output
|
||||||
# @brief Outputs the content of the layer
|
# @brief Outputs the content of the layer
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,24 @@ module DRC
|
||||||
end
|
end
|
||||||
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
|
# A wrapper for a pair of limit values
|
||||||
# This class is used to identify projection limits for DRC
|
# This class is used to identify projection limits for DRC
|
||||||
# functions
|
# functions
|
||||||
|
|
|
||||||
|
|
@ -1396,3 +1396,8 @@ TEST(60d_issue1216)
|
||||||
{
|
{
|
||||||
run_test (_this, "60", true);
|
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