use glam::Vec2;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub type Point2D = Vec2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CurveKind {
Quad,
Cubic,
}
#[derive(Debug, Clone, Copy)]
pub struct ContourPoint {
pub point: Point2D,
pub on_curve: bool,
pub curve_kind: CurveKind,
}
impl ContourPoint {
pub fn new(point: Point2D, on_curve: bool) -> Self {
Self {
point,
on_curve,
curve_kind: CurveKind::Quad,
}
}
pub fn on_curve(point: Point2D) -> Self {
Self {
point,
on_curve: true,
curve_kind: CurveKind::Quad,
}
}
pub fn off_curve(point: Point2D) -> Self {
Self {
point,
on_curve: false,
curve_kind: CurveKind::Quad,
}
}
pub fn off_curve_cubic(point: Point2D) -> Self {
Self {
point,
on_curve: false,
curve_kind: CurveKind::Cubic,
}
}
}
#[derive(Debug, Clone)]
pub struct Contour {
pub points: Vec<ContourPoint>,
pub closed: bool,
}
impl Contour {
pub fn new(closed: bool) -> Self {
Self {
points: Vec::new(),
closed,
}
}
pub fn push(&mut self, point: ContourPoint) {
self.points.push(point);
}
pub fn push_on_curve(&mut self, point: Point2D) {
self.points.push(ContourPoint::on_curve(point));
}
pub fn push_off_curve(&mut self, point: Point2D) {
self.points.push(ContourPoint::off_curve(point));
}
pub fn is_empty(&self) -> bool {
self.points.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct Outline2D {
pub contours: Vec<Contour>,
}
impl Outline2D {
pub fn new() -> Self {
Self {
contours: Vec::new(),
}
}
pub fn add_contour(&mut self, contour: Contour) {
self.contours.push(contour);
}
pub fn is_empty(&self) -> bool {
self.contours.is_empty()
}
}
impl Default for Outline2D {
fn default() -> Self {
Self::new()
}
}
impl Outline2D {
#[inline]
pub fn triangulate(&self) -> crate::error::Result<Mesh2D> {
crate::triangulate::triangulate(self)
}
#[inline]
pub fn to_mesh_3d(&self, depth: f32) -> crate::error::Result<Mesh3D> {
let mesh_2d = self.triangulate()?;
crate::extrude::extrude(&mesh_2d, self, depth)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Mesh2D {
pub vertices: Vec<Point2D>,
pub indices: Vec<u32>,
}
impl Mesh2D {
#[must_use]
pub fn new() -> Self {
Self {
vertices: Vec::new(),
indices: Vec::new(),
}
}
#[must_use]
pub fn triangle_count(&self) -> usize {
self.indices.len() / 3
}
#[inline]
pub fn is_empty(&self) -> bool {
self.vertices.is_empty()
}
#[inline]
pub fn extrude(&self, outline: &Outline2D, depth: f32) -> crate::error::Result<Mesh3D> {
crate::extrude::extrude(self, outline, depth)
}
}
impl Default for Mesh2D {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Mesh3D {
pub vertices: Vec<glam::Vec3>,
pub normals: Vec<glam::Vec3>,
pub indices: Vec<u32>,
}
impl Mesh3D {
#[must_use]
pub fn new() -> Self {
Self {
vertices: Vec::new(),
normals: Vec::new(),
indices: Vec::new(),
}
}
#[must_use]
pub fn triangle_count(&self) -> usize {
self.indices.len() / 3
}
#[inline]
pub fn is_empty(&self) -> bool {
self.vertices.is_empty()
}
}
impl Default for Mesh3D {
fn default() -> Self {
Self::new()
}
}