use std::path::Path;
use crate::data::{AnyDataArray, DataArray, PolyData};
use crate::types::VtkError;
use crate::types::{VectorLayerInfo, SpatialRef, GeomType};
pub fn read_vector(path: &Path) -> Result<(PolyData, VectorLayerInfo), VtkError> {
let dataset = gdal::Dataset::open(path)
.map_err(|e| VtkError::Io(std::io::Error::new(std::io::ErrorKind::Other, format!("{e}"))))?;
let layer = dataset.layer(0)
.map_err(|e| VtkError::Parse(format!("layer: {e}")))?;
let spatial_ref = layer.spatial_ref()
.map(|sr| SpatialRef {
epsg: sr.auth_code().ok().map(|c| c as u32),
wkt: sr.to_wkt().unwrap_or_default(),
proj4: sr.to_proj4().unwrap_or_default(),
})
.unwrap_or_default();
let field_names: Vec<String> = layer.defn().fields()
.map(|f| f.name().to_string())
.collect();
let mut points = crate::data::Points::<f64>::new();
let mut polys = crate::data::CellArray::new();
let mut lines = crate::data::CellArray::new();
let mut verts = crate::data::CellArray::new();
let mut num_features = 0;
let num_fields = field_names.len();
let mut field_values: Vec<Vec<f64>> = vec![Vec::new(); num_fields];
for feature in layer.features() {
num_features += 1;
for (fi, fname) in field_names.iter().enumerate() {
let val = feature.field(fname)
.ok()
.flatten()
.and_then(|v| match v {
gdal::vector::FieldValue::IntegerValue(i) => Some(i as f64),
gdal::vector::FieldValue::Integer64Value(i) => Some(i as f64),
gdal::vector::FieldValue::RealValue(f) => Some(f),
_ => None,
})
.unwrap_or(0.0);
field_values[fi].push(val);
}
let Some(geom) = feature.geometry() else { continue };
match geom.geometry_type() {
gdal::vector::OGRwkbGeometryType::wkbPoint |
gdal::vector::OGRwkbGeometryType::wkbPoint25D => {
let (x, y, z) = geom.get_point(0);
let idx = points.len() as i64;
points.push([x, y, z]);
verts.push_cell(&[idx]);
}
gdal::vector::OGRwkbGeometryType::wkbLineString |
gdal::vector::OGRwkbGeometryType::wkbLineString25D => {
let n = geom.point_count();
let base = points.len() as i64;
let mut cell = Vec::with_capacity(n);
for i in 0..n {
let (x, y, z) = geom.get_point(i as i32);
points.push([x, y, z]);
cell.push(base + i as i64);
}
lines.push_cell(&cell);
}
gdal::vector::OGRwkbGeometryType::wkbPolygon |
gdal::vector::OGRwkbGeometryType::wkbPolygon25D => {
if let Some(ring) = geom.geometry_ref(0) {
let n = ring.point_count();
let base = points.len() as i64;
let mut cell = Vec::with_capacity(n.saturating_sub(1));
for i in 0..n.saturating_sub(1) { let (x, y, z) = ring.get_point(i as i32);
points.push([x, y, z]);
cell.push(base + i as i64);
}
if !cell.is_empty() {
polys.push_cell(&cell);
}
}
}
_ => {}
}
}
let geom_type_str = if polys.num_cells() > 0 { "Polygon" }
else if lines.num_cells() > 0 { "LineString" }
else { "Point" };
let info = VectorLayerInfo {
name: layer.name().to_string(),
num_features,
geometry_type: geom_type_str.to_string(),
spatial_ref,
field_names: field_names.clone(),
};
let mut pd = PolyData::new();
pd.points = points;
pd.polys = polys;
pd.lines = lines;
pd.verts = verts;
for (fi, fname) in field_names.iter().enumerate() {
if !field_values[fi].is_empty() {
pd.cell_data_mut().add_array(AnyDataArray::F64(
DataArray::from_vec(fname, field_values[fi].clone(), 1),
));
}
}
Ok((pd, info))
}
pub fn read_all_layers(path: &Path) -> Result<Vec<(PolyData, VectorLayerInfo)>, VtkError> {
let dataset = gdal::Dataset::open(path)
.map_err(|e| VtkError::Io(std::io::Error::new(std::io::ErrorKind::Other, format!("{e}"))))?;
let mut results = Vec::new();
let num_layers = dataset.layer_count();
for i in 0..num_layers {
if let Ok(result) = read_vector(path) {
results.push(result);
break; }
}
Ok(results)
}