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/mixins.rb
ADDED
@@ -0,0 +1,378 @@
|
|
1
|
+
require 'gdsii/record/consts'
|
2
|
+
|
3
|
+
module Gdsii
|
4
|
+
|
5
|
+
#
|
6
|
+
# Various attribute accessor definitions which are used (included) by the
|
7
|
+
# high-level GDSII classes.
|
8
|
+
#
|
9
|
+
module Access
|
10
|
+
|
11
|
+
#
|
12
|
+
# Access layer attribute
|
13
|
+
#
|
14
|
+
module Layer
|
15
|
+
# Get the layer record (returns Record)
|
16
|
+
def layer_record() @records.get(GRT_LAYER); end
|
17
|
+
|
18
|
+
# Get the layer number (returns Fixnum)
|
19
|
+
def layer() @records.get_data(GRT_LAYER); end
|
20
|
+
|
21
|
+
# Set the layer number
|
22
|
+
def layer=(val) @records.set(GRT_LAYER, val); end
|
23
|
+
end
|
24
|
+
|
25
|
+
##########################################################################
|
26
|
+
|
27
|
+
#
|
28
|
+
# Access Datatype attribute
|
29
|
+
#
|
30
|
+
module Datatype
|
31
|
+
# Get the datatype record (returns Record)
|
32
|
+
def datatype_record() @records.get(GRT_DATATYPE); end
|
33
|
+
|
34
|
+
# Get the datatype number (returns Fixnum)
|
35
|
+
def datatype() @records.get_data(GRT_DATATYPE); end
|
36
|
+
|
37
|
+
# Set the datatype number
|
38
|
+
def datatype=(val) @records.set(GRT_DATATYPE, val); end
|
39
|
+
end
|
40
|
+
|
41
|
+
##########################################################################
|
42
|
+
|
43
|
+
#
|
44
|
+
# Access XY attribute
|
45
|
+
#
|
46
|
+
module XY
|
47
|
+
# Gets an xy point record (returns Record)
|
48
|
+
def xy_record() @records.get(GRT_XY); end
|
49
|
+
|
50
|
+
# Gets an xy point record (returns an Array)
|
51
|
+
def xy() @records.get_data(GRT_XY); end
|
52
|
+
|
53
|
+
# Sets an xy point record
|
54
|
+
def xy=(val) @records.set(GRT_XY, val); end
|
55
|
+
end
|
56
|
+
|
57
|
+
##########################################################################
|
58
|
+
|
59
|
+
#
|
60
|
+
# Access ELFlags attribute
|
61
|
+
#
|
62
|
+
module ELFlags
|
63
|
+
# Get the elflags record (returns Record)
|
64
|
+
def elflags_record() @records.get(GRT_ELFLAGS); end
|
65
|
+
|
66
|
+
# Get the elflags record data (returns Fixnum)
|
67
|
+
def elflags() @records.get_data(GRT_ELFLAGS); end
|
68
|
+
|
69
|
+
# Set the elflags record
|
70
|
+
def elflags=(val) @records.set(GRT_ELFLAGS,val); end
|
71
|
+
end
|
72
|
+
|
73
|
+
##########################################################################
|
74
|
+
|
75
|
+
#
|
76
|
+
# Access Plex attribute
|
77
|
+
#
|
78
|
+
module Plex
|
79
|
+
# Set the plex record (returns Record)
|
80
|
+
def plex_record() @records.get_data(GRT_PLEX); end
|
81
|
+
|
82
|
+
# Set the plex record data (returns Fixnum)
|
83
|
+
def plex() @records.get_data(GRT_PLEX); end
|
84
|
+
|
85
|
+
# Set the plex record
|
86
|
+
def plex=(val) @records.set(GRT_PLEX,val); end
|
87
|
+
end
|
88
|
+
|
89
|
+
##########################################################################
|
90
|
+
|
91
|
+
#
|
92
|
+
# Access PathType attribute
|
93
|
+
#
|
94
|
+
module PathType
|
95
|
+
#
|
96
|
+
# Get the path type record (returns Record).
|
97
|
+
#
|
98
|
+
def pathtype_record() @records.get(GRT_PATHTYPE); end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Get the path type number (returns Fixnum).
|
102
|
+
#
|
103
|
+
def pathtype() @records.get_data(GRT_PATHTYPE); end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Set the type number (as Fixnum). Valid range is 0-2,4 (not 3):
|
107
|
+
#
|
108
|
+
# * 0: Square ended paths (default)
|
109
|
+
# * 1: Round ended
|
110
|
+
# * 2: Square ended, extended 1/2 width
|
111
|
+
# * 4: Variable length extensions (see #bgnextn and #endextn)
|
112
|
+
#
|
113
|
+
def pathtype=(val)
|
114
|
+
record = @records.set(GRT_PATHTYPE, val)
|
115
|
+
data_val = record.data_value
|
116
|
+
if [0, 1, 2, 4].member?(data_val)
|
117
|
+
if data_val != 4
|
118
|
+
# Rip out begin/end extensions for pathtypes other than 4
|
119
|
+
@records.delete_key(GRT_BGNEXTN)
|
120
|
+
@records.delete_key(GRT_ENDEXTN)
|
121
|
+
end
|
122
|
+
else
|
123
|
+
# If path type is not 0, 1, 2, or 4, then fail
|
124
|
+
raise TypeError, "Path type #{data_val} is invalid; must be 0, 1, 2, or 4."
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
##########################################################################
|
130
|
+
|
131
|
+
#
|
132
|
+
# Access Width attribute
|
133
|
+
#
|
134
|
+
module Width
|
135
|
+
#
|
136
|
+
# Get the path width record (returns Record)
|
137
|
+
#
|
138
|
+
def width_record() @records.get(GRT_WIDTH); end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Get the path width value (returns Fixnum). The width value is multiplied
|
142
|
+
# with the UNITS value of the library to obtain the actual width.
|
143
|
+
#
|
144
|
+
def width() @records.get_data(GRT_WIDTH); end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Set the path width value (as Fixnum). The width value is multiplied
|
148
|
+
# with the UNITS value of the library and magnification factor to obtain
|
149
|
+
# the actual width. If the width value is negative, then the value is
|
150
|
+
# interpreted to be absolute and will not be affected by the database
|
151
|
+
# units or magnification factor.
|
152
|
+
#
|
153
|
+
def width=(val) @records.set(GRT_WIDTH, val); end
|
154
|
+
end
|
155
|
+
|
156
|
+
##########################################################################
|
157
|
+
|
158
|
+
#
|
159
|
+
# Access Strans record grouping
|
160
|
+
#
|
161
|
+
module StransGroup
|
162
|
+
#
|
163
|
+
# Access the Strans for this object (see Gdsii::Strans class
|
164
|
+
# documentation for a list of Strans methods).
|
165
|
+
#
|
166
|
+
def strans(); @records.get(Strans); end
|
167
|
+
|
168
|
+
#
|
169
|
+
# Set the Strans for this object
|
170
|
+
#
|
171
|
+
def strans=(val); @records.set(Strans, val); end
|
172
|
+
end
|
173
|
+
|
174
|
+
##########################################################################
|
175
|
+
|
176
|
+
#
|
177
|
+
# Access Sname attribute
|
178
|
+
#
|
179
|
+
module Sname
|
180
|
+
#
|
181
|
+
# Get the referenced structure SNAME record (returns Record).
|
182
|
+
#
|
183
|
+
def sname_record() @records.get(GRT_SNAME); end
|
184
|
+
|
185
|
+
#
|
186
|
+
# Get the referenced structure name (returns String).
|
187
|
+
#
|
188
|
+
def sname() @records.get_data(GRT_SNAME); end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Set the referenced structure name.
|
192
|
+
#
|
193
|
+
def sname=(val) @records.set(GRT_SNAME, val); end
|
194
|
+
end
|
195
|
+
|
196
|
+
##########################################################################
|
197
|
+
|
198
|
+
#
|
199
|
+
# Mix in methods that work with a predefined @list attribute. The list is
|
200
|
+
# made Enumerable and a number of methods are mixed in. Used in
|
201
|
+
# Properties, Structure, and Library.
|
202
|
+
#
|
203
|
+
module EnumerableGroup
|
204
|
+
|
205
|
+
include Enumerable
|
206
|
+
|
207
|
+
#
|
208
|
+
# Get the list object.
|
209
|
+
#
|
210
|
+
def list() @list; end
|
211
|
+
|
212
|
+
alias :to_a :list
|
213
|
+
|
214
|
+
#
|
215
|
+
# Loops through each object yielding along the way.
|
216
|
+
#
|
217
|
+
def each(); @list.each {|e| yield e}; end
|
218
|
+
|
219
|
+
#
|
220
|
+
# Add an object to this list as either an object instance or as
|
221
|
+
# the object data. Similar to Array#push but validates the data being
|
222
|
+
# added. The object added is returned.
|
223
|
+
#
|
224
|
+
def add(object)
|
225
|
+
self.validate_addition(object) if self.respond_to?(:validate_addition)
|
226
|
+
@list.push object
|
227
|
+
object
|
228
|
+
end
|
229
|
+
|
230
|
+
#
|
231
|
+
# Remove object(s) from this element when the propert(y/ies) match
|
232
|
+
# the given criteria (in the code block). Equivalent to Array#reject!.
|
233
|
+
#
|
234
|
+
def remove()
|
235
|
+
@list.reject! {|e| yield e}
|
236
|
+
end
|
237
|
+
|
238
|
+
#
|
239
|
+
# Implement a trap for a method that might be missing. Any method not
|
240
|
+
# listed here will default to the @list Array attribute if @list
|
241
|
+
# #respond_to? the method. This nifty feature allows us to "inherit"
|
242
|
+
# *all* methods related Array which will be operated upon the @list Array
|
243
|
+
# attribute.
|
244
|
+
#
|
245
|
+
def method_missing(method_sym, *args)
|
246
|
+
if @list.respond_to?(method_sym)
|
247
|
+
# The array @list responds to this method - use it on @list
|
248
|
+
@list.method(method_sym).call(*args)
|
249
|
+
else
|
250
|
+
# Raise the #method_missing error
|
251
|
+
super
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
##########################################################################
|
257
|
+
|
258
|
+
#
|
259
|
+
# Shared method related to working with the standard Time library within
|
260
|
+
# the Gdsii library.
|
261
|
+
#
|
262
|
+
module GdsiiTime
|
263
|
+
#
|
264
|
+
# Given a Time object, the time is formatted into an array of integers
|
265
|
+
# according to the GDSII specification.
|
266
|
+
#
|
267
|
+
def build_time(time)
|
268
|
+
[time.year-1900, time.month, time.day, time.hour, time.min, time.sec.to_i]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
############################################################################
|
275
|
+
|
276
|
+
#
|
277
|
+
# This module will be extended into all classes descended of Group (i.e.
|
278
|
+
# the high-level GDSII access classes). The extension brings a "read"
|
279
|
+
# class method (i.e. singleton) into these classes which enables a GDSII
|
280
|
+
# file to be read into these data structures using the BNF specification.
|
281
|
+
#
|
282
|
+
module Read
|
283
|
+
#
|
284
|
+
# Accepts a file handle and reads data from that file handle into an
|
285
|
+
# object descended of Group. The parent_records and parent_bnf_item
|
286
|
+
# arguments are for internal use only.
|
287
|
+
#
|
288
|
+
def read(file, parent_records=nil, parent_bnf_item=nil, yield_at=nil)
|
289
|
+
# Set BNF index at 0, get the BNF items, create an empty grouping object
|
290
|
+
i = 0
|
291
|
+
bnf_items = bnf_spec.bnf_items
|
292
|
+
group = self.new
|
293
|
+
# puts "#{self}"
|
294
|
+
|
295
|
+
# Loop through the BNF spec for this grouping...
|
296
|
+
while i < bnf_items.length do
|
297
|
+
bnf_item = bnf_items[i]
|
298
|
+
|
299
|
+
# see what kind of a BNF item this is - a Class or a record type (Fixnum)
|
300
|
+
if bnf_item.key.class == Class
|
301
|
+
# return if stop_at_class is set to true (used internally for
|
302
|
+
# Library#read_header and Cell#read_header).
|
303
|
+
yield group if yield_at == :before_group
|
304
|
+
|
305
|
+
# Determine the class to use
|
306
|
+
klass = bnf_item.key
|
307
|
+
|
308
|
+
# Read from the class
|
309
|
+
if bnf_item.multiple?
|
310
|
+
if (rec = klass.read(file, group.records, bnf_item))
|
311
|
+
# if a record was returned, then add it
|
312
|
+
group.records.add(bnf_item.key, rec)
|
313
|
+
else
|
314
|
+
# if nil was returned, then we're done with the record; next
|
315
|
+
i += 1
|
316
|
+
end
|
317
|
+
else
|
318
|
+
# If the record is singular, then get it from the class and
|
319
|
+
# increment the counter
|
320
|
+
rec = klass.read(file, group.records, bnf_item)
|
321
|
+
group.records.set(bnf_item.key, rec)
|
322
|
+
i += 1
|
323
|
+
end
|
324
|
+
else
|
325
|
+
# ELSE, a record type is expected (Fixnum)
|
326
|
+
rec = Record.read(file)
|
327
|
+
# puts " --> expect #{Gdsii::grt_name(bnf_item.key)}; rec == #{rec.name}"
|
328
|
+
if rec.type == bnf_item.key
|
329
|
+
# This record matches the grouping BNF item that was expected, so
|
330
|
+
# store the data
|
331
|
+
if bnf_item.multiple?
|
332
|
+
group.records.add(bnf_item.key, rec)
|
333
|
+
else
|
334
|
+
group.records.set(bnf_item.key, rec)
|
335
|
+
i += 1
|
336
|
+
end
|
337
|
+
else
|
338
|
+
# Record does not match expected record as per BNF. Check that we
|
339
|
+
# have data already set in this record or that the record is
|
340
|
+
# optional.
|
341
|
+
if group.records.has_data?(bnf_item.key) or bnf_item.optional?
|
342
|
+
# Already has data - just move to the next record and reset file
|
343
|
+
# pointer
|
344
|
+
i += 1
|
345
|
+
file.seek(-rec.byte_size, IO::SEEK_CUR)
|
346
|
+
elsif (parent_bnf_item and parent_bnf_item.key.class == Class and
|
347
|
+
(parent_records.has_data?(parent_bnf_item.key) or
|
348
|
+
parent_bnf_item.optional?))
|
349
|
+
# OK, in this case, we are descended into a Class and did not
|
350
|
+
# match the BNF expected. Furthermore, the parent calling this
|
351
|
+
# grouping either already got the data needed or this was an
|
352
|
+
# optional class in the first place. In either case, we're OK
|
353
|
+
# and just need to get out - which is what we do by returning
|
354
|
+
# nil.
|
355
|
+
file.seek(-rec.byte_size, IO::SEEK_CUR)
|
356
|
+
return nil
|
357
|
+
else
|
358
|
+
# Does not match the expected BNF... fail
|
359
|
+
raise "Unexpected record while reading GDSII file starting at file position #{file.pos-rec.byte_size}\n" +
|
360
|
+
"This record is in the wrong place according to the GDSII specification (from BNF)\n" +
|
361
|
+
"Expected record was #{Gdsii::grt_name(bnf_item.key)}; instead, received:\n" +
|
362
|
+
"Record type = #{Gdsii::grt_name(rec.type)}\n" +
|
363
|
+
"Data type = #{Gdsii::gdt_name(rec.data.type)}\n" +
|
364
|
+
"Record length = #{rec.byte_size}\n"
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# Return this record grouping
|
372
|
+
yield group if yield_at == :group
|
373
|
+
group
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
|
378
|
+
end
|
data/lib/gdsii/node.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'gdsii/group'
|
2
|
+
require 'gdsii/element'
|
3
|
+
|
4
|
+
module Gdsii
|
5
|
+
|
6
|
+
#
|
7
|
+
# Represents a GDSII Node element. Most methods are from Element or from
|
8
|
+
# the various included Access module methods.
|
9
|
+
#
|
10
|
+
class Node < 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
|
+
# Node BNF description:
|
20
|
+
#
|
21
|
+
# <node> ::= NODE [ELFLAGS] [PLEX] LAYER NODETYPE XY
|
22
|
+
#
|
23
|
+
self.bnf_spec = BnfSpec.new(
|
24
|
+
BnfItem.new(GRT_NODE),
|
25
|
+
BnfItem.new(GRT_ELFLAGS, true),
|
26
|
+
BnfItem.new(GRT_PLEX, true),
|
27
|
+
BnfItem.new(GRT_LAYER),
|
28
|
+
BnfItem.new(GRT_NODETYPE),
|
29
|
+
BnfItem.new(GRT_XY),
|
30
|
+
BnfItem.new(Properties, true),
|
31
|
+
BnfItem.new(GRT_ENDEL)
|
32
|
+
)
|
33
|
+
|
34
|
+
#
|
35
|
+
# Create a node record grouping given a layer, nodetype, and xy
|
36
|
+
# coordinates. The node object can have 1-50 coordinate pairs.
|
37
|
+
#
|
38
|
+
# node = Gdsii::Node.new(1, 0, [0,0])
|
39
|
+
#
|
40
|
+
def initialize(layer=nil, nodetype=nil, xy=nil)
|
41
|
+
super()
|
42
|
+
@records[GRT_NODE] = Record.new(GRT_NODE)
|
43
|
+
self.layer = layer unless layer.nil?
|
44
|
+
self.nodetype = nodetype unless nodetype.nil?
|
45
|
+
self.xy = xy unless xy.nil?
|
46
|
+
yield self if block_given?
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Get the nodetype record (returns Record).
|
51
|
+
#
|
52
|
+
def nodetype_record() @records.get(GRT_NODETYPE); end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Get the nodetype number (returns Fixnum).
|
56
|
+
#
|
57
|
+
def nodetype() @records.get_data(GRT_NODETYPE); end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Set the nodetype number.
|
61
|
+
#
|
62
|
+
def nodetype=(val) @records.set(GRT_NODETYPE, val); end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/gdsii/path.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'gdsii/element'
|
2
|
+
require 'gdsii/mixins'
|
3
|
+
|
4
|
+
module Gdsii
|
5
|
+
|
6
|
+
#
|
7
|
+
# Represents a GDSII Path element. Most methods are from Element or from
|
8
|
+
# the various included Access module methods.
|
9
|
+
#
|
10
|
+
class Path < Element
|
11
|
+
|
12
|
+
# Include various record accessors
|
13
|
+
include Access::Layer
|
14
|
+
include Access::Datatype
|
15
|
+
include Access::XY
|
16
|
+
include Access::PathType
|
17
|
+
include Access::Width
|
18
|
+
include Access::ELFlags
|
19
|
+
include Access::Plex
|
20
|
+
|
21
|
+
#
|
22
|
+
# Boundary BNF description:
|
23
|
+
#
|
24
|
+
# <path> ::= PATH [ELFLAGS] [PLEX] LAYER DATATYPE [PATHTYPE]
|
25
|
+
# [WIDTH] [BGNEXTN] [ENDEXTN] XY
|
26
|
+
#
|
27
|
+
self.bnf_spec = BnfSpec.new(
|
28
|
+
BnfItem.new(GRT_PATH),
|
29
|
+
BnfItem.new(GRT_ELFLAGS, true),
|
30
|
+
BnfItem.new(GRT_PLEX, true),
|
31
|
+
BnfItem.new(GRT_LAYER),
|
32
|
+
BnfItem.new(GRT_DATATYPE),
|
33
|
+
BnfItem.new(GRT_PATHTYPE, true),
|
34
|
+
BnfItem.new(GRT_WIDTH, true),
|
35
|
+
BnfItem.new(GRT_BGNEXTN, true),
|
36
|
+
BnfItem.new(GRT_ENDEXTN, true),
|
37
|
+
BnfItem.new(GRT_XY),
|
38
|
+
BnfItem.new(Properties,true),
|
39
|
+
BnfItem.new(GRT_ENDEL)
|
40
|
+
)
|
41
|
+
|
42
|
+
#
|
43
|
+
# Generic method to create a path given a layer, datatype, pathtype,
|
44
|
+
# width, and series of alternating x/y coordinates. The default pathtype
|
45
|
+
# is 0.
|
46
|
+
#
|
47
|
+
# path = Gdsii::Path.new(1, 0, 0, 100, [0,0, 1000,0, 1000,1000])
|
48
|
+
#
|
49
|
+
def initialize(layer=nil, datatype=nil, pathtype=nil, width=nil, xy=nil)
|
50
|
+
super()
|
51
|
+
@records[GRT_PATH] = Record.new(GRT_PATH)
|
52
|
+
self.layer = layer unless layer.nil?
|
53
|
+
self.datatype = datatype unless datatype.nil?
|
54
|
+
self.pathtype = (pathtype.nil?) ? 0 : pathtype
|
55
|
+
self.width = width unless width.nil?
|
56
|
+
self.xy = xy unless xy.nil?
|
57
|
+
|
58
|
+
# Set a code block to validate a path record
|
59
|
+
@validate = proc {
|
60
|
+
# Check for begin/end extensions for pathtype == 4
|
61
|
+
if self.pathtype == 4
|
62
|
+
unless self.bgnextn and self.endextn
|
63
|
+
raise "Begin/end extensions (#bgnextn= and #endextn=) required for path type 4"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
}
|
67
|
+
|
68
|
+
yield self if block_given?
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Creates a path of type 0
|
73
|
+
#
|
74
|
+
def Path.new0(layer=nil, datatype=nil, width=nil, xy=nil)
|
75
|
+
Path.new(layer, datatype, 0, width, xy) {|p| yield p if block_given?}
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Creates a path of type 1
|
80
|
+
#
|
81
|
+
def Path.new1(layer=nil, datatype=nil, width=nil, xy=nil)
|
82
|
+
Path.new(layer, datatype, 1, width, xy) {|p| yield p if block_given?}
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Creates a path of type 2
|
87
|
+
#
|
88
|
+
def Path.new2(layer=nil, datatype=nil, width=nil, xy=nil)
|
89
|
+
Path.new(layer, datatype, 2, width, xy) {|p| yield p if block_given?}
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Creates a path of type 4; accepts begin/end extension values
|
94
|
+
#
|
95
|
+
# path = Path.new4(1, 0, 100, 30, 30, [0,0, 1000,0, 1000,1000])
|
96
|
+
#
|
97
|
+
def Path.new4(layer=nil, datatype=nil, width=nil,
|
98
|
+
bgnextn=nil, endextn=nil, xy=nil)
|
99
|
+
Path.new(layer, datatype, 4, width, xy) do |path|
|
100
|
+
path.bgnextn = bgnextn
|
101
|
+
path.endextn = endextn
|
102
|
+
yield self if block_given?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Set the beginning extension for path type 4 (as Fixnum). Value is in
|
108
|
+
# database units.
|
109
|
+
#--
|
110
|
+
# TODO: more explanation of database units; also example
|
111
|
+
#++
|
112
|
+
#
|
113
|
+
def bgnextn=(val)
|
114
|
+
ensure_pathtype_4
|
115
|
+
@records.set(GRT_BGNEXTN, val)
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Get the beginning extension for path type 4 (as Fixnum). Value is in
|
120
|
+
# database units.
|
121
|
+
#
|
122
|
+
def bgnextn(); @records.get_data(GRT_BGNEXTN); end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Get the beginning extension record for path type 4 (as Fixnum). Value is
|
126
|
+
# in database units.
|
127
|
+
#
|
128
|
+
def bgnextn_record(); @records.get(GRT_BGNEXTN); end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Set the ending extension for path type 4 (as Fixnum). Value is in
|
132
|
+
# database units.
|
133
|
+
#--
|
134
|
+
# TODO: more explanation of database units; also example
|
135
|
+
#++
|
136
|
+
#
|
137
|
+
def endextn=(val)
|
138
|
+
ensure_pathtype_4
|
139
|
+
@records.set(GRT_ENDEXTN, val)
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Get the ending extension for path type 4 (as Fixnum). Value is in
|
144
|
+
# database units.
|
145
|
+
#
|
146
|
+
def endextn(); @records.get_data(GRT_ENDEXTN); end
|
147
|
+
|
148
|
+
#
|
149
|
+
# Get the ending extension record for path type 4 (as Fixnum). Value is
|
150
|
+
# in database units.
|
151
|
+
#
|
152
|
+
def endextn_record(); @records.get(GRT_ENDEXTN); end
|
153
|
+
|
154
|
+
###########################################################################
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
#
|
159
|
+
# Ensures that pathtype == 4. This needs to be verified for a few of the
|
160
|
+
# methods only relevant for pathtype == 4 (see #bgnextn and #endextn).
|
161
|
+
#
|
162
|
+
def ensure_pathtype_4()
|
163
|
+
if pathtype != 4
|
164
|
+
raise TypeError, "Attempt to access a method only relevant to pathtype == 4"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|