Skip to content

Commit

Permalink
projection transform
Browse files Browse the repository at this point in the history
  • Loading branch information
nokonoko1203 committed Nov 11, 2024
1 parent c3fc8e7 commit 7be09f8
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,28 @@ use std::path::PathBuf;

use pcd_parser::parsers::{las::LasParserProvider, ParserProvider as _};
use pcd_transformer::{
builder::ProjectionTransformerBuilder,
builder::PointCloudTransformBuilder,
runner::{PointCloudTransformer, Transformer},
TransformBuilder as _,
};

fn main() {
let las_parser_provider = LasParserProvider {
filenames: vec![PathBuf::from(
"pcd-transformer/examples/data/sample.las".to_string(),
)],
epsg: 10170,
};
let provider = las_parser_provider;
let parser = provider.get_parser();
let point_cloud = parser.parse().unwrap();

let builder = ProjectionTransformerBuilder;
let transform = builder.build();
let transformer = PointCloudTransformer::new(transform);
let transform_builder = PointCloudTransformBuilder::new(4979);
let transformer = PointCloudTransformer::new(Box::new(transform_builder));

let transformed = transformer.execute(point_cloud);

for (i, pc) in transformed.iter().enumerate() {
println!("PointCloud {}:", i);
for point in &pc.points {
println!(" Point(x: {}, y: {}, z: {})", point.x, point.y, point.z);
}
println!(" Point(x: {}, y: {}, z: {})", pc.0, pc.1, pc.2);
}
}
32 changes: 25 additions & 7 deletions pcd-transformer/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
use crate::transform::{CompositeTransform, Transform};
use std::sync::Arc;

use projection_transform::{crs::EpsgCode, vshift::Jgd2011ToWgs84};

use crate::transform::{projection::ProjectionTransform, SerialTransform, Transform};

pub trait TransformBuilder {
fn build(&self) -> Box<dyn Transform>;
}

pub struct ProjectionTransformerBuilder;
pub struct PointCloudTransformBuilder {
output_epsg: EpsgCode,
jgd2wgs: Arc<Jgd2011ToWgs84>,
}

