Skip to content

Commit

Permalink
parse rgb
Browse files Browse the repository at this point in the history
  • Loading branch information
nokonoko1203 committed Nov 20, 2024
1 parent d9bc7c1 commit 0f7a3e1
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 42 deletions.
11 changes: 8 additions & 3 deletions app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use pcd_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 Down Expand Up @@ -139,9 +138,15 @@ fn main() {
let provider = csv_parser_provider;
provider.get_parser()
}
_ => panic!("Unsupported extension"),
};
let point_cloud = parser.parse().unwrap();
let point_cloud = match parser.parse() {
Ok(point_cloud) => point_cloud,
Err(e) => {
log::error!("Failed to parse point cloud: {:?}", e);
return;
}
};
// let point_cloud = parser.parse();
log::info!("finish parsing in {:?}", start_local.elapsed());

log::info!("start transforming...");
Expand Down
1 change: 0 additions & 1 deletion pcd-core/src/pointcloud/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ pub struct Color {
// LAS data coordinates are expressed in u32 format
// The actual coordinates are calculated based on a combination of scale and offset, as follows
// x = (x * scale[0]) + offset[0]
// TODO: カラーが存在しないデータに対応
#[derive(Debug, Clone)]
pub struct Point {
pub x: f64,
Expand Down
1 change: 0 additions & 1 deletion pcd-exporter/src/gltf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ pub fn generate_glb<'a>(
let mut gltf_buffer_views = Vec::new();
let mut gltf_accessors = Vec::new();

// TODO: カラーが存在しないデータに対応
const BYTE_STRIDE: usize = (4 * 3) + (3 + 1);

let buffer_offset = bin_content.len();
Expand Down
103 changes: 69 additions & 34 deletions pcd-parser/src/parsers/csv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ pub struct CsvParser {

impl Parser for CsvParser {
fn parse(&self) -> Result<PointCloud, Box<dyn Error>> {
let start = std::time::Instant::now();
let mut reader = ReaderBuilder::new()
.has_headers(true)
.from_path(&self.filenames[0])
.unwrap();
println!("Read CSV time: {:?}", start.elapsed());

let headers = reader.headers().unwrap();
let has_headers = !headers.iter().all(|h| h.trim().is_empty());
Expand Down Expand Up @@ -66,31 +64,66 @@ impl Parser for CsvParser {
.parse()
.map_err(|e| format!("Failed to parse 'z': {}", e))?;

let color = Color {
r: parse_optional_field(&record, &field_mapping, "r")?.unwrap_or(65535),
g: parse_optional_field(&record, &field_mapping, "g")?.unwrap_or(65535),
b: parse_optional_field(&record, &field_mapping, "b")?.unwrap_or(65535),
};

let r = parse_optional_field(&record, &field_mapping, "r")
.or_else(|| parse_optional_field(&record, &field_mapping, "red"))
.unwrap_or("65535".to_string())
.parse::<f64>()
.map_err(|e| format!("Failed to parse 'r': {}", e))?
.floor() as u16;

let g = parse_optional_field(&record, &field_mapping, "g")
.or_else(|| parse_optional_field(&record, &field_mapping, "green"))
.unwrap_or("65535".to_string())
.parse::<f64>()
.map_err(|e| format!("Failed to parse 'g': {}", e))?
.floor() as u16;

let b = parse_optional_field(&record, &field_mapping, "b")
.or_else(|| parse_optional_field(&record, &field_mapping, "blue"))
.unwrap_or("65535".to_string())
.parse::<f64>()
.map_err(|e| format!("Failed to parse 'b': {}", e))?
.floor() as u16;

let color = Color { r, g, b };

// TODO: 将来的に実装する
let attributes = PointAttributes {
intensity: parse_optional_field(&record, &field_mapping, "intensity")?,
return_number: parse_optional_field(&record, &field_mapping, "return_number")?,
classification: get_field_value(&record, &field_mapping, "classification")
.map(|v| v.to_string()),
scanner_channel: parse_optional_field(
&record,
&field_mapping,
"scanner_channel",
)?,
scan_angle: parse_optional_field(&record, &field_mapping, "scan_angle")?,
user_data: parse_optional_field(&record, &field_mapping, "user_data")?,
point_source_id: parse_optional_field(
&record,
&field_mapping,
"point_source_id",
)?,
gps_time: parse_optional_field(&record, &field_mapping, "gps_time")?,
intensity: None,
return_number: None,
classification: None,
scanner_channel: None,
scan_angle: None,
user_data: None,
point_source_id: None,
gps_time: None,
};
// let attributes = PointAttributes {
// intensity: parse_optional_field(&record, &field_mapping, "intensity")
// .unwrap_or(None),
// return_number: parse_optional_field(&record, &field_mapping, "return_number")
// .unwrap_or(None),
// classification: get_field_value(&record, &field_mapping, "classification")
// .map(|v| v.to_string()),
// scanner_channel: parse_optional_field(
// &record,
// &field_mapping,
// "scanner_channel",
// )
// .unwrap_or(None),
// scan_angle: parse_optional_field(&record, &field_mapping, "scan_angle")
// .unwrap_or(None),
// user_data: parse_optional_field(&record, &field_mapping, "user_data")
// .unwrap_or(None),
// point_source_id: parse_optional_field(
// &record,
// &field_mapping,
// "point_source_id",
// )
// .unwrap_or(None),
// gps_time: parse_optional_field(&record, &field_mapping, "gps_time")
// .unwrap_or(None),
// };

let point = Point {
x,
Expand Down Expand Up @@ -131,11 +164,15 @@ fn create_field_mapping(
"r",
"g",
"b",
"red",
"green",
"blue",
];

if has_headers {
for (index, header) in headers.iter().enumerate() {
let normalized_header = header.to_lowercase().replace("_", "").replace("-", "");

for attr_name in &attribute_names {
let normalized_attr = attr_name.to_lowercase().replace("_", "").replace("-", "");
if normalized_header == normalized_attr {
Expand Down Expand Up @@ -169,27 +206,25 @@ fn get_field_value<'a>(
field_name: &str,
) -> Option<&'a str> {
if let Some(&index) = field_mapping.get(field_name) {
record.get(index)
let value = record.get(index);
value
} else {
None
}
}

fn parse_optional_field<T: std::str::FromStr>(
fn parse_optional_field(
record: &csv::StringRecord,
field_mapping: &HashMap<String, usize>,
field_name: &str,
) -> Result<Option<T>, Box<dyn Error>> {
) -> Option<String> {
if let Some(value_str) = get_field_value(record, field_mapping, field_name) {
if value_str.trim().is_empty() {
Ok(None)
None
} else {
let value = value_str
.parse::<T>()
.map_err(|_| format!("Failed to parse '{}'", field_name))?;
Ok(Some(value))
Some(value_str.to_string())
}
} else {
Ok(None)
None
}
}
4 changes: 1 addition & 3 deletions pcd-parser/src/parsers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::{error::Error, ffi::OsStr, path::PathBuf};
use std::error::Error;

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

pub mod csv;
pub mod las;
Expand Down

0 comments on commit 0f7a3e1

Please sign in to comment.