use std::fmt::{Display, Formatter, Result};
#[derive(Debug, Clone, Default)]
pub struct Document {
pub unit: Option<Unit>,
pub version: Option<f64>,
pub lang: Option<String>,
pub objects: Vec<Object>,
pub materials: Vec<Material>,
pub textures: Vec<Texture>,
pub constellations: Vec<Constellation>,
pub metadatas: Vec<Metadata>,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub enum Unit {
Inch,
Millimeter,
#[default]
Meter,
Feet,
Micron,
}
#[derive(Debug, Clone, Default)]
pub struct Object {
pub id: u32,
pub colors: Vec<Color>,
pub mesh: Mesh,
pub metadatas: Vec<Metadata>,
}
#[derive(Debug, Clone, Default)]
pub struct Metadata {
pub r#type: String,
pub value: String,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Color {
pub r: String,
pub g: String,
pub b: String,
pub a: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct Mesh {
pub vertices: Vertices,
pub volume: Volume,
}
#[derive(Debug, Clone, Default)]
pub struct Vertices {
pub vertices: Vec<Vertex>,
pub edges: Vec<Edge>,
}
impl Vertices {
pub fn get_positions(&self) -> Vec<[f32; 3]> {
self.vertices.iter()
.map(|v| {
let coord = &v.coordinates;
[coord.x as f32, coord.z as f32, -coord.y as f32]
})
.collect()
}
pub fn get_normals(&self) -> Vec<[f32; 3]> {
self.vertices.iter().map(|v| {
if let Some(normal) = v.normals.first() {
[normal.nx as f32, normal.nz as f32, -normal.ny as f32]
} else {
[0.0, 0.0, 0.0]
}
}).collect()
}
}
#[derive(Debug, Clone, Default)]
pub struct Vertex {
pub metadatas: Vec<Metadata>,
pub coordinates: Coordinates,
pub colors: Vec<Color>,
pub normals: Vec<Normal>,
}
#[derive(Debug, Clone, Default)]
pub struct Coordinates {
pub x: f64,
pub y: f64,
pub z: f64,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Normal {
pub nx: f64,
pub ny: f64,
pub nz: f64,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Edge {
pub v1: u32,
pub dx1: f64,
pub dy1: f64,
pub dz1: f64,
pub v2: u32,
pub dx2: f64,
pub dy2: f64,
pub dz2: f64,
}
#[derive(Debug, Clone, Default)]
pub struct Volume {
pub material_id: Option<u32>,
pub r#type: Option<VolumeType>,
pub metadatas: Vec<Metadata>,
pub triangles: Vec<Triangle>,
pub colors: Vec<Color>,
}
impl Volume {
pub fn get_indices(&self) -> Vec<u32> {
self.triangles.iter()
.flat_map(|t| [t.v1, t.v2, t.v3])
.collect()
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub enum VolumeType {
#[default]
Object,
Support,
}
impl From<&str> for VolumeType {
fn from(value: &str) -> Self {
match value {
"object" => Self::Object,
"support" => Self::Support,
_ => Self::Object,
}
}
}
impl Display for VolumeType {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Self::Object => write!(f, "object"),
Self::Support => write!(f, "support"),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Triangle {
pub v1: u32,
pub v2: u32,
pub v3: u32,
pub texmap: Option<TexMap>,
pub colors: Vec<Color>,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct TexMap {
pub rtexid: Option<u32>,
pub gtexid: Option<u32>,
pub btexid: Option<u32>,
pub atexid: Option<u32>,
pub utex1: f64,
pub utex2: f64,
pub utex3: f64,
pub vtex1: f64,
pub vtex2: f64,
pub vtex3: f64,
pub wtex1: Option<f64>,
pub wtex2: Option<f64>,
pub wtex3: Option<f64>,
}
#[derive(Debug, Clone, Default)]
pub struct Material {
pub id: u32,
pub metadatas: Vec<Metadata>,
pub composites: Vec<Composite>,
}
#[derive(Debug, Clone, Default)]
pub struct Composite {
pub material_id: u32,
pub value: String,
}
#[derive(Debug, Clone, Default)]
pub struct Texture {
pub id: u32,
pub width: u32,
pub height: u32,
pub depth: u32,
pub tiled: bool,
pub r#type: TextureType,
pub value: String,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub enum TextureType {
#[default]
Grayscale,
}
impl From<&str> for TextureType {
fn from(value: &str) -> Self {
match value {
"grayscale" => Self::Grayscale,
_ => Self::Grayscale,
}
}
}
impl Display for TextureType {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Self::Grayscale => write!(f, "grayscale"),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Constellation {
pub id: u32,
pub instances: Vec<Instance>,
}
#[derive(Debug, Clone, Default)]
pub struct Instance {
pub object_id: u32,
pub deltax: Option<f64>,
pub deltay: Option<f64>,
pub deltaz: Option<f64>,
pub rx: Option<f64>,
pub ry: Option<f64>,
pub rz: Option<f64>,
}
impl Unit {
pub const SCALES: &[(Self, f64)] = &[
(Self::Millimeter, 1.0),
(Self::Inch, 25.4),
(Self::Feet, 304.8),
(Self::Meter, 1000.0),
(Self::Micron, 0.001),
];
}
impl From<&str> for Unit {
fn from(s: &str) -> Self {
match s.to_lowercase().as_str() {
"inch" => Unit::Inch,
"millimeter" | "mm" => Unit::Millimeter,
"meter" | "m" => Unit::Meter,
"feet" | "foot" | "ft" => Unit::Feet,
"micron" => Unit::Micron,
_ => Unit::Meter,
}
}
}
impl Display for Unit {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
Self::Millimeter => write!(f, "millimeter"),
Self::Inch => write!(f, "inch"),
Self::Feet => write!(f, "feet"),
Self::Meter => write!(f, "meter"),
Self::Micron => write!(f, "micron"),
}
}
}
impl Color {
pub fn white() -> Self {
Self {
r: "1.0".to_string(),
g: "1.0".to_string(),
b: "1.0".to_string(),
a: Some("1.0".to_string()),
}
}
pub fn black() -> Self {
Self {
r: "0.0".to_string(),
g: "0.0".to_string(),
b: "0.0".to_string(),
a: Some("1.0".to_string()),
}
}
pub fn red() -> Self {
Self {
r: "1.0".to_string(),
g: "0.0".to_string(),
b: "0.0".to_string(),
a: Some("1.0".to_string()),
}
}
pub fn green() -> Self {
Self {
r: "0.0".to_string(),
g: "1.0".to_string(),
b: "0.0".to_string(),
a: Some("1.0".to_string()),
}
}
pub fn blue() -> Self {
Self {
r: "0.0".to_string(),
g: "0.0".to_string(),
b: "1.0".to_string(),
a: Some("1.0".to_string()),
}
}
}
impl Default for Color {
fn default() -> Self {
Self::white()
}
}
impl Material {
pub fn new(id: u32) -> Self {
Self {
id,
metadatas: Vec::new(),
composites: Vec::new(),
}
}
pub fn set_name(&mut self, value: &str) {
self.metadatas.retain(|m| m.r#type != "name");
self.metadatas.push(Metadata {
r#type: "name".to_string(),
value: value.to_string(),
});
}
pub fn get_name(&self) -> Option<&str> {
self.metadatas
.iter()
.find(|m| m.r#type == "name")
.map(|m| m.value.as_str())
}
}
impl Volume {
pub fn new(material_id: Option<u32>) -> Self {
Self {
material_id,
r#type: None,
metadatas: Vec::new(),
triangles: Vec::new(),
colors: Vec::new(),
}
}
pub fn add_triangle(&mut self, triangle: Triangle) {
self.triangles.push(triangle);
}
pub fn set_name(&mut self, value: &str) {
self.metadatas.retain(|m| m.r#type != "name");
self.metadatas.push(Metadata {
r#type: "name".to_string(),
value: value.to_string(),
});
}
pub fn get_name(&self) -> Option<&str> {
self.metadatas
.iter()
.find(|m| m.r#type == "name")
.map(|m| m.value.as_str())
}
}
impl Mesh {
pub fn new() -> Self {
Self {
vertices: Vertices::default(),
volume: Volume::default(),
}
}
pub fn set_vertices(&mut self, vertices: Vec<Vertex>) {
self.vertices.vertices = vertices;
}
pub fn add_vertices(&mut self, vertices: Vec<Vertex>) {
self.vertices.vertices.extend(vertices);
}
pub fn set_edge(&mut self, edges: Vec<Edge>) {
self.vertices.edges = edges;
}
pub fn add_edge(&mut self, edges: Vec<Edge>) {
self.vertices.edges.extend(edges);
}
pub fn set_volume(&mut self, volume: Volume) {
self.volume = volume;
}
}
impl Object {
pub fn new(id: u32) -> Self {
Self {
id,
metadatas: Vec::new(),
colors: Vec::new(),
mesh: Mesh::new(),
}
}
pub fn set_name(&mut self, value: &str) {
self.metadatas.retain(|m| m.r#type != "name");
self.metadatas.push(Metadata {
r#type: "name".to_string(),
value: value.to_string(),
});
}
pub fn get_name(&self) -> Option<&str> {
self.metadatas
.iter()
.find(|m| m.r#type == "name")
.map(|m| m.value.as_str())
}
pub fn set_mesh(&mut self, mesh: Mesh) {
self.mesh = mesh;
}
}
impl Document {
pub fn new() -> Self {
Self {
unit: None,
version: None,
lang: None,
objects: Vec::new(),
materials: Vec::new(),
textures: Vec::new(),
constellations: Vec::new(),
metadatas: Vec::new(),
}
}
pub fn add_object(&mut self, object: Object) {
self.objects.push(object);
}
pub fn get_object(&self, id: u32) -> Option<&Object> {
self.objects.iter().find(|o| o.id == id)
}
pub fn get_object_mut(&mut self, id: u32) -> Option<&mut Object> {
self.objects.iter_mut().find(|o| o.id == id)
}
pub fn set_version(&mut self, value: f64) {
self.version = Some(value);
}
}