116 lines
3.0 KiB
GDScript
116 lines
3.0 KiB
GDScript
class_name SonarSampleBuffer
|
|
extends RefCounted
|
|
|
|
const SonarMaterial = preload("res://game/domain/sonar/sonar_material.gd")
|
|
const SonarSample = preload("res://game/domain/sonar/sonar_sample.gd")
|
|
|
|
var columns: int
|
|
var rows: int
|
|
|
|
var _positions := PackedVector3Array()
|
|
var _normals := PackedVector3Array()
|
|
var _intensities := PackedFloat32Array()
|
|
var _elevations_m := PackedFloat32Array()
|
|
var _materials := PackedInt32Array()
|
|
var _observed := PackedByteArray()
|
|
var _sealed := false
|
|
|
|
|
|
func _init(p_columns: int, p_rows: int) -> void:
|
|
columns = p_columns
|
|
rows = p_rows
|
|
var sample_count := maxi(columns, 0) * maxi(rows, 0)
|
|
_positions.resize(sample_count)
|
|
_normals.resize(sample_count)
|
|
_intensities.resize(sample_count)
|
|
_elevations_m.resize(sample_count)
|
|
_materials.resize(sample_count)
|
|
_observed.resize(sample_count)
|
|
for index in sample_count:
|
|
_normals[index] = Vector3.UP
|
|
_materials[index] = SonarMaterial.Value.UNKNOWN
|
|
|
|
|
|
func set_sample(row: int, column: int, sample: SonarSample) -> String:
|
|
if _sealed:
|
|
return "sonar sample buffer is sealed"
|
|
var index := _index_of(row, column)
|
|
if index < 0:
|
|
return "sonar sample coordinates are outside the buffer"
|
|
if sample == null:
|
|
return "sonar sample is missing"
|
|
var error := sample.validation_error()
|
|
if not error.is_empty():
|
|
return error
|
|
if not sample.observed:
|
|
return "cannot write an unobserved sonar sample"
|
|
if _observed[index] == 1:
|
|
return "sonar sample coordinates are duplicated"
|
|
_positions[index] = sample.position_m
|
|
_normals[index] = sample.normal.normalized()
|
|
_intensities[index] = sample.intensity
|
|
_elevations_m[index] = sample.elevation_m
|
|
_materials[index] = sample.material
|
|
_observed[index] = 1
|
|
return ""
|
|
|
|
|
|
func seal() -> String:
|
|
if columns < 2 or rows < 2:
|
|
return "sonar sample buffer dimensions must be at least 2 by 2"
|
|
_sealed = true
|
|
return ""
|
|
|
|
|
|
func is_sealed() -> bool:
|
|
return _sealed
|
|
|
|
|
|
func sample_count() -> int:
|
|
return columns * rows
|
|
|
|
|
|
func observed_count() -> int:
|
|
var count := 0
|
|
for value: int in _observed:
|
|
count += value
|
|
return count
|
|
|
|
|
|
func sample_at(row: int, column: int) -> SonarSample:
|
|
var index := _index_of(row, column)
|
|
if index < 0 or _observed[index] == 0:
|
|
return SonarSample.unknown()
|
|
return SonarSample.new(
|
|
_positions[index],
|
|
_normals[index],
|
|
_intensities[index],
|
|
_elevations_m[index],
|
|
_materials[index],
|
|
true
|
|
)
|
|
|
|
|
|
func validation_error() -> String:
|
|
if columns < 2 or rows < 2:
|
|
return "sonar sample buffer dimensions must be at least 2 by 2"
|
|
if not _sealed:
|
|
return "sonar sample buffer must be sealed before publication"
|
|
var expected_size := columns * rows
|
|
if (
|
|
_positions.size() != expected_size
|
|
or _normals.size() != expected_size
|
|
or _intensities.size() != expected_size
|
|
or _elevations_m.size() != expected_size
|
|
or _materials.size() != expected_size
|
|
or _observed.size() != expected_size
|
|
):
|
|
return "sonar sample buffer arrays are not aligned"
|
|
return ""
|
|
|
|
|
|
func _index_of(row: int, column: int) -> int:
|
|
if row < 0 or row >= rows or column < 0 or column >= columns:
|
|
return -1
|
|
return row * columns + column
|