summaryrefslogtreecommitdiff
path: root/calibration.e
diff options
context:
space:
mode:
Diffstat (limited to 'calibration.e')
-rw-r--r--calibration.e550
1 files changed, 495 insertions, 55 deletions
diff --git a/calibration.e b/calibration.e
index e1b2d6a..fc6b3e0 100644
--- a/calibration.e
+++ b/calibration.e
@@ -5,102 +5,542 @@ class CALIBRATION
-- - reload calibration grid,
-- - use calibration grid for coordinates conversion.
+-- Calibration file format:
+-- device_description_file_name
+-- [offset_map] x
+-- [offset_map] y
+-- [parameter_offset] p0 x
+-- [parameter_offset] p0 y
+-- [parameter_offset] p1 x
+-- [parameter_offset] p1 y
+-- ...
+-- [parameter_offset] pnb_param-1 x
+-- [parameter_offset] pnb_param-1 y
+--
+--
+-- offset_map format:
+-- nb_point_x nb_point_y
+-- offset
+-- ...
+-- offset (nb_point_x * nb_point_y values)
+--
+--
+-- parameter_offset format:
+-- nb_point_x nb_point_y nb_param_values
+-- offset
+-- ...
+-- offset (nb_point_x * nb_point_y * nb_param_values values)
+--
+
create {ANY}
- make
+ make, load_from
+create {CALIBRATION_HANDLER}
+ uncalibrated
+
feature {}
make is
do
- create reference_points.make
end
feature {ANY}
- ready: BOOLEAN
-
- build (display_width_, display_height_: INTEGER) is
+ write_to (os: OUTPUT_STREAM) is
+ require
+ os.is_connected
local
- uncalibrated: FAST_ARRAY[INTEGER]
+ i: INTEGER
do
- display_width := display_width_
- display_height := display_height_
+ os.put_line(device_description_name)
+ x_map.write_to(os)
+ y_map.write_to(os)
from
- uncalibrated := {FAST_ARRAY[INTEGER] <<0, 0, display_width, display_height>>}
+ i := x_parameters_maps.lower
until
- uncalibrated.is_empty
+ i > x_parameters_maps.upper
loop
-
+ x_parameters_maps.item(i).write_to(os)
+ y_parameters_maps.item(i).write_to(os)
+ i := i + 1
end
ensure
- ready
+ os.is_connected
end
- write_to (os: OUTPUT_STREAM) is
+ load_from (data: INPUT_STREAM) is
require
- os.is_connected
+ data.is_connected
+ local
+ i: INTEGER
+ po: PARAMETER_OFFSET
+ device_file: TEXT_FILE_READ
do
- ensure
- os.is_connected
+ data.read_line
+ device_description_name := data.last_string.twin
+ create device_file.connect_to(device_description_name)
+ create device.load_from(device_file)
+ device_file.disconnect
+ create x_map.load_from(data, device)
+ create y_map.load_from(data, device)
+ from
+ create x_parameters_maps.make(device.nb_parameters)
+ create y_parameters_maps.make(device.nb_parameters)
+ i := x_parameters_maps.lower
+ until
+ i > x_parameters_maps.upper
+ loop
+ create po.load_from(data, device, i + 1)
+ x_parameters_maps.put(po, i)
+ create po.load_from(data, device, i + 1)
+ y_parameters_maps.put(po, i)
+ i := i + 1
+ end
end
- load_from (data: INPUT_STREAM) is
+
+ convert (x_device, y_device: INTEGER ; params: FAST_ARRAY[INTEGER]) is
+ -- Result is available in last_x, last_y
require
- data.is_connected
+ x_device.in_range(0, device.width)
+ y_device.in_range(0, device.height)
+ params /= Void implies params.count = device.nb_parameters
+ local
+ i: INTEGER
do
+ last_x := x_device + x_map.offset_at(x_device, y_device)
+ last_y := y_device + y_map.offset_at(x_device, y_device)
+ if params /= Void then
+ from
+ i := x_parameters_maps.lower
+ until
+ i > x_parameters_maps.upper
+ loop
+ last_x := last_x + x_parameters_maps.item(i).offset_at(x_device, y_device, params.item(i))
+ last_y := last_y + y_parameters_maps.item(i).offset_at(x_device, y_device, params.item(i))
+ i := i + 1
+ end
+ end
+ if last_x < 0 then
+ last_x := 0
+ end
+ if last_y < 0 then
+ last_y := 0
+ end
+ if last_x > device.width then
+ last_x := device.width
+ end
+ if last_y > device.height then
+ last_y := device.height
+ end
+ ensure
+ last_x.in_range(0, device.width)
+ last_y.in_range(0, device.height)
end
- set_offset(x_display, y_display: INTEGER) is
+ last_x, last_y: INTEGER
+ -- Last conversion result (in device coordinates)
+
+feature {}
+ partial_offset (x_device, y_device, param_index: INTEGER) is
+ -- Sum offset with parameters set to 0, up to param_index excluded.
+ -- Result is available in last_x, last_y
+ require
+ x_device.in_range(0, device.width)
+ y_device.in_range(0, device.height)
+ param_index.in_range(0, device.nb_parameters - 1)
+ local
+ i: INTEGER
do
- x_offset := x_display
- y_offset := y_display
+ last_x := x_map.offset_at(x_device, y_device)
+ last_y := y_map.offset_at(x_device, y_device)
+ from
+ i := x_parameters_maps.lower
+ until
+ i >= param_index
+ loop
+ last_x := last_x + x_parameters_maps.item(i).offset_at(x_device, y_device, 0)
+ last_y := last_y + y_parameters_maps.item(i).offset_at(x_device, y_device, 0)
+ i := i + 1
+ end
end
+
+feature {}
+ file_tools: FILE_TOOLS
- convert (x_device, y_device: INTEGER) is
- -- Result is available in last_x, last_y
+ uncalibrated(device_file_name: STRING) is
require
- x_device.in_range(0, device_width)
- y_device.in_range(0, device_height)
+ file_tools.file_exists(device_file_name)
+ local
+ i: INTEGER
+ po: PARAMETER_OFFSET
+ device_file: TEXT_FILE_READ
+ do
+ device_description_name := device_file_name
+ create device_file.connect_to(device_file_name)
+ create device.load_from(device_file)
+ device_file.disconnect
+ create x_map.uncalibrated(device)
+ create y_map.uncalibrated(device)
+ from
+ create x_parameters_maps.make(device.nb_parameters)
+ create y_parameters_maps.make(device.nb_parameters)
+ i := x_parameters_maps.lower
+ until
+ i > x_parameters_maps.upper
+ loop
+ create po.uncalibrated(device, i + 1)
+ x_parameters_maps.put(po, i)
+ create po.uncalibrated(device, i + 1)
+ y_parameters_maps.put(po, i)
+ i := i + 1
+ end
+ create reference_points.make(device.nb_parameters)
+ end
+
+ reference_points: REFERENCE_POINTS
+
+ rebuild_maps is
+ local
+ i: INTEGER
+ do
+ from
+ i := x_parameters_maps.lower
+ until
+ i > x_parameters_maps.upper
+ loop
+ x_parameters_maps.item(i).reset
+ y_parameters_maps.item(i).reset
+ i := i + 1
+ end
+ from
+ build_position_maps
+ i := x_parameters_maps.lower
+ until
+ i > x_parameters_maps.upper
+ loop
+ build_parameter_maps(i)
+ i := i + 1
+ end
+ end
+
+feature {} -- building maps
+-- nb_intervals: INTEGER is 100 --*** auto ?
+ nb_intervals: INTEGER is 10
+
+ build_position_maps is
local
i, j: INTEGER
- x_rest, y_rest: INTEGER
-
+ xmap, ymap: FAST_ARRAY2[INTEGER]
do
- i := x_device // horizontal_step
- j := y_device // vertical_step
- x_rest := x_device - i * horizontal_step
- y_rest := y_device - j * vertical_step
- if y_rest * 2 < vertical_step then
- last_x := ((x_table.item(i, j) * x_rest + x_table.item(i + 1, j) * (horizontal_step - x_rest)) / horizontal_step).force_to_integer_32
+ from
+ xmap := x_map.empty_map(nb_intervals + 1)
+ ymap := y_map.empty_map(nb_intervals + 1)
+ i := xmap.lower1
+ until
+ i > xmap.upper1
+ loop
+ from
+ j := xmap.lower2
+ until
+ j > xmap.upper2
+ loop
+ xmap.put(build_x_offset_for(i/nb_intervals, j/nb_intervals), i, j)
+ ymap.put(build_y_offset_for(i/nb_intervals, j/nb_intervals), i, j)
+ j := j + 1
+ end
+ i := i + 1
+ end
+ end
+
+ build_x_offset_for(x, y: REAL): INTEGER is
+ local
+ i, j, v: INTEGER
+ continue: BOOLEAN
+ left_index, right_index: INTEGER
+ left_distance, right_distance: REAL
+ left_error, right_error: INTEGER
+ tmp, length, dev: REAL
+ do
+ from
+ left_distance := device.nb_parameters * 3
+ right_distance := left_distance
+ left_index := -1
+ right_index := -1
+ i := reference_points.count - 1
+ until
+ i < 0
+ loop
+ from
+ tmp := (reference_points.x_target(i) / device.width - x) * 3
+ length := tmp * tmp
+ tmp := reference_points.y_target(i) / device.height - y
+ length := length + tmp * tmp
+ j := device.nb_parameters - 1
+ continue := True
+ until
+ j < 0 or not continue
+ loop
+ v := reference_points.parameter_value(i, j)
+ dev := rate(v, device.min_parameter(j + 1), device.max_parameter(j + 1))
+ continue := dev.in_range(0.4, 0.6)
+ dev := dev - 0.5
+ length := length + dev * dev
+ j := j - 1
+ end
+ if continue then
+ if reference_points.x_target(i) / device.width < x then
+ if length < left_distance then
+ left_index := i
+ left_distance := length
+ end
+ else
+ if length < right_distance then
+ right_index := i
+ right_distance := length
+ end
+ end
+ end
+ i := i - 1
+ end
+ if right_index = -1 then
+ Result := reference_points.x_target(left_index) - reference_points.x_measure(left_index)
+ elseif left_index = -1 then
+ Result := reference_points.x_target(right_index) - reference_points.x_measure(right_index)
else
- last_x := ((x_table.item(i, j + 1) * x_rest + x_table.item(i + 1, j + 1) * (horizontal_step - x_rest)) / horizontal_step).force_to_integer_32
+ left_distance := left_distance.sqrt
+ right_distance := right_distance.sqrt
+-- io.put_string(once "x = "); io.put_real(x); io.put_string(once " y = "); io.put_real(y); io.put_new_line
+-- io.put_string(once "ld = "); io.put_real(left_distance); io.put_character(' '); io.put_integer(left_index);io.put_new_line
+-- io.put_string(once "rd = "); io.put_real(right_distance); io.put_character(' '); io.put_integer(right_index); io.put_new_line
+ left_error := reference_points.x_target(left_index) - reference_points.x_measure(left_index)
+ right_error := reference_points.x_target(right_index) - reference_points.x_measure(right_index)
+-- io.put_string(once "le = "); io.put_real(left_error); io.put_new_line
+-- io.put_string(once "re = "); io.put_real(right_error); io.put_new_line
+ Result := ((right_error*left_distance + left_error*right_distance) / (left_distance + right_distance)).force_to_integer_32
+-- io.put_string(once "R = "); io.put_integer(Result); io.put_new_line; io.put_new_line
+ end
+ end
+
+ build_y_offset_for(x, y: REAL): INTEGER is
+ local
+ i, j, v: INTEGER
+ continue: BOOLEAN
+ up_index, down_index: INTEGER
+ up_distance, down_distance: REAL
+ up_error, down_error: INTEGER
+ tmp, length, dev: REAL
+ do
+ from
+ up_distance := device.nb_parameters * 3
+ down_distance := up_distance
+ up_index := -1
+ down_index := -1
+ i := reference_points.count - 1
+ until
+ i < 0
+ loop
+ from
+ tmp := reference_points.x_target(i) / device.width - x
+ length := tmp * tmp
+ tmp := (reference_points.y_target(i) / device.height - y) * 3
+ length := length + tmp * tmp
+ j := device.nb_parameters - 1
+ continue := True
+ until
+ j < 0 or not continue
+ loop
+ v := reference_points.parameter_value(i, j)
+ dev := rate(v, device.min_parameter(j + 1), device.max_parameter(j + 1))
+ continue := dev.in_range(0.4, 0.6)
+ dev := dev - 0.5
+ length := length + dev * dev
+ j := j - 1
+ end
+ if continue then
+ if reference_points.y_target(i) / device.height < y then
+ if length < up_distance then
+ up_index := i
+ up_distance := length
+ end
+ else
+ if length < down_distance then
+ down_index := i
+ down_distance := length
+ end
+ end
+ end
+ i := i - 1
end
- if x_rest * 2 < horizontal_step then
- last_y := ((y_table.item(i, j) * y_rest + y_table.item(i, j + 1) * (vertical_step - y_rest)) / vertical_step).force_to_integer_32
+ if down_index = -1 then
+ Result := reference_points.y_target(up_index) - reference_points.y_measure(up_index)
+ elseif up_index = -1 then
+ Result := reference_points.y_target(down_index) - reference_points.y_measure(down_index)
else
- last_y := ((y_table.item(i + 1, j) * y_rest + y_table.item(i + 1, j + 1) * (vertical_step - y_rest)) / vertical_step).force_to_integer_32
+ up_distance := up_distance.sqrt
+ down_distance := down_distance.sqrt
+ up_error := reference_points.y_target(up_index) - reference_points.y_measure(up_index)
+ down_error := reference_points.y_target(down_index) - reference_points.y_measure(down_index)
+ Result := ((down_error*up_distance + up_error*down_distance) / (up_distance + down_distance)).force_to_integer_32
end
- ensure
- last_x.in_range(x_offset, x_offset + display_width -1)
- last_y.in_range(y_offset, y_offset + display_height - 1)
end
- last_x, last_y: INTEGER
- -- Last conversion result (in display coordinates)
+ param_division: INTEGER is 4
-feature {}
- x_offset, y_offset, display_width, display_height: INTEGER
- -- coordinates and size of the displayed area in pixels
+ build_parameter_maps(param: INTEGER) is
+ require
+ param.in_range(0, device.nb_parameters - 1)
+ local
+ i, j, k: INTEGER
+ xmap, ymap: FAST_ARRAY3[INTEGER]
+ hstep, vstep: INTEGER
+ correction_x, correction_y: INTEGER
+ do
+ hstep := x_map.horizontal_step.to_integer_32
+ vstep := y_map.vertical_step.to_integer_32
+ xmap := x_parameters_maps.item(param).empty_map(nb_intervals + 1, param_division + 1)
+ ymap := y_parameters_maps.item(param).empty_map(nb_intervals + 1, param_division + 1)
+ from
+ i := xmap.lower1
+ until
+ i > xmap.upper1
+ loop
+ from
+ j := xmap.lower2
+ until
+ j > xmap.upper2
+ loop
+ from
+ k := xmap.lower3
+ partial_offset(i * hstep, j * vstep, param)
+ correction_x := last_x
+ correction_y := last_y
+ until
+ k > xmap.upper3
+ loop
+ xmap.put(build_x_offset_for_parameter(i/nb_intervals, j/nb_intervals, k / param_division, param, correction_x), i, j, k)
+ ymap.put(build_y_offset_for_parameter(i/nb_intervals, j/nb_intervals, k / param_division, param, correction_y), i, j, k)
+ k := k + 1
+ end
+ j := j + 1
+ end
+ i := i + 1
+ end
+ end
+
+ build_x_offset_for_parameter(x, y, z: REAL; index: INTEGER; cumulated_correction: INTEGER): INTEGER is
+ local
+ i, j, v: INTEGER
+ continue: BOOLEAN
+ left_index, right_index: INTEGER
+ left_distance, right_distance: REAL
+ left_error, right_error: INTEGER
+ tmp, length, dev: REAL
+ do
+ from
+ left_distance := device.nb_parameters * 3
+ right_distance := left_distance
+ left_index := -1
+ right_index := -1
+ i := reference_points.count - 1
+ until
+ i < 0
+ loop
+ from
+ tmp := reference_points.x_target(i) / device.width - x
+ length := tmp * tmp
+ tmp := reference_points.y_target(i) / device.height - y
+ length := length + tmp * tmp
+ j := device.nb_parameters - 1
+ continue := True
+ until
+ j < 0 or not continue
+ loop
+ v := reference_points.parameter_value(i, j)
+ dev := rate(v, device.min_parameter(j + 1), device.max_parameter(j + 1))
+ if j = index then
+ continue := dev.in_range(z - 0.15, z + 0.15)
+ dev := (dev - z) * 3
+ else
+ continue := dev.in_range(0.4, 0.6)
+ dev := dev - 0.5
+ end
+ length := length + dev * dev
+ j := j - 1
+ end
+ if continue then
+ if reference_points.x_target(i) / device.width < x then
+ if length < left_distance then
+ left_index := i
+ left_distance := length
+ end
+ else
+ if length < right_distance then
+ right_index := i
+ right_distance := length
+ end
+ end
+ end
+ i := i - 1
+ end
+ if right_index /= -1 then
+ if left_index /= -1 then
+ left_distance := left_distance.sqrt
+ right_distance := right_distance.sqrt
+ left_error := reference_points.x_target(left_index) - reference_points.x_measure(left_index)
+ right_error := reference_points.x_target(right_index) - reference_points.x_measure(right_index)
+ Result := ((right_error*left_distance + left_error*right_distance) / (left_distance + right_distance)).force_to_integer_32 - cumulated_correction
+ else
+ Result := reference_points.x_target(right_index) - reference_points.x_measure(right_index) - cumulated_correction
+ end
+ else
+ if left_index /= -1 then
+ Result := reference_points.x_target(left_index) - reference_points.x_measure(left_index) - cumulated_correction
+ else
+ Result := 0
+ end
+ end
+ end
+
+ build_y_offset_for_parameter(x, y, z: REAL; index: INTEGER; cumulated_correction: INTEGER): INTEGER is
+ do
+ end
+
+ rate(value, min, max: INTEGER): REAL is
+ require
+ value.in_range(min, max)
+ do
+ Result := (value - min) / (max - min)
+ ensure
+ Result.in_range(0, 1)
+ end
+
+feature {CALIBRATION_HANDLER}
+ add_measure(x_target, y_target: INTEGER; x_measure, y_measure: INTEGER; parameters_values: FAST_ARRAY[INTEGER]) is
+ require
+ device.valid_x(x_target)
+ device.valid_y(y_target)
+ device.valid_x(x_measure)
+ device.valid_y(y_measure)
+ device.valid_parameters(parameters_values)
+ do
+ reference_points.add_point(x_target, y_target, x_measure, y_measure, parameters_values)
+ rebuild_maps
+ end
- x_table, y_table: FAST_ARRAY2[REAL]
- -- Store display coordinates for device coordinate. Use
- -- `horizontal_step' and `vertical_step' for table indexes values.
+ x_map, y_map: OFFSET_MAP
- horizontal_step, vertical_step: INTEGER
- -- Indexes steps for tables
+ x_parameters_maps, y_parameters_maps: FAST_ARRAY[PARAMETER_OFFSET]
- device_width, device_height: INTEGER
- -- Digitizer size
+ device: DEVICE_DESCRIPTION
+
+feature {}
+ device_description_name: STRING
+
+invariant
+ (x_parameters_maps /= Void) = (y_parameters_maps /= Void)
- reference_points: REFERENCE_POINTS
- -- 4 values per reference point x_device
+ x_parameters_maps /= Void implies x_parameters_maps.count = y_parameters_maps.count
+
+ device.nb_parameters = 0 implies x_parameters_maps = Void
+
+ device.nb_parameters /= 0 implies x_parameters_maps.count = device.nb_parameters
end
-