use crate::errors::{GrandmaError, GrandmaResult};
use crate::tree_file_format::*;
use protobuf::{CodedInputStream, CodedOutputStream, Message};
use std::fs::File;
use std::fs::{read_to_string, remove_file, OpenOptions};
use std::path::Path;
use std::sync::Arc;
use yaml_rust::YamlLoader;
use crate::builders::CoverTreeBuilder;
use crate::tree::CoverTreeWriter;
use pointcloud::loaders::{labeled_ram_from_yaml, ram_from_yaml};
use pointcloud::*;
pub fn cover_tree_from_labeled_yaml<P: AsRef<Path>>(
path: P,
) -> GrandmaResult<CoverTreeWriter<DefaultLabeledCloud<L2>>> {
let config = read_to_string(&path).expect("Unable to read config file");
let params_files = YamlLoader::load_from_str(&config).unwrap();
let params = ¶ms_files[0];
let point_cloud = labeled_ram_from_yaml::<_, L2>(&path)?;
if let Some(count) = params["count"].as_i64() {
if count as usize != point_cloud.len() {
panic!(
"We expected {:?} points, but the file has {:?} points at dim {:?}",
count,
point_cloud.len(),
point_cloud.dim()
);
}
}
let builder = CoverTreeBuilder::from_yaml(&path);
println!(
"Loaded dataset, building a cover tree with scale base {}, leaf_cutoff {}, min_res_index {}, and use_singletons {}",
&builder.scale_base, &builder.min_res_index, &builder.min_res_index, &builder.use_singletons
);
Ok(builder.build(Arc::new(point_cloud))?)
}
pub fn cover_tree_from_yaml<P: AsRef<Path>>(
path: P,
) -> GrandmaResult<CoverTreeWriter<DefaultCloud<L2>>> {
let config = read_to_string(&path).expect("Unable to read config file");
let params_files = YamlLoader::load_from_str(&config).unwrap();
let params = ¶ms_files[0];
let point_cloud = ram_from_yaml::<_, L2>(&path)?;
if let Some(count) = params["count"].as_i64() {
if count as usize != point_cloud.len() {
panic!(
"We expected {:?} points, but the file has {:?} points at dim {:?}",
count,
point_cloud.len(),
point_cloud.dim()
);
}
}
let builder = CoverTreeBuilder::from_yaml(&path);
println!(
"Loaded dataset, building a cover tree with scale base {}, leaf_cutoff {}, min_res_index {}, and use_singletons {}",
&builder.scale_base, &builder.min_res_index, &builder.min_res_index, &builder.use_singletons
);
Ok(builder.build(Arc::new(point_cloud))?)
}
pub fn load_tree<P: AsRef<Path>, D: PointCloud>(
tree_path: P,
point_cloud: Arc<D>,
) -> GrandmaResult<CoverTreeWriter<D>> {
let tree_path_ref: &Path = tree_path.as_ref();
println!("\nLoading tree from : {}", tree_path_ref.to_string_lossy());
if !tree_path_ref.exists() {
let tree_path_str = match tree_path_ref.to_str() {
Some(expr) => expr,
None => panic!("Unicode error with the tree path"),
};
panic!(tree_path_str.to_string() + &" does not exist\n".to_string());
}
let mut cover_proto = CoreProto::new();
let mut file = match File::open(&tree_path_ref) {
Ok(file) => file,
Err(e) => panic!("Unable to open file {:#?}", e),
};
let mut cis = CodedInputStream::new(&mut file);
if let Err(e) = cover_proto.merge_from(&mut cis) {
panic!("Proto buff was unable to read {:#?}", e)
}
CoverTreeWriter::load(&cover_proto, point_cloud)
}
pub fn save_tree<P: AsRef<Path>, D: PointCloud>(
tree_path: P,
cover_tree: &CoverTreeWriter<D>,
) -> GrandmaResult<()> {
let tree_path_ref: &Path = tree_path.as_ref();
println!("Saving tree to : {}", tree_path_ref.to_string_lossy());
if tree_path_ref.exists() {
let tree_path_str = match tree_path_ref.to_str() {
Some(expr) => expr,
None => panic!("Unicode error with the tree path"),
};
println!("\t \t {:?} exists, removing", tree_path_str);
remove_file(&tree_path).map_err(GrandmaError::from)?;
}
let cover_proto = cover_tree.save();
let mut core_file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&tree_path)
.unwrap();
let mut cos = CodedOutputStream::new(&mut core_file);
cover_proto.write_to(&mut cos).map_err(GrandmaError::from)?;
cos.flush().map_err(GrandmaError::from)?;
Ok(())
}