Skip to content

Commit 3dfaf34

Browse files
committed
Add GRAxis, GRTick, and GRTickLabel classes for enhanced axis handling
1 parent bac8a3a commit 3dfaf34

File tree

1 file changed

+168
-44
lines changed

1 file changed

+168
-44
lines changed

lib/gr.rb

Lines changed: 168 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,54 @@ class << self
9595
# a Fiddley::MemoryPointer in the GRBase class.
9696
extend GRBase
9797

98+
# High-level axis/tick objects
99+
class GRTick
100+
attr_accessor :value, :is_major
101+
102+
def initialize(value:, is_major:)
103+
@value = value
104+
@is_major = is_major
105+
end
106+
end
107+
108+
class GRTickLabel
109+
attr_accessor :tick, :label, :width
110+
111+
def initialize(tick:, label:, width:)
112+
@tick = tick
113+
@label = label
114+
@width = width
115+
end
116+
end
117+
118+
class GRAxis
119+
attr_accessor :min, :max, :tick, :org, :position,
120+
:major_count, :num_ticks, :ticks,
121+
:tick_size, :tick_labels, :label_position,
122+
:draw_axis_line, :label_orientation
123+
124+
def initialize(min: Float::NAN, max: Float::NAN, tick: Float::NAN,
125+
org: Float::NAN, position: Float::NAN,
126+
major_count: 1, num_ticks: 0, ticks: nil,
127+
tick_size: Float::NAN, tick_labels: nil,
128+
label_position: Float::NAN,
129+
draw_axis_line: 1, label_orientation: 0)
130+
@min = min
131+
@max = max
132+
@tick = tick
133+
@org = org
134+
@position = position
135+
@major_count = major_count
136+
@num_ticks = num_ticks
137+
@ticks = ticks
138+
@tick_size = tick_size
139+
@tick_labels = tick_labels
140+
@label_position = label_position
141+
@draw_axis_line = draw_axis_line
142+
@label_orientation = label_orientation
143+
end
144+
end
145+
98146
class << self
99147
# @!method initgr
100148

@@ -1116,50 +1164,31 @@ def inqtextext(x, y, string)
11161164

11171165
alias axes2d axes
11181166

1119-
def axis(option, min: Float::NAN, max: Float::NAN, tick: Float::NAN, org: Float::NAN, position: Float::NAN, major_count: 1,
1120-
tick_size: Float::NAN, label_position: Float::NAN, draw_axis_line: 1, label_orientation: 0)
1121-
ax = FFI::Axis.malloc
1122-
ax[:min] = min
1123-
ax[:max] = max
1124-
ax[:tick] = tick
1125-
ax[:org] = org
1126-
ax[:position] = position
1127-
ax[:major_count] = major_count
1128-
ax[:tick_size] = tick_size
1129-
ax[:label_position] = label_position
1130-
ax[:draw_axis_line] = draw_axis_line
1131-
ax[:label_orientation] = label_orientation
1132-
ax[:ticks] = 0
1133-
ax[:num_ticks] = 0
1134-
ax[:tick_labels] = 0
1135-
ax[:num_tick_labels] = 0
1136-
super(option, ax)
1137-
ax
1138-
end
1139-
1140-
def drawaxis(option, min: Float::NAN, max: Float::NAN, tick: Float::NAN, org: Float::NAN, position: Float::NAN,
1141-
major_count: 1, tick_size: Float::NAN, label_position: Float::NAN, draw_axis_line: 1, label_orientation: 0)
1142-
ax = FFI::Axis.malloc
1143-
ax[:min] = min
1144-
ax[:max] = max
1145-
ax[:tick] = tick
1146-
ax[:org] = org
1147-
ax[:position] = position
1148-
ax[:major_count] = major_count
1149-
ax[:tick_size] = tick_size
1150-
ax[:label_position] = label_position
1151-
ax[:draw_axis_line] = draw_axis_line
1152-
ax[:label_orientation] = label_orientation
1153-
ax[:ticks] = 0
1154-
ax[:num_ticks] = 0
1155-
ax[:tick_labels] = 0
1156-
ax[:num_tick_labels] = 0
1157-
super(option, ax)
1158-
ax
1159-
end
1160-
1161-
def drawaxes(x_axis, y_axis, option = 1)
1162-
super(x_axis, y_axis, option)
1167+
def axis(option, **opts)
1168+
axis = GRAxis.new
1169+
opts.each do |k, v|
1170+
setter = "#{k}="
1171+
axis.public_send(setter, v) if axis.respond_to?(setter)
1172+
end
1173+
1174+
c_axis = __axis_to_c_axis(axis)
1175+
# accept String, Symbol or single-character option
1176+
ch = option.is_a?(Symbol) ? option.to_s[0, 1] : option.to_s[0, 1]
1177+
FFI.gr_axis(ch.ord, c_axis)
1178+
__axis_from_c_axis(c_axis)
1179+
end
1180+
1181+
def drawaxis(option, axis)
1182+
c_axis = __axis_to_c_axis(axis)
1183+
# accept String, Symbol or single-character option
1184+
ch = option.is_a?(Symbol) ? option.to_s[0, 1] : option.to_s[0, 1]
1185+
FFI.gr_drawaxis(ch.ord, c_axis)
1186+
end
1187+
1188+
def drawaxes(x_axis = nil, y_axis = nil, option = 1)
1189+
c_x = x_axis && __axis_to_c_axis(x_axis)
1190+
c_y = y_axis && __axis_to_c_axis(y_axis)
1191+
FFI.gr_drawaxes(c_x || 0, c_y || 0, option)
11631192
end
11641193

