use crate::foundation::{GeoError, Result};
use std::path::Path;
const POLY_SEP: f64 = 999.0;
fn parse_xyz(line: &str) -> Result<Option<[f64; 3]>> {
let line = line.trim();
if line.is_empty() || line.starts_with('#') || line.starts_with('!') {
return Ok(None);
}
let mut it = line.split(|c: char| c.is_whitespace() || c == ',');
let mut next = |what: &str| -> Result<f64> {
loop {
let t = it
.next()
.ok_or_else(|| GeoError::Parse(format!("XYZ: missing {what} in '{line}'")))?;
if t.is_empty() {
continue; }
return t
.parse::<f64>()
.map_err(|e| GeoError::Parse(format!("XYZ: bad {what} '{t}': {e}")));
}
};
let x = next("x")?;
let y = next("y")?;
let z = next("z")?;
Ok(Some([x, y, z]))
}
pub fn load_points(path: &Path) -> Result<Vec<[f64; 3]>> {
let text = std::fs::read_to_string(path)?;
let mut out = Vec::new();
for line in text.lines() {
if let Some(p) = parse_xyz(line)? {
if p[0] == POLY_SEP {
continue;
}
out.push(p);
}
}
Ok(out)
}
pub fn load_polygons(path: &Path) -> Result<Vec<Vec<[f64; 3]>>> {
let text = std::fs::read_to_string(path)?;
let mut rings: Vec<Vec<[f64; 3]>> = Vec::new();
let mut current: Vec<[f64; 3]> = Vec::new();
for line in text.lines() {
let Some(p) = parse_xyz(line)? else { continue };
if p[0] == POLY_SEP {
if !current.is_empty() {
rings.push(std::mem::take(&mut current));
}
} else {
current.push(p);
}
}
if !current.is_empty() {
rings.push(current);
}
Ok(rings)
}