#[cfg(feature = "derive_serdes")]
use serde::{Deserialize, Serialize};
use crate::geometry;
use super::*;
type LinearBasis2 <S> = NonZero2 <S>;
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PlanarBasis2 <S> (Matrix2 <S>);
type LinearBasis3 <S> = NonZero3 <S>;
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PlanarBasis3 <S> ([NonZero3 <S>; 2]);
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct EntireBasis3 <S> (Matrix3 <S>);
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Line2 <S> {
pub origin : Point2 <S>,
pub basis : LinearBasis2 <S>
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Plane2 <S> {
pub origin : Point2 <S>,
pub basis : PlanarBasis2 <S>
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Line3 <S> {
pub origin : Point3 <S>,
pub basis : LinearBasis3 <S>
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Plane3 <S> {
pub origin : Point3 <S>,
pub basis : PlanarBasis3 <S>
}
#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Space3 <S> {
pub origin : Point3 <S>,
pub basis : EntireBasis3 <S>
}
impl <S : Ring> Line2 <S> {
pub fn point (&self, coordinate : S) -> Point2 <S> {
self.origin + *self.basis * coordinate
}
}
impl <S : OrderedRing> From <geometry::Line2 <S>> for Line2 <S> {
fn from (line : geometry::Line2 <S>) -> Self {
line.affine_line()
}
}
impl <S : OrderedRing> From <geometry::Ray2 <S>> for Line2 <S> {
fn from (ray : geometry::Ray2 <S>) -> Self {
ray.affine_line()
}
}
impl <S : OrderedRing> From <geometry::Segment2 <S>> for Line2 <S> {
fn from (segment : geometry::Segment2 <S>) -> Self {
segment.affine_line()
}
}
impl <S : Ring> Plane2 <S> {
pub fn point (&self, coordinates : Vector2 <S>) -> Point2 <S> {
self.origin + *self.basis * coordinates
}
}
impl <S : OrderedField> From <geometry::Triangle2 <S>> for Plane2 <S> {
fn from (triangle : geometry::Triangle2 <S>) -> Self {
triangle.affine_plane()
}
}
impl <S : Ring> Line3 <S> {
pub fn point (&self, coordinate : S) -> Point3 <S> {
self.origin + *self.basis * coordinate
}
}
impl <S : OrderedRing> From <geometry::Line3 <S>> for Line3 <S> {
fn from (line : geometry::Line3 <S>) -> Self {
line.affine_line()
}
}
impl <S : OrderedRing> From <geometry::Ray3 <S>> for Line3 <S> {
fn from (ray : geometry::Ray3 <S>) -> Self {
ray.affine_line()
}
}
impl <S : OrderedRing> From <geometry::Segment3 <S>> for Line3 <S> {
fn from (segment : geometry::Segment3 <S>) -> Self {
segment.affine_line()
}
}
impl <S : Ring> Plane3 <S> {
pub fn point (&self, coordinates : Vector2 <S>) -> Point3 <S> {
self.origin + *self.basis[0] * coordinates.x + *self.basis[1] * coordinates.y
}
}
impl <S : OrderedField> From <geometry::Triangle3 <S>> for Plane3 <S> {
fn from (triangle : geometry::Triangle3 <S>) -> Self {
triangle.affine_plane()
}
}
impl <S> Space3 <S> {
pub fn point (&self, coordinates : Vector3 <S>) -> Point3 <S> where S : Ring {
self.origin + *self.basis * coordinates
}
}
impl <S : Field> PlanarBasis2 <S> {
pub fn new (basis : Matrix2 <S>) -> Option <Self> {
if LinearIso::is_invertible (basis) {
Some (PlanarBasis2 (basis))
} else {
None
}
}
}
impl <S> std::ops::Deref for PlanarBasis2 <S> {
type Target = Matrix2 <S>;
fn deref (&self) -> &Self::Target {
&self.0
}
}
impl <S : OrderedRing> PlanarBasis3 <S> {
pub fn new (basis : [NonZero3 <S>; 2]) -> Option <Self> {
if *basis[0].cross (*basis[1]).self_dot() != S::zero() {
Some (PlanarBasis3 (basis))
} else {
None
}
}
}
impl <S> std::ops::Deref for PlanarBasis3 <S> {
type Target = [NonZero3 <S>; 2];
fn deref (&self) -> &Self::Target {
&self.0
}
}
impl <S : Field> EntireBasis3 <S> {
pub fn new (basis : Matrix3 <S>) -> Option <Self> {
if LinearIso::is_invertible (basis) {
Some (EntireBasis3 (basis))
} else {
None
}
}
}
impl <S> std::ops::Deref for EntireBasis3 <S> {
type Target = Matrix3 <S>;
fn deref (&self) -> &Self::Target {
&self.0
}
}