jfreeze-ruby-gdsii 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +6 -0
- data/LICENSE.txt +20 -0
- data/README.txt +113 -0
- data/Rakefile +30 -0
- data/bin/rgds-debug +43 -0
- data/bin/rgds-dump +38 -0
- data/bin/rgds-join +98 -0
- data/bin/rgds-layers +53 -0
- data/bin/rgds-sremove +136 -0
- data/bin/rgds-ssplit +113 -0
- data/bin/rgds-stats +134 -0
- data/bin/rgds-structs +41 -0
- data/bin/rgds-tree +167 -0
- data/bin/rgds2rb +99 -0
- data/lib/gdsii.rb +137 -0
- data/lib/gdsii/aref.rb +243 -0
- data/lib/gdsii/bnf.rb +309 -0
- data/lib/gdsii/boundary.rb +53 -0
- data/lib/gdsii/box.rb +65 -0
- data/lib/gdsii/byte_order.rb +36 -0
- data/lib/gdsii/element.rb +172 -0
- data/lib/gdsii/group.rb +98 -0
- data/lib/gdsii/library.rb +518 -0
- data/lib/gdsii/mixins.rb +378 -0
- data/lib/gdsii/node.rb +65 -0
- data/lib/gdsii/path.rb +169 -0
- data/lib/gdsii/property.rb +108 -0
- data/lib/gdsii/record.rb +606 -0
- data/lib/gdsii/record/consts.rb +384 -0
- data/lib/gdsii/record/datatypes/ascii.rb +145 -0
- data/lib/gdsii/record/datatypes/bitarray.rb +101 -0
- data/lib/gdsii/record/datatypes/data.rb +111 -0
- data/lib/gdsii/record/datatypes/int2.rb +67 -0
- data/lib/gdsii/record/datatypes/int4.rb +65 -0
- data/lib/gdsii/record/datatypes/nodata.rb +60 -0
- data/lib/gdsii/record/datatypes/real4.rb +51 -0
- data/lib/gdsii/record/datatypes/real8.rb +120 -0
- data/lib/gdsii/sref.rb +61 -0
- data/lib/gdsii/strans.rb +133 -0
- data/lib/gdsii/structure.rb +352 -0
- data/lib/gdsii/text.rb +203 -0
- data/pkg/ruby-gdsii.gem +46 -0
- data/samples/hello.gds +0 -0
- data/samples/hello.out.rb +84 -0
- data/samples/hello.rb +94 -0
- data/test/baseline/dcp1.gds +0 -0
- data/test/baseline/h_write.gds +0 -0
- data/test/h_pthru.rb +22 -0
- data/test/h_write.rb +117 -0
- data/test/hs_pthru.rb +31 -0
- data/test/l_pthru.rb +23 -0
- data/test/test_gds_group.rb +379 -0
- data/test/test_gds_record.rb +99 -0
- metadata +117 -0
data/lib/gdsii/bnf.rb
ADDED
@@ -0,0 +1,309 @@
|
|
1
|
+
require 'gdsii/record/consts'
|
2
|
+
|
3
|
+
module Gdsii
|
4
|
+
|
5
|
+
#
|
6
|
+
# Class to hold BNF items which are to be listed in the BnfSpec class. The
|
7
|
+
# BnfItem objects are used to indicate the unique BNF key and also whether
|
8
|
+
# or not it is optional and whether or not it is multiple.
|
9
|
+
#
|
10
|
+
class BnfItem
|
11
|
+
|
12
|
+
attr_reader :key, :optional, :multiple
|
13
|
+
|
14
|
+
#
|
15
|
+
# Create a new BNF item of a given key and specify if it is optional
|
16
|
+
# and if there are multiple values. The key is either one of the
|
17
|
+
# Gdsii::GRT_* constants or is a class descended from Gdsii::Group.
|
18
|
+
# Examples:
|
19
|
+
#
|
20
|
+
# BnfItem.new(Property,true,true),
|
21
|
+
# BnfItem.new(GRT_ENDEL)
|
22
|
+
#
|
23
|
+
def initialize(key, optional=false, multiple=false)
|
24
|
+
@key = key
|
25
|
+
@optional = optional
|
26
|
+
@multiple = multiple
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# True if this BNF item is optional; false if not (opposite of #required?)
|
31
|
+
#
|
32
|
+
def optional?() @optional; end
|
33
|
+
|
34
|
+
#
|
35
|
+
# True if this BNF item has multiple values; false if not
|
36
|
+
#
|
37
|
+
def multiple?() @multiple; end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Dump the name for this BNF item
|
41
|
+
#
|
42
|
+
def to_s(); Gdsii::grt_name(@key); end
|
43
|
+
|
44
|
+
#
|
45
|
+
# (hide from RDoc) - Add details to inspect
|
46
|
+
#
|
47
|
+
def inspect() # :nodoc:
|
48
|
+
"#<#{self.class}:0x#{sprintf("%x", self.object_id*2)} == #{self.to_s}>"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
############################################################################
|
54
|
+
|
55
|
+
#
|
56
|
+
# This class represents the order of a GDSII record grouping using a specific
|
57
|
+
# record order in Backus-Naur Form (BNF). It consists of a number of BnfItem
|
58
|
+
# objects where the order of the items is important in determining the order
|
59
|
+
# in which the GDSII file format should be read or written from/to a file.
|
60
|
+
#
|
61
|
+
class BnfSpec
|
62
|
+
|
63
|
+
include Enumerable
|
64
|
+
|
65
|
+
attr_reader :bnf_items
|
66
|
+
|
67
|
+
#
|
68
|
+
# Creates a Backus-Naur Form (BNF) grouping consisting of BnfItem objects.
|
69
|
+
#
|
70
|
+
# spec = BnfSpec.new(
|
71
|
+
# BnfItem.new(GRT_PROPATTR),
|
72
|
+
# BnfItem.new(GRT_PROPVALUE)
|
73
|
+
# )
|
74
|
+
#
|
75
|
+
def initialize(*bnf_items)
|
76
|
+
@bnf_items = bnf_items
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Loops through each BnfItem in this BnfSpec yielding the BnfItem along
|
81
|
+
# the way.
|
82
|
+
#
|
83
|
+
# spec.each {|bnf_item| ...}
|
84
|
+
#
|
85
|
+
def each()
|
86
|
+
@bnf_items.each {|bnf_item| yield bnf_item}
|
87
|
+
end
|
88
|
+
alias :each_item :each
|
89
|
+
|
90
|
+
#
|
91
|
+
# Finds a BnfItem of a given key in this Bnf object or nil if one is not
|
92
|
+
# found.
|
93
|
+
#
|
94
|
+
# spec = ...
|
95
|
+
# spec.find_item(GRT_PROPATTR) #=> BnfItem ...
|
96
|
+
# spec.find_item(GRT_HEADER) #=> nil
|
97
|
+
#
|
98
|
+
def find_item(key)
|
99
|
+
@bnf_items.find {|bnf_item| bnf_item.key == key}
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Shortcut for #find_item but will raise an exception if the item key
|
104
|
+
# is not part of this BNF.
|
105
|
+
#
|
106
|
+
# spec = ...
|
107
|
+
# spec.find_item(GRT_PROPATTR) #=> BnfItem ...
|
108
|
+
# spec.find_item(GRT_HEADER) #=> raise IndexError ...
|
109
|
+
#
|
110
|
+
def [](key)
|
111
|
+
if (found = find_item(key))
|
112
|
+
found
|
113
|
+
else
|
114
|
+
raise IndexError, "Cannot find BnfItem of key #{Gdsii::grt_name(key)} in BNF"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Format for inspection
|
120
|
+
#
|
121
|
+
def inspect() # :nodoc:
|
122
|
+
"#<#{self.class}:0x#{sprintf("%x", self.object_id*2)}:@bnf_items.map {|i| i.to_s}.inspect>"
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
############################################################################
|
128
|
+
|
129
|
+
#
|
130
|
+
# Used to store records for a record grouping (i.e. classes descending
|
131
|
+
# from Group). Only records that are in the BnfSpec may be added.
|
132
|
+
#
|
133
|
+
class BnfRecords
|
134
|
+
|
135
|
+
#
|
136
|
+
# Create a new BnfRecords object. The parent class is stored so that
|
137
|
+
# entries may be compared against the BnfSpec.
|
138
|
+
#
|
139
|
+
def initialize(parent_class)
|
140
|
+
@parent_class = parent_class
|
141
|
+
@bnf_records = {}
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Returns the BnfSpec of the parent class.
|
146
|
+
#
|
147
|
+
def bnf_spec()
|
148
|
+
@parent_class.bnf_spec
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
# Returns the BNF record keys that exist in this grouping of BNF records.
|
153
|
+
#
|
154
|
+
def bnf_keys()
|
155
|
+
@bnf_records.keys
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Retrieves the Record for a given BNF item key. If the record is
|
160
|
+
# multiple according to the BNF description, then an array of
|
161
|
+
# Record objects is returned. Used internally by various grouping accessor
|
162
|
+
# methods.
|
163
|
+
#
|
164
|
+
def get(key)
|
165
|
+
bnf_item = bnf_spec[key]
|
166
|
+
if bnf_item.multiple?
|
167
|
+
@bnf_records[key] = [] unless @bnf_records.has_key? key
|
168
|
+
@bnf_records[key]
|
169
|
+
else
|
170
|
+
if key.class == Class and @bnf_records[key].nil?
|
171
|
+
@bnf_records[key] = key.new
|
172
|
+
end
|
173
|
+
@bnf_records[key]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
alias :[] :get
|
178
|
+
|
179
|
+
#
|
180
|
+
# Retrieves the Record *data* (i.e value) for a given BNF item key. If
|
181
|
+
# the record is multiple according to the BNF description, then an array
|
182
|
+
# of Record data is returned. Used internally by various grouping accessor
|
183
|
+
# methods.
|
184
|
+
#
|
185
|
+
def get_data(key)
|
186
|
+
if bnf_spec[key].multiple?
|
187
|
+
get(key).map {|record| record.data_value}
|
188
|
+
else
|
189
|
+
((record = get(key)).nil?) ? nil : record.data_value
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Sets the record data for a given BNF item key. The value may be the
|
195
|
+
# of the class to be added or can be a raw value which is automatically
|
196
|
+
# coerced into the proper class for the given key. Used internally by
|
197
|
+
# various grouping accessor methods. Returns the object being set.
|
198
|
+
#
|
199
|
+
def set(key, value)
|
200
|
+
if key.class == Class
|
201
|
+
@bnf_records[key] = value
|
202
|
+
elsif value.nil?
|
203
|
+
@bnf_records[key] = value
|
204
|
+
else
|
205
|
+
value = coerce_record_value(key, value)
|
206
|
+
value = [value] if bnf_spec[key].multiple? and value.class != Array
|
207
|
+
@bnf_records[key] = value
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
alias :[]= :set
|
212
|
+
|
213
|
+
#
|
214
|
+
# Adds the record or record value to the bnf_records hash (applicable only
|
215
|
+
# for records with multiple entries). Returns the updated list of values.
|
216
|
+
# Used internally by various grouping accessor methods. Returns the object
|
217
|
+
# being set.
|
218
|
+
#
|
219
|
+
def add(key, value)
|
220
|
+
if bnf_spec[key].multiple?
|
221
|
+
value = coerce_record_value(key, value)
|
222
|
+
get(key).push value
|
223
|
+
else
|
224
|
+
raise TypeError, "BNF for key #{key} is singular in class #{parent_class}; use #set instead"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
#
|
229
|
+
# Accepts a code block which should return true or false. If the return
|
230
|
+
# value is true, then the value meeting the criteria is removed. This
|
231
|
+
# is used internally by various grouping accessor methods. Note, this is
|
232
|
+
# only applicable for records with multiple values.
|
233
|
+
#
|
234
|
+
# object.reject!(Property) {|property|
|
235
|
+
# property.attr == 1
|
236
|
+
# }
|
237
|
+
#
|
238
|
+
def reject!(key)
|
239
|
+
if bnf_spec[key].multiple?
|
240
|
+
@bnf_records[key].reject! {|value| yield value}
|
241
|
+
else
|
242
|
+
raise TypeError, "BNF for key #{key} is singular in class #{parent_class}; use #set to nil"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
#
|
247
|
+
# Deletes the given key from the bnf_records hash.
|
248
|
+
#
|
249
|
+
def delete_key(key)
|
250
|
+
@bnf_records.delete(key)
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
# True if the record item is not nil (if the BnfItem is singular) or an
|
255
|
+
# empty array (if the BnfItem is multiple).
|
256
|
+
#
|
257
|
+
def has_data?(key)
|
258
|
+
bnf_item = bnf_spec[key]
|
259
|
+
if (bnf_item.multiple? and get(key).empty?) or
|
260
|
+
(not bnf_item.multiple? and get(key).nil?)
|
261
|
+
false
|
262
|
+
else
|
263
|
+
true
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
#
|
268
|
+
# Write the BNF records to file. Ensures that the required records exist
|
269
|
+
# according to the BnfSpec (otherwise an error is raised). A file object
|
270
|
+
# is expected.
|
271
|
+
#
|
272
|
+
def write(file, alt_bnf=nil)
|
273
|
+
# Loop through each BNF item
|
274
|
+
bnf = alt_bnf ? alt_bnf : bnf_spec
|
275
|
+
bnf.each_item do |bnf_item|
|
276
|
+
if has_data?(bnf_item.key)
|
277
|
+
if bnf_item.multiple?
|
278
|
+
get(bnf_item.key).each {|record| record.write(file)}
|
279
|
+
else
|
280
|
+
get(bnf_item.key).write(file)
|
281
|
+
end
|
282
|
+
elsif not bnf_item.optional?
|
283
|
+
raise "Required data in BNF are not set: #{bnf_item}"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
##########################################################################
|
289
|
+
# PRIVATE METHODS
|
290
|
+
##########################################################################
|
291
|
+
|
292
|
+
private
|
293
|
+
|
294
|
+
#
|
295
|
+
# Used by #add and #set to convert a raw value into the proper class
|
296
|
+
# given the key (if needed). This method is not used outside of this
|
297
|
+
# class.
|
298
|
+
#
|
299
|
+
def coerce_record_value(key, value)
|
300
|
+
if value.kind_of?(Record) or value.kind_of?(Group)
|
301
|
+
value
|
302
|
+
else
|
303
|
+
Record.new(key, value)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'gdsii/element'
|
2
|
+
require 'gdsii/mixins'
|
3
|
+
|
4
|
+
module Gdsii
|
5
|
+
|
6
|
+
#
|
7
|
+
# Represents a GDSII Boundary element (i.e. a rectangle or polygon). Most
|
8
|
+
# methods are from Element or from the various included Access module
|
9
|
+
# methods.
|
10
|
+
#
|
11
|
+
class Boundary < Element
|
12
|
+
|
13
|
+
# Include various record accessors
|
14
|
+
include Access::Layer
|
15
|
+
include Access::Datatype
|
16
|
+
include Access::XY
|
17
|
+
include Access::ELFlags
|
18
|
+
include Access::Plex
|
19
|
+
|
20
|
+
#
|
21
|
+
# Boundary BNF description:
|
22
|
+
#
|
23
|
+
# <boundary> ::= BOUNDARY [ELFLAGS] [PLEX] LAYER DATATYPE XY
|
24
|
+
#
|
25
|
+
self.bnf_spec = BnfSpec.new(
|
26
|
+
BnfItem.new(GRT_BOUNDARY),
|
27
|
+
BnfItem.new(GRT_ELFLAGS, true),
|
28
|
+
BnfItem.new(GRT_PLEX, true),
|
29
|
+
BnfItem.new(GRT_LAYER),
|
30
|
+
BnfItem.new(GRT_DATATYPE),
|
31
|
+
BnfItem.new(GRT_XY),
|
32
|
+
BnfItem.new(Properties,true),
|
33
|
+
BnfItem.new(GRT_ENDEL)
|
34
|
+
)
|
35
|
+
|
36
|
+
#
|
37
|
+
# Boundary object constructor. Layer and datatype are given as Fixnum
|
38
|
+
# and the coordinate points are given as an array of Fixnum alternating
|
39
|
+
# x and y values (coordinate pair range is 4-200). Example:
|
40
|
+
#
|
41
|
+
# rectangle = Gdsii::Boundary.new(1, 0, [0,0, 0,10, 10,10, 10,0, 0,0])
|
42
|
+
#
|
43
|
+
def initialize(layer=nil, datatype=nil, xy=nil)
|
44
|
+
super()
|
45
|
+
@records[GRT_BOUNDARY] = Record.new(GRT_BOUNDARY)
|
46
|
+
self.layer = layer unless layer.nil?
|
47
|
+
self.datatype = datatype unless datatype.nil?
|
48
|
+
self.xy = xy unless xy.nil?
|
49
|
+
yield self if block_given?
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/lib/gdsii/box.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'gdsii/group'
|
2
|
+
require 'gdsii/element'
|
3
|
+
|
4
|
+
module Gdsii
|
5
|
+
|
6
|
+
#
|
7
|
+
# Represents a GDSII box element. Most methods are from Element or from the
|
8
|
+
# various included Access module methods.
|
9
|
+
#
|
10
|
+
class Box < Element
|
11
|
+
|
12
|
+
# Include various record accessors
|
13
|
+
include Access::Layer
|
14
|
+
include Access::XY
|
15
|
+
include Access::ELFlags
|
16
|
+
include Access::Plex
|
17
|
+
|
18
|
+
#
|
19
|
+
# Box BNF description:
|
20
|
+
#
|
21
|
+
# <box> ::= BOX [ELFLAGS] [PLEX] LAYER BOXTYPE XY
|
22
|
+
#
|
23
|
+
self.bnf_spec = BnfSpec.new(
|
24
|
+
BnfItem.new(GRT_BOX),
|
25
|
+
BnfItem.new(GRT_ELFLAGS, true),
|
26
|
+
BnfItem.new(GRT_PLEX, true),
|
27
|
+
BnfItem.new(GRT_LAYER),
|
28
|
+
BnfItem.new(GRT_BOXTYPE),
|
29
|
+
BnfItem.new(GRT_XY),
|
30
|
+
BnfItem.new(Properties, true),
|
31
|
+
BnfItem.new(GRT_ENDEL)
|
32
|
+
)
|
33
|
+
|
34
|
+
#
|
35
|
+
# Create a box record grouping given a layer, boxtype, and xy coordinates.
|
36
|
+
# The box object is to have exactly 5 coordinate pairs.
|
37
|
+
#
|
38
|
+
# box = Gdsii::Box.new(1, 0, [0,0, 0,10, 10,10, 10,0, 0,0])
|
39
|
+
#
|
40
|
+
def initialize(layer=nil, boxtype=nil, xy=nil)
|
41
|
+
super()
|
42
|
+
@records[GRT_BOX] = Record.new(GRT_BOX)
|
43
|
+
self.layer = layer unless layer.nil?
|
44
|
+
self.boxtype = boxtype unless boxtype.nil?
|
45
|
+
self.xy = xy unless xy.nil?
|
46
|
+
yield self if block_given?
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Get the boxtype record (returns Record).
|
51
|
+
#
|
52
|
+
def boxtype_record() @records.get(GRT_BOXTYPE); end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Get the boxtype number (returns Fixnum).
|
56
|
+
#
|
57
|
+
def boxtype() @records.get_data(GRT_BOXTYPE); end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Set the boxtype number.
|
61
|
+
#
|
62
|
+
def boxtype=(val) @records.set(GRT_BOXTYPE, val); end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# ByteOrder is lifted from ruby-talk 107439, cited by Michael Neumann
|
3
|
+
#
|
4
|
+
module ByteOrder
|
5
|
+
|
6
|
+
Native = :Native
|
7
|
+
Big = BigEndian = Network = :BigEndian
|
8
|
+
Little = LittleEndian = :LittleEndian
|
9
|
+
|
10
|
+
# examines the locale byte order on the running machine
|
11
|
+
def byte_order
|
12
|
+
if [0x12345678].pack("L") == "\x12\x34\x56\x78"
|
13
|
+
BigEndian
|
14
|
+
else
|
15
|
+
LittleEndian
|
16
|
+
end
|
17
|
+
end
|
18
|
+
alias byteorder byte_order
|
19
|
+
module_function :byte_order, :byteorder
|
20
|
+
|
21
|
+
def little_endian?
|
22
|
+
byte_order == LittleEndian
|
23
|
+
end
|
24
|
+
|
25
|
+
def big_endian?
|
26
|
+
byte_order == BigEndian
|
27
|
+
end
|
28
|
+
|
29
|
+
alias little? little_endian?
|
30
|
+
alias big? big_endian?
|
31
|
+
alias network? big_endian?
|
32
|
+
|
33
|
+
module_function :little_endian?, :little?
|
34
|
+
module_function :big_endian?, :big?, :network?
|
35
|
+
|
36
|
+
end
|