ruby-gdsii 1.0.0
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/LICENSE.txt +20 -0
- data/README.txt +113 -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 +135 -0
- data/bin/rgds-ssplit +113 -0
- data/bin/rgds-stats +134 -0
- data/bin/rgds-structs +41 -0
- data/bin/rgds-tree +166 -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 +23 -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 +118 -0
data/bin/rgds2rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
##############################################################################
|
3
|
+
#
|
4
|
+
# == gds2rb.rb
|
5
|
+
#
|
6
|
+
# Reads a GDSII file and then generates the corresponding Ruby code necessary
|
7
|
+
# to recreate the GDSII.
|
8
|
+
#
|
9
|
+
# === Author
|
10
|
+
#
|
11
|
+
# James D. Masters (james.d.masters@gmail.com)
|
12
|
+
#
|
13
|
+
# === History
|
14
|
+
#
|
15
|
+
# * 03/26/2007 (jdm): Initial version
|
16
|
+
#
|
17
|
+
##############################################################################
|
18
|
+
|
19
|
+
require 'getoptlong'
|
20
|
+
require 'gdsii/record.rb'
|
21
|
+
include Gdsii
|
22
|
+
|
23
|
+
usage = "
|
24
|
+
Reads a GDSII file and then generates the corresponding Ruby code necessary
|
25
|
+
to recreate the GDSII.
|
26
|
+
|
27
|
+
Usage: gds2rb.rb [options] <gds-file> <rb-file> <gds-out-file>
|
28
|
+
|
29
|
+
Options:
|
30
|
+
|
31
|
+
-s, --structs Specify structure(s) in a space separated list to process.
|
32
|
+
The default behavior is to process all structures.
|
33
|
+
-f, --force Force existing Ruby file if it exists.
|
34
|
+
-h, --help Displays this usage message.
|
35
|
+
|
36
|
+
"
|
37
|
+
|
38
|
+
# Get command-line arguments
|
39
|
+
structs = []
|
40
|
+
force = false
|
41
|
+
|
42
|
+
opts = GetoptLong.new(
|
43
|
+
['--structs', '-s', GetoptLong::OPTIONAL_ARGUMENT],
|
44
|
+
['--force', '-f', GetoptLong::OPTIONAL_ARGUMENT|GetoptLong::NO_ARGUMENT],
|
45
|
+
['--help', '-h', GetoptLong::OPTIONAL_ARGUMENT|GetoptLong::NO_ARGUMENT]
|
46
|
+
)
|
47
|
+
|
48
|
+
opts.each do |option, argument|
|
49
|
+
case option
|
50
|
+
when '--help' : abort usage
|
51
|
+
when '--structs' : structs = argument.split(/\s+/)
|
52
|
+
when '--force' : force = true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get GDSII file directory from command line
|
57
|
+
gds_file, rb_file, gds_out_file = ARGV
|
58
|
+
unless (gds_file and rb_file and gds_out_file)
|
59
|
+
abort usage
|
60
|
+
end
|
61
|
+
|
62
|
+
# Fail if the Ruby file exists and force isn't enabled
|
63
|
+
if File.exists? rb_file and not force
|
64
|
+
abort "\nRuby file exists: #{rb_file} (use -f or --force to ignore)"
|
65
|
+
end
|
66
|
+
|
67
|
+
space_before = [GRT_BOUNDARY, GRT_PATH, GRT_TEXT, GRT_NODE,
|
68
|
+
GRT_BOX, GRT_ENDSTR, GRT_ENDLIB]
|
69
|
+
|
70
|
+
# Open Ruby file for write
|
71
|
+
File.open(rb_file, 'w') do |rbf|
|
72
|
+
# Write the header information
|
73
|
+
rbf.puts "require 'gdsii'"
|
74
|
+
rbf.puts
|
75
|
+
rbf.puts "File.open('#{gds_out_file}', 'wb') do |outf|"
|
76
|
+
rbf.puts
|
77
|
+
|
78
|
+
# Read the GDSII file and write out resulting GDSII files
|
79
|
+
File.open(gds_file, 'rb') do |inf|
|
80
|
+
# Read each record in the GDSII file
|
81
|
+
Record.read_each(inf) do |record|
|
82
|
+
rbf.puts if space_before.member?(record.type)
|
83
|
+
if record.type == GRT_BGNSTR
|
84
|
+
strname = Record.peek(inf).data_value
|
85
|
+
rbf.puts
|
86
|
+
rbf.puts ' ' + '#' * 76
|
87
|
+
rbf.puts ' # STRUCTURE: ' + strname.to_s
|
88
|
+
rbf.puts ' ' + '#' * 76
|
89
|
+
rbf.puts
|
90
|
+
end
|
91
|
+
rbf.puts " Gdsii::Record.new(Gdsii::GRT_#{record.name}, #{record.data_value.inspect}).write(outf)"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
rbf.puts
|
96
|
+
rbf.puts "end"
|
97
|
+
end
|
98
|
+
|
99
|
+
|
data/lib/gdsii.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
#
|
2
|
+
# There are two approaches to interacting with a GDSII file using this module:
|
3
|
+
#
|
4
|
+
# 1. At the record level (low-level)
|
5
|
+
# 2. At the record group level (high-level)
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# = Approach #1
|
9
|
+
#
|
10
|
+
# (See Record class for details)
|
11
|
+
#
|
12
|
+
# Interaction at the record level is intended for streamlined file processing
|
13
|
+
# where the author has a good knowledge of the GDSII structure. A typical
|
14
|
+
# usage might be to streamline changes to a GDSII file such as changing
|
15
|
+
# bus bit characters on a node name from <> to [] format (see the samples
|
16
|
+
# directory of this library installation for an example). Here is a simple
|
17
|
+
# way to dump the all strings in a GDSII file using the Record class:
|
18
|
+
#
|
19
|
+
# require 'gdsii'
|
20
|
+
#
|
21
|
+
# # Note: 'rb' is required for DOS/Windows compatibility
|
22
|
+
# File.open('mydesign.gds', 'rb') do |file|
|
23
|
+
# Gds::Record.read_each(file) do |record|
|
24
|
+
# puts record.data[0] if record.is_string?
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# = Approach #2
|
30
|
+
#
|
31
|
+
# (See Group, Library, Structure, Element, Boundary, Path, Text, SRef, ARef,
|
32
|
+
# Node, and Box classes for details)
|
33
|
+
#
|
34
|
+
# The second approach offers a high-level interface to the GDSII format which
|
35
|
+
# might be ideal in cases where the author may not be familiar with the details
|
36
|
+
# of the GDSII format. This example will write a small transistor cell:
|
37
|
+
#
|
38
|
+
# require 'gdsii'
|
39
|
+
#
|
40
|
+
# Gdsii::Library.new('MYLIB.DB') do |lib|
|
41
|
+
#
|
42
|
+
# Gdsii::Structure.new('trans') do |struct|
|
43
|
+
#
|
44
|
+
# # Diffusion layer
|
45
|
+
# struct.add Gdsii::Boundary.new(1, 0, [-2000,0, -2000,4000, 2000,4000, 2000,0, -2000,0])
|
46
|
+
#
|
47
|
+
# # Gate layer... add a property labling as "gate"
|
48
|
+
# Gdsii::Path.new(2, 0, 0, 800, [0,-600, 0,4600]) do |path|
|
49
|
+
# path.add Gdsii::Property.new(1, 'gate')
|
50
|
+
# struct.add path
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# # Add this structure to the library
|
54
|
+
# lib.add struct
|
55
|
+
#
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# # Write the library to a file
|
59
|
+
# lib.write('trans.gds')
|
60
|
+
#
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
#
|
64
|
+
# = Important notes
|
65
|
+
#
|
66
|
+
# == Look at inherited and mixed-in methods
|
67
|
+
#
|
68
|
+
# The high-level classes in this GDSII library rely heavily upon inheritance
|
69
|
+
# and mixed-in modules to reduce code. When reviewing documentation, be sure
|
70
|
+
# to be aware of methods defined implicitly through class inheritance and
|
71
|
+
# through Module#include and Module#extend.
|
72
|
+
#
|
73
|
+
# == Use 'b' during R/W of files
|
74
|
+
#
|
75
|
+
# Be sure to always use the 'b' read/write attribute when reading and writing
|
76
|
+
# GDSII files to ensure that read/write happens properly on DOS/Windows
|
77
|
+
# systems. For example (see IO#open for more details):
|
78
|
+
#
|
79
|
+
# inf = File.open('mydesign.gds', 'rb')
|
80
|
+
# outf = File.open('mydesign.gds', 'wb')
|
81
|
+
#
|
82
|
+
# == Improving performance
|
83
|
+
#
|
84
|
+
# The low-level GDSII methods will offer significantly better GDSII read/write
|
85
|
+
# performance as compared to the high-level methods. For most streamlined
|
86
|
+
# manipulations of GDSII files, the low-level methods are probably the best
|
87
|
+
# option. For smaller GDSII files or when code re-use/readability is
|
88
|
+
# important, then the performance hit with the high-level methods may not be
|
89
|
+
# a concern.
|
90
|
+
#
|
91
|
+
# Here are some benchmarks using both low and high level methods to read and
|
92
|
+
# immediately write a GDSII file:
|
93
|
+
#
|
94
|
+
# * GDSII file size: 7 MB
|
95
|
+
# * WinXP machine: Intel(R) Pentium(R) M (Centrino) 1.6 Ghz @ 1 GB RAM
|
96
|
+
# * Linux machine (SuSE): 2x Intel(R) Pentium(R) 4 3.4 Ghz @ 1 GB RAM
|
97
|
+
#
|
98
|
+
# Linux WinXP
|
99
|
+
# ------- -------
|
100
|
+
# High-level methods: 8m 45s 11m 23s
|
101
|
+
# Low-level methods: 0m 45s 1m 29s
|
102
|
+
#
|
103
|
+
module Gdsii
|
104
|
+
# Empty module here as a placeholder for rdoc
|
105
|
+
end
|
106
|
+
|
107
|
+
# Require byte order, constants, and mixins
|
108
|
+
require 'gdsii/byte_order.rb'
|
109
|
+
require 'gdsii/record/consts.rb'
|
110
|
+
require 'gdsii/mixins.rb'
|
111
|
+
|
112
|
+
# Require low-level files (data types and records)
|
113
|
+
require 'gdsii/record/datatypes/bitarray.rb'
|
114
|
+
require 'gdsii/record/datatypes/int4.rb'
|
115
|
+
require 'gdsii/record/datatypes/nodata.rb'
|
116
|
+
require 'gdsii/record/datatypes/real4.rb'
|
117
|
+
require 'gdsii/record/datatypes/ascii.rb'
|
118
|
+
require 'gdsii/record/datatypes/data.rb'
|
119
|
+
require 'gdsii/record/datatypes/real8.rb'
|
120
|
+
require 'gdsii/record/datatypes/int2.rb'
|
121
|
+
require 'gdsii/record.rb'
|
122
|
+
|
123
|
+
# Require high-level files
|
124
|
+
require 'gdsii/bnf.rb'
|
125
|
+
require 'gdsii/group.rb'
|
126
|
+
require 'gdsii/element.rb'
|
127
|
+
require 'gdsii/property.rb'
|
128
|
+
require 'gdsii/strans.rb'
|
129
|
+
require 'gdsii/boundary.rb'
|
130
|
+
require 'gdsii/path.rb'
|
131
|
+
require 'gdsii/text.rb'
|
132
|
+
require 'gdsii/box.rb'
|
133
|
+
require 'gdsii/node.rb'
|
134
|
+
require 'gdsii/sref.rb'
|
135
|
+
require 'gdsii/aref.rb'
|
136
|
+
require 'gdsii/structure.rb'
|
137
|
+
require 'gdsii/library.rb'
|
data/lib/gdsii/aref.rb
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'gdsii/element'
|
2
|
+
require 'gdsii/group'
|
3
|
+
require 'gdsii/strans'
|
4
|
+
|
5
|
+
module Gdsii
|
6
|
+
|
7
|
+
#
|
8
|
+
# Represents a GDSII structure array reference (ARef) element. Most
|
9
|
+
# methods are from Element or from the various included Access module
|
10
|
+
# methods.
|
11
|
+
#
|
12
|
+
class ARef < Element
|
13
|
+
|
14
|
+
# Include various record accessors
|
15
|
+
include Access::ELFlags
|
16
|
+
include Access::Plex
|
17
|
+
include Access::StransGroup
|
18
|
+
include Access::Sname
|
19
|
+
|
20
|
+
#
|
21
|
+
# ARef BNF description:
|
22
|
+
#
|
23
|
+
# <aref> ::= AREF [ELFLAGS] [PLEX] SNAME [<strans>] COLROW XY
|
24
|
+
#
|
25
|
+
self.bnf_spec = BnfSpec.new(
|
26
|
+
BnfItem.new(GRT_AREF),
|
27
|
+
BnfItem.new(GRT_ELFLAGS, true),
|
28
|
+
BnfItem.new(GRT_PLEX, true),
|
29
|
+
BnfItem.new(GRT_SNAME),
|
30
|
+
BnfItem.new(Strans, true),
|
31
|
+
BnfItem.new(GRT_COLROW),
|
32
|
+
BnfItem.new(GRT_XY),
|
33
|
+
BnfItem.new(Properties, true),
|
34
|
+
BnfItem.new(GRT_ENDEL)
|
35
|
+
)
|
36
|
+
|
37
|
+
#
|
38
|
+
# Create a new structure array reference (ARef) to be used within a
|
39
|
+
# Structure object. The structure name is a String or anything that has
|
40
|
+
# a #to_s method. The ref_xy is a *single* set of x/y coordinates
|
41
|
+
# that the placement of the ARef (note this is _NOT_ the same as the
|
42
|
+
# XY record for ARef - see #xy_record for more details). The colrow is an
|
43
|
+
# array of a number of columns and rows respectively. The colrow_spc is
|
44
|
+
# an array of spacing values for columns and rows respectively.
|
45
|
+
#
|
46
|
+
# # Create an ARef at coordinates (0,0) with 2 columns and 8 rows. The
|
47
|
+
# # spacing between columns is 200 units and between rows is 300 units.
|
48
|
+
# aref = ARef.new('array', [0,0], [2,8], [200, 300])
|
49
|
+
#
|
50
|
+
# Note, the #ref_xy, #column_space, and #row_space are required.
|
51
|
+
# See #xy_record for details.
|
52
|
+
#
|
53
|
+
def initialize(sname=nil, ref_xy=nil, colrow=nil, colrow_spc=nil)
|
54
|
+
super()
|
55
|
+
@records[GRT_AREF] = Record.new(GRT_AREF)
|
56
|
+
self.sname = sname unless sname.nil?
|
57
|
+
self.colrow = colrow unless colrow.nil?
|
58
|
+
self.ref_xy = ref_xy unless ref_xy.nil?
|
59
|
+
self.column_space = colrow_spc[0] if colrow_spc.class == Array
|
60
|
+
self.row_space = colrow_spc[1] if colrow_spc.class == Array
|
61
|
+
yield self if block_given?
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Get the colrow record (returns Record)
|
66
|
+
#
|
67
|
+
def colrow_record() @records.get(GRT_COLROW); end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Get the colrow array of numbers (returns 2-element Array of Fixnum)
|
71
|
+
# where the first number is columns and the second is rows [col, row].
|
72
|
+
# Alternatively, the #rows and #columns method may also be used.
|
73
|
+
#
|
74
|
+
# aref.colrow #=> [2, 8]
|
75
|
+
#
|
76
|
+
def colrow() @records.get_data(GRT_COLROW); end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Set the colrow number (see #colrow for format details). Alternatively,
|
80
|
+
# the #rows= and #columns= methods may be used.
|
81
|
+
#
|
82
|
+
# aref.colrow = [2, 8]
|
83
|
+
#
|
84
|
+
def colrow=(val) @records.set(GRT_COLROW, val); end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Set the columns number in the COLROW record (Fixnum)
|
88
|
+
#
|
89
|
+
# aref.columns = 2
|
90
|
+
#
|
91
|
+
def columns=(val)
|
92
|
+
if (cr=colrow)
|
93
|
+
@records.set(GRT_COLROW, [val, cr[1]])
|
94
|
+
else
|
95
|
+
@records.set(GRT_COLROW, [val, nil])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Get the columns number in the COLROW record (returns Fixnum)
|
101
|
+
#
|
102
|
+
# aref.columns #=> 2
|
103
|
+
#
|
104
|
+
def columns()
|
105
|
+
(cr=@records.get(GRT_COLROW)) ? cr[0] : nil
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Set the rows number in the COLROW record
|
110
|
+
#
|
111
|
+
# aref.rows = 8
|
112
|
+
#
|
113
|
+
def rows=(val)
|
114
|
+
if (cr=colrow)
|
115
|
+
@records.set(GRT_COLROW, [cr[0], val])
|
116
|
+
else
|
117
|
+
@records.set(GRT_COLROW, [nil, val])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Get the rows number in the COLROW record (returns Fixnum)
|
123
|
+
#
|
124
|
+
# aref.rows #=> 8
|
125
|
+
#
|
126
|
+
def rows()
|
127
|
+
(cr=@records.get(GRT_COLROW)) ? cr[1] : nil
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Defines the placement XY coordinate for this ARef. See #xy_record for
|
132
|
+
# details on how the XY record is used in ARef.
|
133
|
+
#
|
134
|
+
# aref.ref_xy = [10, 20]
|
135
|
+
#
|
136
|
+
def ref_xy=(val)
|
137
|
+
if val.class == Array and val.length == 2
|
138
|
+
@ref_xy = val
|
139
|
+
update_xy
|
140
|
+
else
|
141
|
+
raise TypeError, "Expected Array of length 2"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# Returns the placement XY coordinate for this ARef. See #xy_record for
|
147
|
+
# details on how the XY record is used in ARef.
|
148
|
+
#
|
149
|
+
# aref.ref_xy #=> [10, 20]
|
150
|
+
#
|
151
|
+
def ref_xy(); @ref_xy; end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Defines the column spacing (in units) for this ARef. Internally this
|
155
|
+
# value is stored in the XY record. See #xy_record for details on how the
|
156
|
+
# XY record is used in ARef.
|
157
|
+
#
|
158
|
+
# aref.column_space = 200
|
159
|
+
#
|
160
|
+
def column_space=(val)
|
161
|
+
@column_space = val
|
162
|
+
update_xy
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Returns the placement XY coordinate for this ARef. See #xy_record for
|
167
|
+
# details on how the XY record is used in ARef.
|
168
|
+
#
|
169
|
+
# aref.column_space #=> 200
|
170
|
+
#
|
171
|
+
def column_space(); @column_space; end
|
172
|
+
|
173
|
+
#
|
174
|
+
# Defines the row spacing (in units) for this ARef. Internally this
|
175
|
+
# value is stored in the XY record. See #xy_record for details on how the
|
176
|
+
# XY record is used in ARef.
|
177
|
+
#
|
178
|
+
# aref.row_space = 300
|
179
|
+
#
|
180
|
+
def row_space=(val)
|
181
|
+
@row_space = val
|
182
|
+
update_xy
|
183
|
+
end
|
184
|
+
|
185
|
+
#
|
186
|
+
# Returns the placement XY coordinate for this ARef. See #xy_record for
|
187
|
+
# details on how the XY record is used in ARef.
|
188
|
+
#
|
189
|
+
# aref.row_space #=> 300
|
190
|
+
#
|
191
|
+
def row_space(); @row_space; end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Gets the ARef record for XY.
|
195
|
+
#
|
196
|
+
# Important note on the XY record (i.e. #xy, #xy_record): the GDSII
|
197
|
+
# specification calls for exactly 3 XY records for ARef. Because of this
|
198
|
+
# specification, there is no #xy= method available for the ARef class.
|
199
|
+
# Instead, the XY record is created dynamically when all three of these
|
200
|
+
# components are set. Otherwise, the XY record will not exist.
|
201
|
+
#
|
202
|
+
# The XY record data specification is as follows:
|
203
|
+
#
|
204
|
+
# * 1: ARef reference point (#ref_xy)
|
205
|
+
# * 2: column_space*columns+reference_x (#ref_xy, #columns, and #column_space)
|
206
|
+
# * 3: row_space*rows+reference_y (#ref_xy, #rows, and #row_space)
|
207
|
+
#
|
208
|
+
def xy_record() @records.get(GRT_XY); end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Gets an xy point record (returns an Array). Note, it is probably easier
|
212
|
+
# to use #ref_xy, #column_space, or #row_space instead; see #xy_record for
|
213
|
+
# details on how the XY record is used for ARef.
|
214
|
+
#
|
215
|
+
def xy() @records.get_data(GRT_XY); end
|
216
|
+
|
217
|
+
|
218
|
+
#####################
|
219
|
+
## PRIVATE METHODS ##
|
220
|
+
#####################
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
#
|
225
|
+
# Update the GRT_XY record if all prerequisites are met (#ref_xy,
|
226
|
+
# #column_space, and #row_space).
|
227
|
+
#
|
228
|
+
def update_xy()
|
229
|
+
if ((pxy=ref_xy) and (cs=column_space) and (rs=row_space) and (cr=colrow).length == 2)
|
230
|
+
# see #xy_record for an explanation of this formula
|
231
|
+
array = pxy + [pxy[0]+cs*cr[0], pxy[1]] + [pxy[0], pxy[1]+rs*cr[1]]
|
232
|
+
@records.set(GRT_XY, array)
|
233
|
+
else
|
234
|
+
@records.set(GRT_XY, nil)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
|
243
|
+
|