mirror of https://github.com/KLayout/klayout.git
WIP: stashed another version of complex DRC framework
This commit is contained in:
parent
815b81ce59
commit
43302dbe68
|
|
@ -32,7 +32,7 @@ class DRCOpNode
|
||||||
attr_accessor :engine
|
attr_accessor :engine
|
||||||
|
|
||||||
def initialize(engine, node = nil)
|
def initialize(engine, node = nil)
|
||||||
@node = nil
|
@node = node
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
self.description = "Basic"
|
self.description = "Basic"
|
||||||
end
|
end
|
||||||
|
|
@ -45,37 +45,11 @@ class DRCOpNode
|
||||||
return indent + self.description
|
return indent + self.description
|
||||||
end
|
end
|
||||||
|
|
||||||
def _build_log_bool_node(other, op)
|
|
||||||
if ! other.is_a?(DRCOpNode)
|
|
||||||
raise("Second argument to #{op.to_s} must be a DRC expression")
|
|
||||||
end
|
|
||||||
if self.is_a?(DRCOpNodeLogicalBool) && self.op == op
|
|
||||||
self.children << other
|
|
||||||
return self
|
|
||||||
elsif other.is_a?(DRCOpNodeLogicalBool) && other.op == op
|
|
||||||
other.children.unshift(self)
|
|
||||||
return other
|
|
||||||
else
|
|
||||||
res = DRCOpNodeLogicalBool::new(op)
|
|
||||||
res.children = [ self, other ]
|
|
||||||
res
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
%w(and or).each do |f|
|
|
||||||
eval <<"CODE"
|
|
||||||
def #
|
|
||||||
#{f}(other)
|
|
||||||
self._build_log_bool_node(other, :#{f})
|
|
||||||
end
|
|
||||||
CODE
|
|
||||||
end
|
|
||||||
|
|
||||||
def _build_geo_bool_node(other, op)
|
def _build_geo_bool_node(other, op)
|
||||||
if ! other.is_a?(DRCOpNode)
|
if ! other.is_a?(DRCOpNode)
|
||||||
raise("Second argument to #{op.to_s} must be a DRC expression")
|
raise("Second argument to #{op.to_s} must be a DRC expression")
|
||||||
end
|
end
|
||||||
DRCOpNodeBool::new(op, self, other)
|
DRCOpNodeBool::new(@engine, op, self, other)
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(& - ^ | +).each do |f|
|
%w(& - ^ | +).each do |f|
|
||||||
|
|
@ -91,10 +65,8 @@ CODE
|
||||||
if self.respond_to?(:inverted)
|
if self.respond_to?(:inverted)
|
||||||
return self.inverted
|
return self.inverted
|
||||||
else
|
else
|
||||||
res = DRCOpNodeCase::new
|
empty = RBA::CompoundRegionOperationNode::new_empty(RBA::CompoundRegionOperationNode::ResultType::Region)
|
||||||
res.children << self
|
DRCOpNodeCase::new(@engine, [ self, DRCOpNode::new(@engine, empty), @engine.primary ])
|
||||||
res.children << nil
|
|
||||||
res.children << @engine.primary
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -237,28 +209,28 @@ CODE
|
||||||
CODE
|
CODE
|
||||||
end
|
end
|
||||||
|
|
||||||
def odd_polygons
|
def odd_polygon
|
||||||
return DRCOpNodeFilter(@engine, self, :new_strange_polygons_filter, "odd_polygons")
|
return DRCOpNodeFilter::new(@engine, self, :new_strange_polygons_filter, "odd_polygon")
|
||||||
end
|
end
|
||||||
|
|
||||||
def rectangles
|
def rectangle
|
||||||
return DRCOpNodeFilter(@engine, self, :new_rectangle_filter, "rectangles")
|
return DRCOpNodeFilter::new(@engine, self, :new_rectangle_filter, "rectangle")
|
||||||
end
|
end
|
||||||
|
|
||||||
def rectilinear
|
def rectilinear
|
||||||
return DRCOpNodeFilter(@engine, self, :new_rectilinear_filter, "rectilinear")
|
return DRCOpNodeFilter::new(@engine, self, :new_rectilinear_filter, "rectilinear")
|
||||||
end
|
end
|
||||||
|
|
||||||
def holes
|
def holes
|
||||||
return DRCOpNodeFilter(@engine, self, :new_holes, "holes")
|
return DRCOpNodeFilter::new(@engine, self, :new_holes, "holes")
|
||||||
end
|
end
|
||||||
|
|
||||||
def hulls
|
def hull
|
||||||
return DRCOpNodeFilter(@engine, self, :new_hulls, "hulls")
|
return DRCOpNodeFilter::new(@engine, self, :new_hulls, "hull")
|
||||||
end
|
end
|
||||||
|
|
||||||
def edges
|
def edges
|
||||||
return DRCOpNodeFilter(@engine, self, :new_edges, "edges")
|
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges")
|
||||||
end
|
end
|
||||||
|
|
||||||
def sized(*args)
|
def sized(*args)
|
||||||
|
|
@ -288,35 +260,35 @@ CODE
|
||||||
end
|
end
|
||||||
args << mode
|
args << mode
|
||||||
|
|
||||||
return DRCOpNodeFilter(@engine, self, :new_sized, "sized", *args)
|
return DRCOpNodeFilter::new(@engine, self, :new_sized, "sized", *args)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def extents(e = 0)
|
def extents(e = 0)
|
||||||
return DRCOpNodeFilter(@engine, self, :new_extents, "extents", self._make_value(e, :e))
|
return DRCOpNodeFilter::new(@engine, self, :new_extents, "extents", self._make_value(e, :e))
|
||||||
end
|
end
|
||||||
|
|
||||||
def first_edges
|
def first_edges
|
||||||
return DRCOpNodeFilter(@engine, self, :new_edge_pair_to_first_edges, "first_edges")
|
return DRCOpNodeFilter::new(@engine, self, :new_edge_pair_to_first_edges, "first_edges")
|
||||||
end
|
end
|
||||||
|
|
||||||
def second_edges
|
def second_edges
|
||||||
return DRCOpNodeFilter(@engine, self, :new_edge_pair_to_second_edges, "second_edges")
|
return DRCOpNodeFilter::new(@engine, self, :new_edge_pair_to_second_edges, "second_edges")
|
||||||
end
|
end
|
||||||
|
|
||||||
def end_segments(length, fraction = 0.0)
|
def end_segments(length, fraction = 0.0)
|
||||||
self._check_numeric(fraction, :fraction)
|
self._check_numeric(fraction, :fraction)
|
||||||
return DRCOpNodeFilter(@engine, self, :new_end_segments, "end_segments", self._make_value(length, :length), fraction)
|
return DRCOpNodeFilter::new(@engine, self, :new_end_segments, "end_segments", self._make_value(length, :length), fraction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_segments(length, fraction = 0.0)
|
def start_segments(length, fraction = 0.0)
|
||||||
self._check_numeric(fraction, :fraction)
|
self._check_numeric(fraction, :fraction)
|
||||||
return DRCOpNodeFilter(@engine, self, :new_start_segments, "start_segments", self._make_value(length, :length), fraction)
|
return DRCOpNodeFilter::new(@engine, self, :new_start_segments, "start_segments", self._make_value(length, :length), fraction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def centers(length, fraction = 0.0)
|
def centers(length, fraction = 0.0)
|
||||||
self._check_numeric(fraction, :fraction)
|
self._check_numeric(fraction, :fraction)
|
||||||
return DRCOpNodeFilter(@engine, self, :new_centers, "centers", self._make_value(length, :length), fraction)
|
return DRCOpNodeFilter::new(@engine, self, :new_centers, "centers", self._make_value(length, :length), fraction)
|
||||||
end
|
end
|
||||||
|
|
||||||
def extended(*args)
|
def extended(*args)
|
||||||
|
|
@ -336,20 +308,20 @@ CODE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return DRCOpNodeFilter(@engine, self, :new_extended, "extended", *args)
|
return DRCOpNodeFilter::new(@engine, self, :new_extended, "extended", *args)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def extended_in(e)
|
def extended_in(e)
|
||||||
return DRCOpNodeFilter(@engine, self, :new_extended_in, "extended_in", self._make_value(e))
|
return DRCOpNodeFilter::new(@engine, self, :new_extended_in, "extended_in", self._make_value(e))
|
||||||
end
|
end
|
||||||
|
|
||||||
def extended_out(e)
|
def extended_out(e)
|
||||||
return DRCOpNodeFilter(@engine, self, :new_extended_out, "extended_out", self._make_value(e))
|
return DRCOpNodeFilter::new(@engine, self, :new_extended_out, "extended_out", self._make_value(e))
|
||||||
end
|
end
|
||||||
|
|
||||||
def polygons
|
def polygons
|
||||||
return DRCOpNodeFilter(@engine, self, :new_polygons, "polygons")
|
return DRCOpNodeFilter::new(@engine, self, :new_polygons, "polygons")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -371,8 +343,8 @@ class DRCOpNodeLogicalBool < DRCOpNode
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_node
|
def create_node
|
||||||
log_op = { :and => RBA::CompoundOperationNode::LogAnd, :or => RBA::CompoundOperationNode::LogOr }[self.op]
|
log_op = { :land => RBA::CompoundRegionOperationNode::LogicalOp::LogAnd, :lor => RBA::CompoundRegionOperationNode::LogicalOp::LogOr }[self.op]
|
||||||
RBA::CompoundOperationNode::new_logical_boolean(log_op, false, self.children.collect { |c| c.create_node })
|
RBA::CompoundRegionOperationNode::new_logical_boolean(log_op, false, self.children.collect { |c| c.create_node })
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -394,17 +366,24 @@ class DRCOpNodeBool < DRCOpNode
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_node
|
def create_node
|
||||||
bool_op = { :& => RBA::CompoundOperationNode::And,
|
bool_op = { :& => RBA::CompoundRegionOperationNode::GeometricalOp::And,
|
||||||
:+ => RBA::CompoundOperationNode::Or,
|
:+ => RBA::CompoundRegionOperationNode::GeometricalOp::Or,
|
||||||
:| => RBA::CompoundOperationNode::Or,
|
:| => RBA::CompoundRegionOperationNode::GeometricalOp::Or,
|
||||||
:- => RBA::CompoundOperationNode::Not,
|
:- => RBA::CompoundRegionOperationNode::GeometricalOp::Not,
|
||||||
:^ => RBA::CompoundOperationNode::Xor }[self.op]
|
:^ => RBA::CompoundRegionOperationNode::GeometricalOp::Xor }[self.op]
|
||||||
RBA::CompoundOperationNode::new_logical_boolean(bool_op, false, self.children.collect { |c| c.create_node })
|
nodes = self.children.collect do |c|
|
||||||
|
n = c.create_node
|
||||||
|
if n.result_type == RBA::CompoundRegionOperationNode::ResultType::EdgePairs
|
||||||
|
n = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(n)
|
||||||
|
end
|
||||||
|
n
|
||||||
|
end
|
||||||
|
RBA::CompoundRegionOperationNode::new_geometrical_boolean(bool_op, *nodes)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class DRCOpCase < DRCOpNode
|
class DRCOpNodeCase < DRCOpNode
|
||||||
|
|
||||||
attr_accessor :children
|
attr_accessor :children
|
||||||
|
|
||||||
|
|
@ -419,7 +398,7 @@ class DRCOpCase < DRCOpNode
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_node
|
def create_node
|
||||||
RBA::CompoundOperationNode::new_case(self.children.collect { |c| c.create_node })
|
RBA::CompoundRegionOperationNode::new_case(self.children.collect { |c| c.create_node })
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
@ -567,7 +546,7 @@ class DRCOpNodeAreaFilter < DRCOpNodeWithCompare
|
||||||
attr_accessor :inverted
|
attr_accessor :inverted
|
||||||
|
|
||||||
def initialize(engine, input)
|
def initialize(engine, input)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.input = input
|
self.input = input
|
||||||
self.inverted = false
|
self.inverted = false
|
||||||
self.description = "area"
|
self.description = "area"
|
||||||
|
|
@ -600,7 +579,7 @@ class DRCOpNodeEdgeLengthFilter < DRCOpNodeWithCompare
|
||||||
attr_accessor :inverted
|
attr_accessor :inverted
|
||||||
|
|
||||||
def initialize(engine, input)
|
def initialize(engine, input)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.input = input
|
self.input = input
|
||||||
self.inverted = false
|
self.inverted = false
|
||||||
self.description = "length"
|
self.description = "length"
|
||||||
|
|
@ -633,7 +612,7 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare
|
||||||
attr_accessor :inverted
|
attr_accessor :inverted
|
||||||
|
|
||||||
def initialize(engine, input)
|
def initialize(engine, input)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.input = input
|
self.input = input
|
||||||
self.inverted = false
|
self.inverted = false
|
||||||
self.description = "angle"
|
self.description = "angle"
|
||||||
|
|
@ -665,7 +644,7 @@ class DRCOpNodePerimeterFilter < DRCOpNodeWithCompare
|
||||||
attr_accessor :inverted
|
attr_accessor :inverted
|
||||||
|
|
||||||
def initialize(engine, input)
|
def initialize(engine, input)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.input = input
|
self.input = input
|
||||||
self.inverted = false
|
self.inverted = false
|
||||||
self.description = "perimeter"
|
self.description = "perimeter"
|
||||||
|
|
@ -699,7 +678,7 @@ class DRCOpNodeInteractingWithCount < DRCOpNodeWithCompare
|
||||||
attr_accessor :op
|
attr_accessor :op
|
||||||
|
|
||||||
def initialize(engine, a, b, op)
|
def initialize(engine, a, b, op)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.a = a
|
self.a = a
|
||||||
self.b = b
|
self.b = b
|
||||||
self.op = op
|
self.op = op
|
||||||
|
|
@ -734,7 +713,7 @@ class DRCOpNodeInteracting < DRCOpNode
|
||||||
attr_accessor :op
|
attr_accessor :op
|
||||||
|
|
||||||
def initialize(engine, a, b, op)
|
def initialize(engine, a, b, op)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.a = a
|
self.a = a
|
||||||
self.b = b
|
self.b = b
|
||||||
self.op = op
|
self.op = op
|
||||||
|
|
@ -763,7 +742,7 @@ class DRCOpNodeFilter < DRCOpNode
|
||||||
attr_accessor :args
|
attr_accessor :args
|
||||||
|
|
||||||
def initialize(engine, input, factory, description, args = [])
|
def initialize(engine, input, factory, description, args = [])
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.input = input
|
self.input = input
|
||||||
self.factory = factory
|
self.factory = factory
|
||||||
self.args = args
|
self.args = args
|
||||||
|
|
@ -817,35 +796,28 @@ class DRCOpNodeCheck < DRCOpNodeWithCompare
|
||||||
:isolated => :new_isolated_check, :overlap => :new_overlap_check,
|
:isolated => :new_isolated_check, :overlap => :new_overlap_check,
|
||||||
:enclosing => :new_inside_check }[self.check]
|
:enclosing => :new_inside_check }[self.check]
|
||||||
|
|
||||||
res = nil
|
|
||||||
|
|
||||||
if self.lt || self.le
|
if self.lt || self.le
|
||||||
dmin = self.le ? self._make_value(self.le, :le) + 1 : self._make_value(self.lt, :lt)
|
dmin = self.le ? self._make_value(self.le, :le) + 1 : self._make_value(self.lt, :lt)
|
||||||
res = RBA::CompoundRegionOperationNode::send(factory, dmin, *self.args)
|
res = RBA::CompoundRegionOperationNode::send(factory, dmin, *self.args)
|
||||||
|
else
|
||||||
|
res = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.gt || self.ge
|
if self.gt || self.ge
|
||||||
dmax = self.ge ? self._make_value(self.ge, :ge) : self._make_value(self.gt, :gt) + 1
|
dmax = self.ge ? self._make_value(self.ge, :ge) : self._make_value(self.gt, :gt) + 1
|
||||||
inv = RBA::CompoundRegionOperationNode::send(factory, dmax, *self.args)
|
max_check = RBA::CompoundRegionOperationNode::send(factory, dmax, *self.args + [ true ])
|
||||||
# TODO: instead of doing the NOT we could make use of inverse output of the checks
|
res_max = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(max_check)
|
||||||
# (needs GSI enabling first)
|
|
||||||
if self.check == :width || self.check == :notch
|
|
||||||
# Same polygon check - we need to take both edges of the result
|
|
||||||
to_subtract = RBA::CompoundRegionOperationNode::new_edges(inv)
|
|
||||||
else
|
|
||||||
to_subtract = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(inv)
|
|
||||||
end
|
|
||||||
if res
|
if res
|
||||||
if self.check == :width || self.check == :notch
|
if self.check == :width || self.check == :notch
|
||||||
# Same polygon check - we need to take both edges of the result
|
# Same polygon check - we need to take both edges of the result
|
||||||
subtract_from = RBA::CompoundRegionOperationNode::new_edges(res)
|
and_with = RBA::CompoundRegionOperationNode::new_edges(res)
|
||||||
else
|
else
|
||||||
subtract_from = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(res)
|
and_with = RBA::CompoundRegionOperationNode::new_edge_pair_to_first_edges(res)
|
||||||
end
|
end
|
||||||
|
res = RBA::CompoundRegionOperationNode::new_geometrical_boolean(RBA::CompoundRegionOperationNode::GeometricalOp::And, and_with, res_max)
|
||||||
else
|
else
|
||||||
subtract_from = RBA::CompoundRegionOperationNode::new_edges(RBA::CompoundRegionOperationNode::new_primary)
|
res = res_max
|
||||||
end
|
end
|
||||||
res = RBA::CompoundRegionOperationNode::new_geometrical_boolean(RBA::CompoundRegionOperationNode::GeometricalOp::Not, subtract_from, to_subtract)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
@ -861,7 +833,7 @@ class DRCOpNodeBBoxParameterFilter < DRCOpNodeWithCompare
|
||||||
attr_accessor :inverted
|
attr_accessor :inverted
|
||||||
|
|
||||||
def initialize(engine, parameter, input, description)
|
def initialize(engine, parameter, input, description)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.parameter = parameter
|
self.parameter = parameter
|
||||||
self.input = input
|
self.input = input
|
||||||
self.inverted = false
|
self.inverted = false
|
||||||
|
|
@ -892,7 +864,7 @@ class DRCOpNodeCornersFilter < DRCOpNodeWithCompare
|
||||||
attr_accessor :inverted
|
attr_accessor :inverted
|
||||||
|
|
||||||
def initialize(engine, as_dots, input)
|
def initialize(engine, as_dots, input)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.as_dots = as_dots
|
self.as_dots = as_dots
|
||||||
self.input = input
|
self.input = input
|
||||||
self.description = "corners"
|
self.description = "corners"
|
||||||
|
|
@ -919,7 +891,7 @@ class DRCOpNodeRelativeExtents < DRCOpNode
|
||||||
attr_accessor :as_edges, :fx1, :fx2, :fy1, :fy2, :dx, :dy
|
attr_accessor :as_edges, :fx1, :fx2, :fy1, :fy2, :dx, :dy
|
||||||
|
|
||||||
def initialize(engine, input, as_edges, fx1, fx2, fy1, fy2, dx = 0, dy = 0)
|
def initialize(engine, input, as_edges, fx1, fx2, fy1, fy2, dx = 0, dy = 0)
|
||||||
self.super(engine)
|
super(engine)
|
||||||
self.input = input
|
self.input = input
|
||||||
self.as_edges = as_edges
|
self.as_edges = as_edges
|
||||||
self.description = "extents"
|
self.description = "extents"
|
||||||
|
|
@ -953,9 +925,7 @@ class DRCEngine
|
||||||
end
|
end
|
||||||
anum += 1
|
anum += 1
|
||||||
end
|
end
|
||||||
res = DRCOpNodeCase::new(self)
|
DRCOpNodeCase::new(self, args)
|
||||||
res.children = args
|
|
||||||
return res
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def secondary(layer)
|
def secondary(layer)
|
||||||
|
|
@ -971,7 +941,22 @@ class DRCEngine
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
%w(area perimeter bbox_min bbox_max bbox_width bbox_height rectangles rectilinear edges odd_polygons hulls holes).each do |f|
|
%w(land lor).each do |f|
|
||||||
|
eval <<"CODE"
|
||||||
|
def #{f}(*args)
|
||||||
|
args.each_with_index do |a,ia|
|
||||||
|
if ! a.is_a?(DRCOpNode)
|
||||||
|
raise("Argument #" + (ia + 1).to_s + " to #{f} must be a DRC expression")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
res = DRCOpNodeLogicalBool::new(self, :#{f})
|
||||||
|
res.children = args
|
||||||
|
res
|
||||||
|
end
|
||||||
|
CODE
|
||||||
|
end
|
||||||
|
|
||||||
|
%w(area perimeter bbox_min bbox_max bbox_width bbox_height rectangle rectilinear edges odd_polygon hull holes).each do |f|
|
||||||
eval <<"CODE"
|
eval <<"CODE"
|
||||||
def #{f}
|
def #{f}
|
||||||
primary.#{f}
|
primary.#{f}
|
||||||
|
|
@ -1048,8 +1033,8 @@ CODE
|
||||||
elsif a.is_a?(DRCOpNode)
|
elsif a.is_a?(DRCOpNode)
|
||||||
other = a
|
other = a
|
||||||
elsif a.is_a?(DRCProjectionLimits)
|
elsif a.is_a?(DRCProjectionLimits)
|
||||||
minp = self._make_value(a.min, :pmin)
|
minp = self._prep_value(a.min)
|
||||||
maxp = self._make_value(a.max, :pmax)
|
maxp = self._prep_value(a.max)
|
||||||
elsif a.is_a?(DRCShielded)
|
elsif a.is_a?(DRCShielded)
|
||||||
shielded = a.value
|
shielded = a.value
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue