jfreeze-ruby-gdsii 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|