Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Former glory #97

Closed
wants to merge 14 commits into from
1,917 changes: 1,713 additions & 204 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ cargo test
Simple exaples using the rust code can be found in `packages/cadmium/examples`

Run simple rust example with:
```

```shell
cargo run --example project_simple_extrusion
```

Expand Down
4 changes: 2 additions & 2 deletions applications/web/src/components/AppBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@

<div class="flex-grow flex flex-row-reverse gap-4 mr-4">
<div>
<a href="https://discord.com/invite/qJCsKJeyZv" target="_blank"><DiscordLogo class="h-6 w-6"/></a>
<a href="https://discord.com/invite/qJCsKJeyZv" target="_blank"><DiscordLogo class="h-6 w-6" /></a>
</div>
<div>
<a href="https://github.com/mattferraro/cadmium" target="_blank"><GithubLogo class="h-6 w-6"/></a>
<a href="https://github.com/mattferraro/cadmium" target="_blank"><GithubLogo class="h-6 w-6" /></a>
</div>
</div>
</div>
Expand Down
18 changes: 18 additions & 0 deletions packages/cadmium-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ pub fn message_handler_derive(input: proc_macro::TokenStream) -> proc_macro::Tok
_ => panic!("MessageEnum can only be derived for enums"),
};

let variants_type = data.variants.iter().map(|variant| {
let syn::Fields::Unnamed(field) = &variant.fields else {
panic!("MessageEnum can only be derived for enums with unnamed fields");
};

let field_type = &field.unnamed[0].ty;
quote! { #field_type }
}).collect::<Vec<_>>();

let variants = data.variants.iter().map(|variant| {
println!("Message Handler: {}", variant.ident);
let variant_name = &variant.ident;
Expand All @@ -21,6 +30,7 @@ pub fn message_handler_derive(input: proc_macro::TokenStream) -> proc_macro::Tok

let variant_names = data.variants.iter().map(|variant| &variant.ident).collect::<Vec<_>>();
let variants_clone = variants.clone();
let variants_clone2 = variants.clone();

quote! {
impl #name {
Expand All @@ -31,6 +41,14 @@ pub fn message_handler_derive(input: proc_macro::TokenStream) -> proc_macro::Tok
}
}

#(
impl From<#variants_type> for #name {
fn from(msg: #variants_type) -> Self {
#variants_clone2
}
}
)*

impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down
12 changes: 6 additions & 6 deletions packages/cadmium/examples/project_simple_extrusion.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use cadmium::workbench::AddSketch;
use cadmium::solid::extrusion::{self, Direction, Mode};
use cadmium::feature::extrusion::{self, Direction, Mode};
use cadmium::project::Project;
use cadmium::message::MessageHandler as _;
use cadmium::isketch::{AddLine, AddPoint};
use cadmium::isketch::primitive::{AddLine, AddPoint};
use cadmium::archetypes::PlaneDescription;

fn main() {
Expand All @@ -22,12 +22,12 @@ fn main() {
AddLine { start: ur, end: ul }.handle_message(sketch.clone()).unwrap();
AddLine { start: ul, end: ll }.handle_message(sketch.clone()).unwrap();

let faces = sketch.borrow().sketch().borrow().get_faces();
extrusion::Add { sketch_id, faces, length: 25.0, offset: 0.0, direction: Direction::Normal, mode: Mode::New }.handle_message(wb_ref.clone()).unwrap();
extrusion::Add { sketch_id, faces: vec![0], length: 25.0, offset: 0.0, direction: Direction::Normal, mode: Mode::New }.handle_message(wb_ref.clone()).unwrap();

let wb = wb_ref.borrow();
let solid_ref = wb.solids.first_key_value().unwrap().1;
let solid = solid_ref.borrow();
let feature_ref = wb.features.first_key_value().unwrap().1;
let solid_like = feature_ref.borrow().as_solid_like().to_solids().unwrap();
let solid = solid_like.get(0).unwrap();

println!("{:?}", solid);

Expand Down
2 changes: 1 addition & 1 deletion packages/cadmium/src/archetypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use truck_modeling::Plane as TruckPlane;
use truck_modeling::InnerSpace;

use crate::solid::point::Point3;
use crate::feature::point::Point3;
use crate::IDType;

#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::cell::RefCell;
use std::cell::{RefCell, RefMut};
use std::rc::Rc;

use isotope::decompose::face::Face;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use truck_modeling::builder;
use tsify_next::Tsify;
Expand All @@ -15,9 +16,7 @@ use crate::workbench::Workbench;
use crate::IDType;

use super::get_isoface_wires;
use super::Feature;
use super::FeatureCell;
use super::SolidLike;
use super::{Feature, SolidLike};

#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
#[tsify(into_wasm_abi, from_wasm_abi)]
Expand Down Expand Up @@ -67,7 +66,7 @@ impl Extrusion {
}

impl SolidLike for Extrusion {
fn references(&self) -> Vec<FeatureCell> {
fn references(&self) -> Vec<Rc<RefCell<Feature>>> {
// self.faces.iter().map(|f| FeatureCell::Face(f.clone())).collect()
todo!("Extrusion::references")
}
Expand All @@ -93,7 +92,7 @@ impl SolidLike for Extrusion {
Ok(self.faces
.iter()
.map(|f| {
let wires = get_isoface_wires(self.sketch.clone(), f).unwrap();
let wires = get_isoface_wires(self.sketch.clone(), &f).unwrap();
let face = builder::try_attach_plane(&wires).unwrap();

// Can we calculate ALL the wires at once and not iter-sweep?
Expand All @@ -105,11 +104,25 @@ impl SolidLike for Extrusion {
}
}

impl<'a> TryFrom<&'a mut Feature> for &'a mut Extrusion {
type Error = anyhow::Error;

// The Feature enum has only 1 variant for now but that will change soon
#[allow(irrefutable_let_patterns)]
fn try_from(value: &'a mut Feature) -> Result<Self, Self::Error> {
let Feature::Extrusion(ref mut extrusion) = value else {
return Err(anyhow::anyhow!("Failed to convert Feature to Extrusion"))
};

Ok(extrusion)
}
}

#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
#[tsify(from_wasm_abi, into_wasm_abi)]
pub struct Add {
pub sketch_id: IDType,
pub faces: Vec<Face>, // TODO: This should be a list of face IDs
pub faces: Vec<IDType>,
pub length: f64,
pub offset: f64,
pub direction: Direction,
Expand All @@ -124,21 +137,86 @@ impl MessageHandler for Add {
let sketch = workbench.get_sketch_by_id(self.sketch_id)?;

let extrusion = Extrusion::new(
self.faces.clone(),
vec![],
sketch.clone(),
self.length,
self.offset,
self.direction.clone(),
self.mode.clone(),
);

// TODO: This is incorrect. We should adding Features to the workbench, not solids
// Until then we can't update or remove as we don't know which solids are associated with this extrusion
extrusion.to_solids()?.iter().for_each(|solid| {
let id = workbench.solids_next_id;
workbench.solids.insert(id, Rc::new(RefCell::new(solid.clone())));
workbench.solids_next_id += 1;
});
let id = workbench.features_next_id;
workbench.features.insert(id, Rc::new(RefCell::new(extrusion.to_feature())));
workbench.features_next_id += 1;
let id = workbench.features_next_id - 1;
drop(workbench);

// We can't keep the workbench borrow during the UpdateFaces
// as it also needs a mutable borrow of the workbench
UpdateFaces {
extrusion_id: id,
sketch_id: self.sketch_id,
faces: self.faces.clone(),
}.handle_message(workbench_ref.clone())?;

Ok(Some(id))
}
}

#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
#[tsify(from_wasm_abi, into_wasm_abi)]
pub struct UpdateFaces {
pub extrusion_id: IDType,
pub sketch_id: IDType,
pub faces: Vec<IDType>,
}

impl MessageHandler for UpdateFaces {
// Parent to workbench to add to solids and be able to reference the sketch
type Parent = Rc<RefCell<Workbench>>;
fn handle_message(&self, workbench_ref: Self::Parent) -> anyhow::Result<Option<IDType>> {
let workbench = workbench_ref.borrow_mut();
let sketch = workbench.get_sketch_by_id(self.sketch_id)?;
let feature_ref = workbench.features.get(&self.extrusion_id).ok_or(anyhow::anyhow!("No feature with ID {} was found", self.extrusion_id))?;
let mut extrusion: RefMut<'_, Extrusion> = RefMut::map(feature_ref.borrow_mut(), |f| f.try_into().unwrap());

let faces = sketch.borrow()
.sketch().borrow()
.get_faces()
.iter()
.enumerate()
.filter_map(|(id, f)| if self.faces.contains(&(id as IDType)) {
Some(f.clone())
} else {
None
})
.collect_vec();

extrusion.faces = faces;

Ok(None)
}
}

#[derive(Tsify, Debug, Clone, Serialize, Deserialize)]
#[tsify(from_wasm_abi, into_wasm_abi)]
pub struct UpdateForm {
pub length: f64,
pub offset: f64,
pub direction: Direction,
pub mode: Mode,
}

impl MessageHandler for UpdateForm {
// Parent to workbench to add to solids and be able to reference the sketch
type Parent = Rc<RefCell<Feature>>;
fn handle_message(&self, feature_ref: Self::Parent) -> anyhow::Result<Option<IDType>> {
let mut extrusion: RefMut<'_, Extrusion> = RefMut::map(feature_ref.borrow_mut(), |f| f.try_into().unwrap());

extrusion.length = self.length;
extrusion.offset = self.offset;
extrusion.direction = self.direction.clone();
extrusion.mode = self.mode.clone();

Ok(None)
}
Expand Down Expand Up @@ -175,7 +253,7 @@ mod tests {
// get a realization
let workbench_ref = p.get_workbench_by_id(0).unwrap();
let workbench = workbench_ref.borrow();
let solids = &workbench.solids;
let solids = &workbench.features;
println!("[{}] solids: {:?}", file, solids.len());

assert_eq!(solids.len(), *expected_solids); // doesn't work yet!
Expand All @@ -187,7 +265,8 @@ mod tests {
let p = create_test_project();
let workbench_ref = p.get_workbench_by_id(0).unwrap();
let workbench = workbench_ref.borrow();
let solid = workbench.solids.get(&0).unwrap().borrow();
let feature = workbench.features.get(&0).unwrap().borrow();
let solid = &feature.as_solid_like().to_solids().unwrap()[0];

solid.save_as_step("pkg/test.step");
solid.save_as_obj("pkg/test.obj", 0.001);
Expand Down
57 changes: 57 additions & 0 deletions packages/cadmium/src/feature/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::cell::RefCell;
use std::fmt::Debug;
use std::rc::Rc;

use serde::Deserialize;
use serde::Serialize;
use tsify_next::Tsify;

use crate::message::Identifiable;
use crate::workbench::Workbench;
use crate::IDType;

pub mod extrusion;
pub mod helpers;
pub mod point;
pub mod prelude;
pub mod solid;

use prelude::*;

pub trait SolidLike: Debug {
fn references(&self) -> Vec<Rc<RefCell<Feature>>>;
fn get_truck_solids(&self) -> anyhow::Result<Vec<TruckClosedSolid>>;
fn to_feature(&self) -> Feature;

fn to_solids(&self) -> anyhow::Result<Vec<Solid>> {
let truck_solids = self.get_truck_solids()?;

Ok(truck_solids.iter().map(|truck_solid| {
Solid::from_truck_solid("".to_owned(), truck_solid.clone())
}).collect())
}
}

#[derive(Tsify, Debug, Serialize, Deserialize, Clone)]
#[tsify(into_wasm_abi, from_wasm_abi)]
#[non_exhaustive]
pub enum Feature {
Extrusion(extrusion::Extrusion),
}

impl Feature {
pub fn as_solid_like(&self) -> &dyn SolidLike {
match self {
Feature::Extrusion(extrusion) => extrusion,
}
}
}

impl Identifiable for Rc<RefCell<Feature>> {
type Parent = Rc<RefCell<Workbench>>;
const ID_NAME: &'static str = "feature_id";

fn from_parent_id(parent: &Self::Parent, id: IDType) -> anyhow::Result<Self> {
Ok(parent.borrow().features.get(&id).ok_or(anyhow::anyhow!("No feature with ID {} was found", id))?.clone())
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
pub use super::helpers::*;
pub use super::solid::Solid;

pub const MESH_TOLERANCE: f64 = 0.1;

pub use isotope::decompose::face::Face as ISOFace;

pub use truck_modeling::Face as TruckFace;
Expand All @@ -20,5 +25,3 @@ pub type TruckClosedSolid = TruckTopoSolid<
truck_modeling::Curve,
truck_modeling::Surface,
>;

pub use super::helpers::*;
Loading