"Edit/Selection/Merge Shapes" does not work. Sometime the path will just disappear. In most case, they are converted but does not get filled. How can I convert a path to filled polygon or box?
Another question will be how to convert polygon to path?
A path will disappear on merging if it has not width. That is because the merge operation creates an equivalent polygon area and if the path does not cover an area none is generated.
Please consider the following: in GDS files, the objects typically represent some "material". There are no "lines" in GDS (well, it's possible, but not common). There is only "area" and all operations will perform some transformation of "area" into "area". Plain lines (such as zero-width paths) do not represent area and get lost in these operations.
Maybe that also explains why there is no polygon to path conversion. I guess you are looking for an operation that traces the border of a polygon. But again - lines are not popular objects in GDS.
In case you consider a path to be a line (width=0), how about:
(1. Create path)
2. Open path properties (double click)
3. Select & copy all coordinates/points from the list --> [CTRL]+[A] --> [CTRL]+[C]
(4. delete path)
5. create temporary polygon (e.g. triangle)
6. Open polygon properties (double click)
7. Replace the coordinates by pasting from clipboard --> [CTRL]+[A] --> [CTRL]+[V]
8. Done :-)
- In case of closed paths (start point = end point) you should delete the duplicate point.
- Polygon to path works the same way (note: copy 1st point to the end of the list to get a closed path again).
- I have no idea how to convert the actual >>area<< covered by path/box to a polygon.
To convert a path or box to a polygon, you can use "Edit/Selection/Merge Shapes". The main functionality of that function is to join overlapping shapes into one polygon. But a side effect is that everything selected will be converted to polygons, also if the selection is a single, non-polygon shape.
Using the merge function seem to delete/remove the object as well. The ability to convert zero width paths to polygons would be a great feature.
Any ideas?
I've tried to create a simple macro to accomplish the task. I can convert the object to a poly but the macro seems to double up the coords. Maybe you could point me in the right direction
view.transaction("Convert to Poly")
begin
view.each_object_selected do |obj|
if obj.shape.is_path?
poly = obj.shape
obj.shape.clear
obj.shape.polygon = poly
the path to polygon conversion using the points is just half the truth. Emulating what the DXF reader does is far more complex - the issues are hole resolution, orientation normalization and such.
Here is a script which basically does what the DXF reader implements. The core is the EdgeProcessor which can convert edge sets back to polygons doing all the magic of hole insertion and so forth. Decomposition of the paths into edges is easy but the EdgeProcessor is picky, so we'll have to sort out the edges which do not form oriented loops. The core functionality used within the DXF reader is not directly available to Ruby yet, so I am providing a brute force implementation here. It does a piecewise elimination of dangling edges and corrects the edge direction n a second step if required. Please see the notes in the text:
shapes = []
cell = nil
layer = nil
# collect the zero-width paths
lv = RBA::LayoutView::current
begin
lv.transaction("Join lines")
lv.each_object_selected do |s|
if !s.is_cell_inst? && s.shape.is_path? && s.shape.path_width == 0
shapes << s.shape
layer ||= s.layer
cell ||= lv.cellview(s.cv_index).layout.cell(s.cell_index)
end
end
lv.cancel
# collect the edges
edges = []
shapes.each do |s|
p0 = nil
s.path.each_point do |p|
p0 && p0 != p && (edges << RBA::Edge::new(p0, p))
p0 = p
end
end
# By providing a hash and eql? function we can use
# points as keys in hashes
class RBA::Point
def eql?(b)
self == b
end
def hash
s1 = 1
s2 = 0
[ self.x, self.y ].each do |v|
s1 = (s1 + v) % 65521
s2 = (s2 + s1) % 65521
end
(s2 << 16) | s1
end
end
# count the number of times a point is present
point_weight = {}
edges.each do |e|
point_weight[e.p1] = (point_weight[e.p1] || 0) + 1
point_weight[e.p2] = (point_weight[e.p2] || 0) + 1
end
# sort out edges with a dangling endpoint
# NOTE: this algorithm is O(N**2) in the worst case
# and is INEFFICIENT.
try_again = true
while try_again
try_again = false
new_edges = []
edges.each do |e|
pw1 = point_weight[e.p1]
pw2 = point_weight[e.p2]
if pw1 == 1 || pw2 == 1
point_weight[e.p1] -= 1
point_weight[e.p2] -= 1
try_again = true
else
new_edges << e
end
end
edges = new_edges
end
# count the number of times a point is present once again,
# this time assigning +1 for a start point and -1 for an
# end point. Hence a weight of 0 means there are edges
# connected in the right way (start to end point).
point_weight = {}
edges.each do |e|
point_weight[e.p1] = (point_weight[e.p1] || 0) + 1
point_weight[e.p2] = (point_weight[e.p2] || 0) - 1
end
# Change edge orientation in to correct
# wrongly oriented edges
try_again = true
while try_again
try_again = false
edges.each do |e|
pw1 = point_weight[e.p1]
pw2 = point_weight[e.p2]
if pw1 > 0 || pw2 < 0
point_weight[e.p1] -= 2
point_weight[e.p2] += 2
e.swap_points
try_again = true
end
end
end
# here is the actual edge to polygon conversion!
polygons = RBA::EdgeProcessor::new.simple_merge_e2p(edges, true, false)
# delete the edges and insert the polygons
# CAUTION: the polygons are put on the layer and cell where the first path was
# so don't select paths from multiple layers and cells
shapes.each do |s|
s.delete
end
if cell
polygons.each do |p|
cell.shapes(layer).insert(p)
end
end
ensure
lv.commit
end
Comments
Hi,
once again ... sorry for the late reply.
A path will disappear on merging if it has not width. That is because the merge operation creates an equivalent polygon area and if the path does not cover an area none is generated.
Please consider the following: in GDS files, the objects typically represent some "material". There are no "lines" in GDS (well, it's possible, but not common). There is only "area" and all operations will perform some transformation of "area" into "area". Plain lines (such as zero-width paths) do not represent area and get lost in these operations.
Maybe that also explains why there is no polygon to path conversion. I guess you are looking for an operation that traces the border of a polygon. But again - lines are not popular objects in GDS.
Matthias
(1. Create path)
2. Open path properties (double click)
3. Select & copy all coordinates/points from the list --> [CTRL]+[A] --> [CTRL]+[C]
(4. delete path)
5. create temporary polygon (e.g. triangle)
6. Open polygon properties (double click)
7. Replace the coordinates by pasting from clipboard --> [CTRL]+[A] --> [CTRL]+[V]
8. Done :-)
- In case of closed paths (start point = end point) you should delete the duplicate point.
- Polygon to path works the same way (note: copy 1st point to the end of the list to get a closed path again).
- I have no idea how to convert the actual >>area<< covered by path/box to a polygon.
Hi,
one way to solve the problem, thanks :-)
To convert a path or box to a polygon, you can use "Edit/Selection/Merge Shapes". The main functionality of that function is to join overlapping shapes into one polygon. But a side effect is that everything selected will be converted to polygons, also if the selection is a single, non-polygon shape.
Matthias
Using the merge function seem to delete/remove the object as well. The ability to convert zero width paths to polygons would be a great feature.
Any ideas?
Thx much
K-
A similar effect can be obtained by selecting "merge lines and auto-close open contours," in the dxf reader options panel.
Is there a way to manually preform the same operation in the layout editor with selected objects?
Thx
K-
No, there is no such feature. And I don't know anybody who needs it, apart from the DXF users. And for them there is the reader option.
Give me a thousand "likes" and I'll be motivated enough to implement it ...
Matthias
I've tried to create a simple macro to accomplish the task. I can convert the object to a poly but the macro seems to double up the coords. Maybe you could point me in the right direction
view.transaction("Convert to Poly")
begin
view.each_object_selected do |obj|
if obj.shape.is_path?
poly = obj.shape
obj.shape.clear
obj.shape.polygon = poly
end
end
end
ensure
view.commit
view.cancel
end
Thanks
K-
Hi ks,
the path to polygon conversion using the points is just half the truth. Emulating what the DXF reader does is far more complex - the issues are hole resolution, orientation normalization and such.
Here is a script which basically does what the DXF reader implements. The core is the EdgeProcessor which can convert edge sets back to polygons doing all the magic of hole insertion and so forth. Decomposition of the paths into edges is easy but the EdgeProcessor is picky, so we'll have to sort out the edges which do not form oriented loops. The core functionality used within the DXF reader is not directly available to Ruby yet, so I am providing a brute force implementation here. It does a piecewise elimination of dangling edges and corrects the edge direction n a second step if required. Please see the notes in the text:
Worth a thousand likes, isn't it :-)
Matthias