Skip to content

Commit

Permalink
choose parser
Browse files Browse the repository at this point in the history
  • Loading branch information
nokonoko1203 committed Nov 19, 2024
1 parent 657ee6b commit d9bc7c1
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 101 deletions.
18 changes: 10 additions & 8 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@
"--input",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1875.las",
// "/Users/satoru/Downloads/pointcloud/09MD0544.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1864.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1875.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1894.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1874.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1885.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1865.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1864.las",
"/Users/satoru/Downloads/pointcloud/tokyo/09LD1884.las",
// "/Users/satoru/Downloads/pointcloud/09LD1876.laz",
"/Users/satoru/Downloads/pointcloud/09LD1876.txt",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1864.las",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1875.las",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1894.las",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1874.las",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1885.las",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1865.las",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1864.las",
// "/Users/satoru/Downloads/pointcloud/tokyo/09LD1884.las",
"--output",
"/Users/satoru/Downloads/plateau/plateau-tutorial/output/3dtiles_tokyo_pointcloud",
"--epsg",
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Point Tiler

A tool for converting point cloud data into 3D Tiles v1.1.
A tool for converting point cloud data(las/laz and csv) into 3D Tiles v1.1.

## Usage

Expand Down
66 changes: 60 additions & 6 deletions app/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::ffi::OsStr;
use std::io::Write;
use std::{
fs,
Expand All @@ -17,13 +18,16 @@ use pcd_exporter::{
gltf::generate_quantized_glb,
tiling::{geometric_error, TileContent, TileTree},
};
use pcd_parser::parsers::csv::CsvParserProvider;
use pcd_parser::parsers::{get_extension, Extension};
use pcd_parser::parsers::{las::LasParserProvider, ParserProvider as _};
use pcd_transformer::{
builder::PointCloudTransformBuilder, runner::PointCloudTransformer, Transformer,
};
use projection_transform::cartesian::geodetic_to_geocentric;

use clap::Parser;
use projection_transform::crs::EpsgCode;
use rayon::iter::{IntoParallelIterator as _, ParallelIterator as _};

#[derive(Parser, Debug)]
Expand All @@ -50,6 +54,25 @@ struct Cli {
max: u8,
}

fn check_and_get_extension(paths: &[PathBuf]) -> Result<Extension, String> {
let mut extensions = vec![];
for path in paths.iter() {
let extension = path.extension().and_then(OsStr::to_str);
match extension {
Some(ext) => extensions.push(ext),
None => return Err("File extension is not found".to_string()),
}
}
extensions.sort();
extensions.dedup();

if extensions.len() > 1 {
return Err("Multiple extensions are not supported".to_string());
}

Ok(get_extension(extensions[0]))
}

fn main() {
Builder::new()
.format(|buf, record| {
Expand Down Expand Up @@ -81,17 +104,48 @@ fn main() {

log::info!("start parsing...");
let start_local = std::time::Instant::now();
let las_parser_provider = LasParserProvider {
filenames: input_files,
epsg: args.epsg,

let extension = check_and_get_extension(&input_files).unwrap();
let parser = match extension {
Extension::Las => {
let las_parser_provider = LasParserProvider {
filenames: input_files,
epsg: args.epsg,
};
let provider = las_parser_provider;
provider.get_parser()
}
Extension::Laz => {
let las_parser_provider = LasParserProvider {
filenames: input_files,
epsg: args.epsg,
};
let provider = las_parser_provider;
provider.get_parser()
}
Extension::Csv => {
let csv_parser_provider = CsvParserProvider {
filenames: input_files,
epsg: args.epsg,
};
let provider = csv_parser_provider;
provider.get_parser()
}
Extension::Txt => {
let csv_parser_provider = CsvParserProvider {
filenames: input_files,
epsg: args.epsg,
};
let provider = csv_parser_provider;
provider.get_parser()
}
_ => panic!("Unsupported extension"),
};
let output_epsg = 4979;
let provider = las_parser_provider;
let parser = provider.get_parser();
let point_cloud = parser.parse().unwrap();
log::info!("finish parsing in {:?}", start_local.elapsed());

log::info!("start transforming...");
let output_epsg = 4979;
let start_local = std::time::Instant::now();
let transform_builder = PointCloudTransformBuilder::new(output_epsg);
let transformer = PointCloudTransformer::new(Box::new(transform_builder));
Expand Down
1 change: 1 addition & 0 deletions pcd-parser/examples/read_csv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use pcd_parser::parsers::{csv::CsvParserProvider, ParserProvider as _};
fn main() {
let provider = CsvParserProvider {
filenames: vec![PathBuf::from("pcd-parser/examples/data/sample.txt")],
epsg: 6677,
};
let parser = provider.get_parser();

Expand Down
91 changes: 6 additions & 85 deletions pcd-parser/src/parsers/csv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,31 @@ use std::{collections::HashMap, error::Error, path::PathBuf};

use csv::ReaderBuilder;

use pcd_core::pointcloud::point::{
BoundingVolume, Color, Metadata, Point, PointAttributes, PointCloud,
};
use pcd_core::pointcloud::point::{Color, Point, PointAttributes, PointCloud};
use projection_transform::crs::EpsgCode;

use super::{Parser, ParserProvider};

pub struct CsvParserProvider {
pub filenames: Vec<PathBuf>,
pub epsg: EpsgCode,
}

impl ParserProvider for CsvParserProvider {
fn get_parser(&self) -> Box<dyn Parser> {
Box::new(CsvParser {
filenames: self.filenames.clone(),
epsg: self.epsg,
})
}
}

pub struct CsvParser {
pub filenames: Vec<PathBuf>,
pub epsg: EpsgCode,
}

pub static SCALE_FACTOR: f64 = 0.001;

impl Parser for CsvParser {
// TODO: LASパーサーのように、PointsからPointCloudを作成するように変更
fn parse(&self) -> Result<PointCloud, Box<dyn Error>> {
let start = std::time::Instant::now();
let mut reader = ReaderBuilder::new()
Expand All @@ -41,83 +40,6 @@ impl Parser for CsvParser {

let field_mapping = create_field_mapping(headers, has_headers).unwrap();

let mut bounding_volume = BoundingVolume {
min: [f64::MAX, f64::MAX, f64::MAX],
max: [f64::MIN, f64::MIN, f64::MIN],
};
let mut digits_x = 3;
let mut digits_y = 3;
let mut digits_z = 3;

let mut point_count = 0;

let start = std::time::Instant::now();
{
for record in reader.records() {
let record: csv::StringRecord = record.unwrap();

let x_str =
get_field_value(&record, &field_mapping, "x").ok_or("Missing 'x' field")?;
let y_str =
get_field_value(&record, &field_mapping, "y").ok_or("Missing 'y' field")?;
let z_str =
get_field_value(&record, &field_mapping, "z").ok_or("Missing 'z' field")?;

let x: f64 = x_str
.parse()
.map_err(|e| format!("Failed to parse 'x': {}", e))?;
let y: f64 = y_str
.parse()
.map_err(|e| format!("Failed to parse 'y': {}", e))?;
let z: f64 = z_str
.parse()
.map_err(|e| format!("Failed to parse 'z': {}", e))?;

bounding_volume.max[0] = bounding_volume.max[0].max(x);
bounding_volume.max[1] = bounding_volume.max[1].max(y);
bounding_volume.max[2] = bounding_volume.max[2].max(z);
bounding_volume.min[0] = bounding_volume.min[0].min(x);
bounding_volume.min[1] = bounding_volume.min[1].min(y);
bounding_volume.min[2] = bounding_volume.min[2].min(z);

for (value, digits) in [(x, &mut digits_x), (y, &mut digits_y), (z, &mut digits_z)]
{
let value_str = format!("{:.7}", value);
if let Some(dot_index) = value_str.find('.') {
let fractional_part = &value_str[dot_index + 1..];
let fractional_part = fractional_part.trim_end_matches('0');
*digits = *digits.max(&mut fractional_part.len());
}
}

point_count += 1;
}
}

let scale_x: f64 = format!("{:.*}", digits_x, 0.1_f64.powi(digits_x as i32)).parse()?;
let scale_y: f64 = format!("{:.*}", digits_y, 0.1_f64.powi(digits_y as i32)).parse()?;
let scale_z: f64 = format!("{:.*}", digits_z, 0.1_f64.powi(digits_z as i32)).parse()?;

let min_x = bounding_volume.min[0];
let min_y = bounding_volume.min[1];
let min_z = bounding_volume.min[2];

let offset_x = min_x;
let offset_y = min_y;
let offset_z = min_z;

let metadata = Metadata {
point_count,
bounding_volume,
epsg: 6677,
scale: [scale_x, scale_y, scale_z],
offset: [offset_x, offset_y, offset_z],
other: HashMap::new(),
};
println!("Calc bounding_volume time: {:?}", start.elapsed());

let start = std::time::Instant::now();
// TODO: 1度目のループで消費されてしまうので、再度読み込みを行っているが、改修が必要
let mut reader = ReaderBuilder::new()
.has_headers(true)
.from_path(&self.filenames[0])
Expand Down Expand Up @@ -181,9 +103,8 @@ impl Parser for CsvParser {
points.push(point);
}
}
println!("Parse CSV time: {:?}", start.elapsed());

let point_cloud = PointCloud { points, metadata };
let point_cloud = PointCloud::new(points, self.epsg);

Ok(point_cloud)
}
Expand Down
21 changes: 20 additions & 1 deletion pcd-parser/src/parsers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::error::Error;
use std::{error::Error, ffi::OsStr, path::PathBuf};

use las::LasParserProvider;
use pcd_core::pointcloud::point::PointCloud;
use projection_transform::crs::EpsgCode;

pub mod csv;
pub mod las;
Expand All @@ -12,3 +14,20 @@ pub trait ParserProvider {
pub trait Parser {
fn parse(&self) -> Result<PointCloud, Box<dyn Error>>;
}

pub enum Extension {
Las,
Laz,
Csv,
Txt,
}

pub fn get_extension(extension: &str) -> Extension {
match extension {
"las" => Extension::Las,
"laz" => Extension::Laz,
"csv" => Extension::Csv,
"txt" => Extension::Txt,
_ => panic!("Unsupported extension"),
}
}

0 comments on commit d9bc7c1

Please sign in to comment.