11651194
# Create axes in the current workspace and supply a custom function for
@@ -2511,6 +2540,101 @@ def ftoa(value, format_ref)
25112540
super(string, value, format_ref)
25122541
string.to_s
25132542
end
2543+
2544+
private
2545+
2546+
# Convert high-level GRAxis into low-level FFI::Axis
2547+
def __axis_to_c_axis(axis)
2548+
c_axis = FFI::Axis.malloc
2549+
2550+
c_axis[:min] = axis.min
2551+
c_axis[:max] = axis.max
2552+
c_axis[:tick] = axis.tick
2553+
c_axis[:org] = axis.org
2554+
c_axis[:position] = axis.position
2555+
c_axis[:major_count] = axis.major_count
2556+
2557+
# ticks
2558+
if axis.ticks && !axis.ticks.empty?
2559+
count = axis.ticks.size
2560+
mem = FFI::Tick.malloc(count)
2561+
axis.ticks.each_with_index do |t, i|
2562+
tick = FFI::Tick.new(mem.to_ptr + i * FFI::Tick.size)
2563+
tick[:value] = t.value
2564+
tick[:is_major] = t.is_major
2565+
end
2566+
c_axis[:num_ticks] = count
2567+
c_axis[:ticks] = mem.to_ptr
2568+
else
2569+
c_axis[:num_ticks] = 0
2570+
c_axis[:ticks] = 0
2571+
end
2572+
2573+
c_axis[:tick_size] = axis.tick_size
2574+
2575+
# tick labels
2576+
if axis.tick_labels && !axis.tick_labels.empty?
2577+
count = axis.tick_labels.size
2578+
mem = FFI::TickLabel.malloc(count)
2579+
axis.tick_labels.each_with_index do |tl, i|
2580+
lbl = FFI::TickLabel.new(mem.to_ptr + i * FFI::TickLabel.size)
2581+
lbl[:tick] = tl.tick
2582+
lbl[:label] = Fiddle::Pointer[tl.label.to_s + "\0"]
2583+
lbl[:width] = tl.width
2584+
end
2585+
c_axis[:num_tick_labels] = count
2586+
c_axis[:tick_labels] = mem.to_ptr
2587+
else
2588+
c_axis[:num_tick_labels] = 0
2589+
c_axis[:tick_labels] = 0
2590+
end
2591+
2592+
c_axis[:label_position] = axis.label_position
2593+
c_axis[:draw_axis_line] = axis.draw_axis_line
2594+
c_axis[:label_orientation] = axis.label_orientation
2595+
2596+
c_axis
2597+
end
2598+
2599+
# Convert low-level FFI::Axis back into high-level GRAxis
2600+
def __axis_from_c_axis(c_axis)
2601+
ticks = if c_axis[:num_ticks].positive? && !Fiddle::Pointer[c_axis[:ticks]].null?
2602+
Array.new(c_axis[:num_ticks]) do |i|
2603+
tick = FFI::Tick.new(c_axis[:ticks] + i * FFI::Tick.size)
2604+
GRTick.new(value: tick[:value], is_major: tick[:is_major])
2605+
end
2606+
else
2607+
[]
2608+
end
2609+
2610+
tick_labels = if c_axis[:num_tick_labels].positive? && !Fiddle::Pointer[c_axis[:tick_labels]].null?
2611+
Array.new(c_axis[:num_tick_labels]) do |i|
2612+
lbl = FFI::TickLabel.new(c_axis[:tick_labels] + i * FFI::TickLabel.size)
2613+
ptr = Fiddle::Pointer[lbl[:label]]
2614+
next if ptr.null?
2615+
2616+
GRTickLabel.new(tick: lbl[:tick], label: ptr.to_s, width: lbl[:width])
2617+
end.compact
2618+
else
2619+
[]
2620+
end
2621+
2622+
GRAxis.new(
2623+
min: c_axis[:min],
2624+
max: c_axis[:max],
2625+
tick: c_axis[:tick],
2626+
org: c_axis[:org],
2627+
position: c_axis[:position],
2628+
major_count: c_axis[:major_count],
2629+
num_ticks: c_axis[:num_ticks],
2630+
ticks: ticks,
2631+
tick_size: c_axis[:tick_size],
2632+
tick_labels: tick_labels,
2633+
label_position: c_axis[:label_position],
2634+
draw_axis_line: c_axis[:draw_axis_line],
2635+
label_orientation: c_axis[:label_orientation]
2636+
)
2637+
end
25142638
end
25152639

25162640
ASF_BUNDLED = 0

0 commit comments

Comments
 (0)