use std::{
fmt,
ops::{Index, IndexMut},
};
use crate::*;
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Clone, Hash)]
pub struct PointCloud2D<P>
where
P: Is2D,
{
pub data: Vec<P>,
}
impl<P> PointCloud2D<P>
where
P: Is2D,
{
pub fn new() -> PointCloud2D<P> {
PointCloud2D { data: Vec::new() }
}
pub fn with_capacity(n: usize) -> PointCloud2D<P> {
PointCloud2D {
data: Vec::with_capacity(n),
}
}
pub fn to_str(&self) -> String {
let mut result = String::new();
for p in &self.data {
result = result + &p.to_str() + "\n";
}
result
}
pub fn for_each_point<F>(&mut self, mut f: F)
where
F: FnMut(&mut P),
{
for p in &mut self.data {
f(&mut *p);
}
}
pub fn reserve_vertices(&mut self, n: usize) {
self.data.reserve(n)
}
}
impl<P> PointCloud2D<P>
where
P: IsBuildable2D + Clone,
{
pub fn parse(text: &str) -> Result<PointCloud2D<P>> {
let lines = text.split("\n").skip_empty_string();
let mut pc = PointCloud2D::new();
for line in lines {
P::parse(line).map(|p| pc.push(p))?;
}
if pc.len() == 0 {
return Err(ErrorKind::ParseError);
}
Ok(pc)
}
pub fn append_ra<RA>(&mut self, ra: &RA)
where
RA: IsRandomAccessible<P>,
{
let n = ra.len();
self.data.reserve(n);
for i in 0..n {
self.data.push(ra[i].clone());
}
}
}
impl<P> IsDataContainer<P> for PointCloud2D<P>
where
P: IsBuildable2D + Clone,
{
fn reserve_d(&mut self, n: usize) {
self.data.reserve(n);
}
fn len_d(&self) -> usize {
self.data.len()
}
fn push_d(&mut self, p: P) {
self.push(p)
}
fn get_d(&self, index: usize) -> P {
self.data[index].clone()
}
fn set_d(&mut self, index: usize, p: P) {
self.data[index] = p
}
}
impl<P> Index<usize> for PointCloud2D<P>
where
P: Is2D,
{
type Output = P;
fn index(&self, i: usize) -> &P {
&self.data[i]
}
}
impl<P> IndexMut<usize> for PointCloud2D<P>
where
P: Is2D,
{
fn index_mut(&mut self, i: usize) -> &mut P {
&mut self.data[i]
}
}
impl<P> IsRandomAccessible<P> for PointCloud2D<P>
where
P: Is2D,
{
fn len(&self) -> usize {
self.data.len()
}
}
impl<P> IsRandomInsertible<P> for PointCloud2D<P>
where
P: Is2D,
{
fn insert(&mut self, index: usize, point: P) -> Result<()> {
if index > self.len() {
Err(ErrorKind::IncorrectVertexID)
} else {
self.data.insert(index, point);
Ok(())
}
}
}
impl<P> IsPushable<P> for PointCloud2D<P>
where
P: Is2D,
{
fn push(&mut self, point: P) {
self.data.push(point)
}
fn reserve(&mut self, n: usize) {
self.data.reserve(n)
}
}
impl<P> IsMovable2D for PointCloud2D<P>
where
P: Is2D + IsMovable2D,
{
fn move_by(&mut self, x: f64, y: f64) {
for p in &mut self.data {
p.move_by(x, y);
}
}
}
impl<P> HasBoundingBox2DMaybe for PointCloud2D<P>
where
P: Is2D,
{
fn bounding_box_maybe(&self) -> Result<BoundingBox2D> {
BoundingBox2D::from_iterator(&self.data)
}
}
impl<P> HasCenterOfGravity2D for PointCloud2D<P>
where
P: Is2D,
{
fn center_of_gravity(&self) -> Result<Point2D> {
let size = self.len();
if size < 1 {
return Err(ErrorKind::TooFewPoints);
}
let sizef = size as f64;
let mut sumx: f64 = 0.0;
let mut sumy: f64 = 0.0;
for p in &self.data {
sumx += p.x();
sumy += p.y();
}
Ok(Point2D {
x: sumx / sizef,
y: sumy / sizef,
})
}
}
impl<P> HasLength for PointCloud2D<P>
where
P: Is2D,
{
fn length(&self) -> f64 {
let mut length: f64 = 0.0;
if self.data.len() < 2 {
return length;
}
for i in 1..self.data.len() {
length += dist_2d(&self.data[i], &self.data[i - 1]);
}
length
}
}
impl<P> IsViewBuildable for PointCloud2D<P>
where
P: Is2D + Clone,
{
fn apply_view(&mut self, view: &View) -> Result<()> {
self.data.apply_view(view)?;
Ok(())
}
fn from_view(&self, view: &View) -> Result<Self> {
let mut cloned = self.clone();
cloned.apply_view(view)?;
Ok(cloned)
}
}
impl<P> IsSortableND for PointCloud2D<P>
where
P: Is2D,
{
fn n_dimensions() -> usize {
2
}
fn sort_dim(&mut self, dimension: usize) -> Result<()> {
match dimension {
0 => {
self.sort_x();
Ok(())
}
1 => {
self.sort_y();
Ok(())
}
_ => Err(ErrorKind::IncorrectDimension),
}
}
}
impl<P> IsSortable2D for PointCloud2D<P>
where
P: Is2D,
{
fn sort_x(&mut self) {
sort_vec_2d_x(&mut self.data)
}
fn sort_y(&mut self) {
sort_vec_2d_y(&mut self.data)
}
}
impl<P> IsMergeable for PointCloud2D<P>
where
P: Is2D + Clone,
{
fn consume(&mut self, other: Self) {
for p in other.data {
self.data.push(p.clone());
}
}
fn combine(&self, other: &Self) -> Self {
let mut result = self.clone();
result.consume(other.clone());
result
}
}
impl<P> IsScalable for PointCloud2D<P>
where
P: IsEditable2D,
{
fn scale(&mut self, factor: Positive) {
if let Ok(bb) = self.bounding_box_maybe() {
let c = bb.center_bb();
for p in &mut self.data {
p.increase_distance_to_by(&c, factor);
}
}
}
}
impl<P> IsMatrix3Transformable for PointCloud2D<P>
where
P: Is2D + IsMatrix3Transformable + Clone,
{
fn transformed(&self, m: &Matrix3) -> Self {
let mut new = self.clone();
new.transform(m);
new
}
fn transform(&mut self, m: &Matrix3) {
for p in &mut self.data {
p.transform(m);
}
}
}
impl<P> Default for PointCloud2D<P>
where
P: Is2D,
{
fn default() -> Self {
let data = Vec::new();
PointCloud2D { data }
}
}
impl<P> fmt::Display for PointCloud2D<P>
where
P: Is2D + fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for p in &self.data {
p.fmt(f)?;
f.write_str("\n")?;
}
Ok(())
}
}
impl<P> Into<Vec<P>> for PointCloud2D<P>
where
P: Is2D,
{
fn into(self) -> Vec<P> {
self.data
}
}
impl<P> From<Vec<P>> for PointCloud2D<P>
where
P: Is2D,
{
fn from(data: Vec<P>) -> Self {
Self { data }
}
}