impl TransformBuilder for ProjectionTransformerBuilder {
impl TransformBuilder for PointCloudTransformBuilder {
fn build(&self) -> Box<dyn Transform> {
let projection_transform =
Box::new(crate::transform::projection::ProjectionTransform::new());
let mut transformers = SerialTransform::default();

let composite = CompositeTransform::new(vec![projection_transform]);
transformers.push(Box::new(ProjectionTransform::new(
self.jgd2wgs.clone(),
self.output_epsg,
)));

Box::new(transformers)
}
}

Box::new(composite)
impl PointCloudTransformBuilder {
pub fn new(output_epsg: EpsgCode) -> Self {
Self {
output_epsg,
jgd2wgs: Jgd2011ToWgs84::default().into(),
}
}
}
15 changes: 8 additions & 7 deletions pcd-transformer/src/runner.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
use pcd_core::pointcloud::point::PointCloud;

use crate::transform::Transform;
use crate::TransformBuilder;

pub trait Transformer {
fn execute(&self, point_cloud: PointCloud) -> Vec<PointCloud>;
fn execute(&self, point_cloud: PointCloud) -> PointCloud;
}

pub struct PointCloudTransformer {
transform: Box<dyn Transform>,
builder: Box<dyn TransformBuilder>,
}

impl PointCloudTransformer {
pub fn new(transform: Box<dyn Transform>) -> Self {
Self { transform }
pub fn new(builder: Box<dyn TransformBuilder>) -> Self {
Self { builder }
}
}

impl Transformer for PointCloudTransformer {
fn execute(&self, point_cloud: PointCloud) -> Vec<PointCloud> {
self.transform.transform(point_cloud)
fn execute(&self, point_cloud: PointCloud) -> PointCloud {
let transform = self.builder.build();
transform.transform(point_cloud)
}
}
32 changes: 13 additions & 19 deletions pcd-transformer/src/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,26 @@ use pcd_core::pointcloud::point::PointCloud;
pub mod projection;

pub trait Transform {
fn transform(&self, point_cloud: PointCloud) -> Vec<PointCloud>;
fn transform(&self, point_cloud: PointCloud) -> PointCloud;
}

pub struct CompositeTransform {
#[derive(Default)]
pub struct SerialTransform {
transforms: Vec<Box<dyn Transform>>,
}

impl CompositeTransform {
pub fn new(transforms: Vec<Box<dyn Transform>>) -> Self {
Self { transforms }
}
}

impl Transform for CompositeTransform {
fn transform(&self, point_cloud: PointCloud) -> Vec<PointCloud> {
let mut intermediate = vec![point_cloud];

impl Transform for SerialTransform {
fn transform(&self, point_cloud: PointCloud) -> PointCloud {
let mut transformed = point_cloud;
for transform in &self.transforms {
let mut next_stage = Vec::new();
for pc in intermediate {
let transformed = transform.transform(pc);
next_stage.extend(transformed);
}
intermediate = next_stage;
transformed = transform.transform(transformed);
}
transformed
}
}

intermediate
impl SerialTransform {
pub fn push(&mut self, transform: Box<dyn Transform>) {
self.transforms.push(transform);
}
}
92 changes: 28 additions & 64 deletions pcd-transformer/src/transform/projection.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::sync::Arc;

use pcd_core::pointcloud::point::PointCloud;
use pcd_core::pointcloud::point::{Point, PointCloud};
use projection_transform::{
crs::*, etmerc::ExtendedTransverseMercatorProjection, jprect::JPRZone, vshift::Jgd2011ToWgs84,
};
Expand All @@ -14,7 +14,7 @@ pub struct ProjectionTransform {
}

impl Transform for ProjectionTransform {
fn transform(&self, point_cloud: PointCloud) -> Vec<PointCloud> {
fn transform(&self, point_cloud: PointCloud) -> PointCloud {
let input_epsg = point_cloud.metadata.epsg;

match input_epsg {
Expand All @@ -31,7 +31,7 @@ impl Transform for ProjectionTransform {
| EPSG_JGD2011_JPRECT_XI_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_XII_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_XIII_JGD2011_HEIGHT => {
self.transform_from_jgd2011(&point_cloud, Some(input_epsg));
self.transform_from_jgd2011(point_cloud, None)
}
_ => {
panic!("Unsupported input CRS: {}", input_epsg);
Expand Down Expand Up @@ -59,73 +59,37 @@ impl ProjectionTransform {
(lng, lat, height)
}

fn transform_from_jgd2011(&mut self, point_cloud: &PointCloud, rectangular: Option<EpsgCode>) {
fn transform_from_jgd2011(
&self,
point_cloud: PointCloud,
rectangular: Option<EpsgCode>,
) -> PointCloud {
let mut points = vec![];
match self.output_epsg {
EPSG_JGD2011_JPRECT_I_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_II_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_III_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_IV_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_V_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_VI_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_VII_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_VIII_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_IX_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_X_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_XI_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_XII_JGD2011_HEIGHT
| EPSG_JGD2011_JPRECT_XIII_JGD2011_HEIGHT => {
// To Japan Plane Rectangular CS + JGD2011 (vertical) height
let proj = self.jpr_zone_proj.as_ref().unwrap();
let mut geom_store = entity.geometry_store.write().unwrap();
geom_store.vertices.iter_mut().for_each(|v| {
let (lng, lat) = (v[1], v[0]);
if let Some(input_epsg) = rectangular {
(v[0], v[1], v[2]) =
Self::rectangular_to_lnglat(v[0], v[1], v[2], input_epsg);
};
// Change x and y; keep the height
// TODO: error handling
(v[0], v[1], _) = proj.project_forward(lng, lat, 0.).unwrap();
});
geom_store.epsg = self.output_epsg;
}
EPSG_JGD2011_JPRECT_I
| EPSG_JGD2011_JPRECT_II
| EPSG_JGD2011_JPRECT_III
| EPSG_JGD2011_JPRECT_IV
| EPSG_JGD2011_JPRECT_V
| EPSG_JGD2011_JPRECT_VI
| EPSG_JGD2011_JPRECT_VII
| EPSG_JGD2011_JPRECT_VIII
| EPSG_JGD2011_JPRECT_IX
| EPSG_JGD2011_JPRECT_X
| EPSG_JGD2011_JPRECT_XI
| EPSG_JGD2011_JPRECT_XII
| EPSG_JGD2011_JPRECT_XIII
| EPSG_JGD2011_JPRECT_XIV
| EPSG_JGD2011_JPRECT_XV
| EPSG_JGD2011_JPRECT_XVI
| EPSG_JGD2011_JPRECT_XVII
| EPSG_JGD2011_JPRECT_XVIII
| EPSG_JGD2011_JPRECT_XIX => {
// To Japan Plane Rectangular CS
let proj = self.jpr_zone_proj.as_ref().unwrap();
let mut geom_store = entity.geometry_store.write().unwrap();
geom_store.vertices.iter_mut().for_each(|v| {
let (lng, lat) = (v[1], v[0]);
if let Some(input_epsg) = rectangular {
(v[0], v[1], v[2]) =
Self::rectangular_to_lnglat(v[0], v[1], v[2], input_epsg);
EPSG_WGS84_GEOGRAPHIC_3D => {
for (x, y, z, point) in point_cloud.iter() {
// Swap x and y (lat, lng -> lng, lat)
let (lng, lat, height) = (y, x, z);
let (lng, lat, height) = if let Some(input_epsg) = rectangular {
Self::rectangular_to_lnglat(lng, lat, height, input_epsg)
} else {
(lng, lat, height)
};
// Change x and y; keep the height
// TODO: error handling
(v[0], v[1], _) = proj.project_forward(lng, lat, 0.).unwrap();
});
geom_store.epsg = self.output_epsg;
// JGD2011 to WGS 84 (elevation to ellipsoidal height)
let (lng, lat, height) = self.jgd2wgs.convert(lng, lat, height);
points.push(Point {
x: lng,
y: lat,
z: height,
color: point.color.clone(),
attributes: point.attributes.clone(),
});
}
}
_ => {
panic!("Unsupported output CRS: {}", self.output_epsg);
}
};
PointCloud::new(points, self.output_epsg)
}
}

0 comments on commit 7be09f8

Please sign in to comment.