diff --git a/packages/cadmium/src/main.rs b/packages/cadmium/src/main.rs index 7ee55d21..a2c0f742 100644 --- a/packages/cadmium/src/main.rs +++ b/packages/cadmium/src/main.rs @@ -7,7 +7,7 @@ use cadmium::extrusion::fuse; use cadmium::oplog::EvolutionLog; use cadmium::oplog::Operation; use cadmium::project::Plane; -use cadmium::{oplog, Realization}; +use cadmium::{oplog, sketch, Realization}; use truck_meshalgo::filters::OptimizingFilter; use truck_meshalgo::tessellation::{MeshableShape, MeshedShape}; use truck_modeling::builder::{translated, tsweep, vertex}; @@ -20,45 +20,103 @@ use truck_topology::{Shell, Solid}; fn main() { let mut el = EvolutionLog::new(); - el.append(Operation::NewPlane { + + // Create the Top Plane + let top_plane_id = el.append(Operation::CreatePlane { + nonce: "a".to_string(), + }); + // Note that top_plane_id is just a sha. the plane doesn't have any unique ID outside of its commit sha + el.append(Operation::SetPlaneName { + plane_id: top_plane_id.clone(), + name: "Top".to_string(), + }); + el.append(Operation::SetPlane { + plane_id: top_plane_id.clone(), + plane: Plane::top(), + }); + + // Create the Front Plane + let front_plane_id = el.append(Operation::CreatePlane { + nonce: "b".to_string(), + }); + el.append(Operation::SetPlaneName { + plane_id: front_plane_id.clone(), name: "Front".to_string(), + }); + el.append(Operation::SetPlane { + plane_id: front_plane_id.clone(), plane: Plane::front(), }); - let new_sketch_hash = el.append(Operation::NewSketch { + + // Create the main sketch + let sketch_id = el.append(Operation::CreateSketch { + nonce: "a".to_string(), + }); + let name_sketch_commit = el.append(Operation::SetSketchName { + sketch_id: sketch_id.clone(), name: "Sketch1".to_string(), - unique_id: "qwerty".to_string(), - plane_name: "Front".to_string(), }); - el.append(Operation::NewRectangle { - sketch_id: "qwerty".to_string(), + let set_sketch_plane_commit = el.append(Operation::SetSketchPlane { + sketch_id: sketch_id.clone(), + plane_id: front_plane_id.clone(), + }); + + el.append(Operation::AddSketchRectangle { + sketch_id: sketch_id.clone(), x: 0.0, y: 0.0, width: 100.0, height: 100.0, }); - let extrude_sha = el.append(Operation::NewExtrusion { + + let extrusion_id = el.append(Operation::CreateExtrusion { + nonce: "c".to_string(), + }); + let name_ext_commit = el.append(Operation::SetExtrusionName { + extrusion_id: extrusion_id.clone(), name: "Extrude1".to_string(), - unique_id: "abc123".to_string(), - sketch_id: "qwerty".to_string(), - click_x: 50.0, - click_y: 50.0, - depth: 100.0, + }); + let set_ext_sketch_commit = el.append(Operation::SetExtrusionSketch { + extrusion_id: extrusion_id.clone(), + sketch_id: sketch_id.clone(), + }); + let set_ext_clicks_commit = el.append(Operation::SetExtrusionClicks { + extrusion_id: extrusion_id.clone(), + clicks: vec![(50.0, 50.0)], + }); + let finished_rectangle_commit = el.append(Operation::SetExtrusionDepth { + extrusion_id: extrusion_id.clone(), + depth: 10.0, }); - // Actually, let's try something different - el.checkout(new_sketch_hash); - el.append(Operation::NewCircle { - sketch_id: "qwerty".to_string(), + // Oops, our sketch was on the wrong plane. Fix that! + let rotated_rectangle_commit = el.append(Operation::SetSketchPlane { + sketch_id: sketch_id.clone(), + plane_id: front_plane_id, + }); + + // Actually, let's try an alternate approach using a circle instead of a rectangle + el.checkout(sketch_id.clone()); + + // Re-use the commits that specified the sketch name and plane + el.cherry_pick(name_sketch_commit); + el.cherry_pick(set_sketch_plane_commit); + + // Add a circle to the sketch + el.append(Operation::AddSketchCircle { + sketch_id: sketch_id.clone(), x: 50.0, y: 50.0, radius: 50.0, }); - el.cherry_pick(extrude_sha); - el.append(Operation::ModifyExtrusionDepth { - unique_id: "abc123".to_string(), - depth: 200.0, - }); + // Re-use all the extrusion commits + el.cherry_pick(extrusion_id); + el.cherry_pick(name_ext_commit); + el.cherry_pick(set_ext_sketch_commit); + el.cherry_pick(set_ext_clicks_commit); + let finished_circle_commit = el.cherry_pick(finished_rectangle_commit).unwrap(); + let rotated_circle_commit = el.cherry_pick(rotated_rectangle_commit).unwrap(); el.pretty_print(); } diff --git a/packages/cadmium/src/oplog/mod.rs b/packages/cadmium/src/oplog/mod.rs index f9be398c..bdf10506 100644 --- a/packages/cadmium/src/oplog/mod.rs +++ b/packages/cadmium/src/oplog/mod.rs @@ -79,23 +79,33 @@ impl EvolutionLog { } } - pub fn checkout(&mut self, sha: Sha) -> Result<(), String> { + pub fn checkout(&mut self, sha: Sha) -> Result { // check that the sha exists in the oplog before doing this for commit in &self.oplog.commits { if commit.id == sha { self.cursor = sha; - return Ok(()); + return Ok(self.cursor.clone()); } } Err(format!("SHA {} not found in oplog", sha)) } - pub fn cherry_pick(&mut self, sha: Sha) -> Result<(), String> { + pub fn cherry_pick(&mut self, sha: Sha) -> Result { // check that the sha exists in the oplog before doing this for commit in &self.oplog.commits { if commit.id == sha { - self.append(commit.operation.clone()); - return Ok(()); + let new_operation = commit.operation.clone(); + let mut new_commit_id = self.append(commit.operation.clone()); + + // If the original commit created an entity, we'll need to create an alias commit + if new_operation.is_create() { + new_commit_id = self.append(Operation::Alias { + original: sha, + new: new_commit_id.clone(), + }); + } + + return Ok(new_commit_id); } } Err(format!("SHA {} not found in oplog", sha)) @@ -141,43 +151,80 @@ pub enum Operation { description: String, commit: Sha, }, - NewPlane { + Alias { + original: Sha, + new: Sha, + }, + + CreatePlane { + nonce: String, + }, + SetPlaneName { + plane_id: Sha, name: String, + }, + SetPlane { + plane_id: Sha, plane: Plane, }, - NewSketch { + + CreateSketch { + nonce: String, + }, + SetSketchName { + sketch_id: Sha, name: String, - plane_name: String, - unique_id: String, }, - NewRectangle { - sketch_id: String, + SetSketchPlane { + sketch_id: Sha, + plane_id: Sha, + }, + + AddSketchRectangle { + sketch_id: Sha, x: f64, y: f64, width: f64, height: f64, }, - NewCircle { - sketch_id: String, + AddSketchCircle { + sketch_id: Sha, x: f64, y: f64, radius: f64, }, - NewExtrusion { + + CreateExtrusion { + nonce: String, + }, + SetExtrusionName { + extrusion_id: Sha, name: String, - unique_id: String, - sketch_id: String, - click_x: f64, - click_y: f64, - depth: f64, }, - ModifyExtrusionDepth { - unique_id: String, + SetExtrusionSketch { + extrusion_id: Sha, + sketch_id: Sha, + }, + SetExtrusionClicks { + extrusion_id: Sha, + clicks: Vec<(f64, f64)>, + }, + SetExtrusionDepth { + extrusion_id: Sha, depth: f64, }, } impl Operation { + pub fn is_create(&self) -> bool { + match self { + Operation::CreatePlane { .. } => true, + Operation::CreateSketch { .. } => true, + Operation::CreateExtrusion { .. } => true, + _ => false, + } + } + pub fn hash(&self) -> Sha { let mut hasher = Sha256::new(); @@ -188,40 +235,58 @@ impl Operation { description, commit, } => hasher.update(format!("{description}-{commit}").as_bytes()), - Operation::NewPlane { name, plane } => { - hasher.update(format!("{name}-{plane:?}").as_bytes()) + Operation::Alias { original, new } => { + hasher.update(format!("{original}-{new}").as_bytes()) + } + Operation::CreatePlane { nonce } => hasher.update(format!("{nonce}").as_bytes()), + Operation::SetPlaneName { plane_id, name } => { + hasher.update(format!("{plane_id}-{name}").as_bytes()) } - Operation::NewSketch { - name, - plane_name, - unique_id, - } => hasher.update(format!("{name}-{plane_name:?}-{unique_id}").as_bytes()), - Operation::NewRectangle { + Operation::SetPlane { plane_id, plane } => { + hasher.update(format!("{plane_id}-{plane:?}").as_bytes()) + } + Operation::CreateSketch { nonce } => hasher.update(format!("{nonce}").as_bytes()), + Operation::SetSketchName { sketch_id, name } => { + hasher.update(format!("{sketch_id}-{name}").as_bytes()) + } + Operation::SetSketchPlane { + sketch_id, + plane_id, + } => hasher.update(format!("{sketch_id}-{plane_id}").as_bytes()), + Operation::AddSketchRectangle { sketch_id, x, y, width, height, } => hasher.update(format!("{sketch_id}-{x}-{y}-{width}-{height}").as_bytes()), - Operation::NewCircle { + Operation::AddSketchCircle { sketch_id, x, y, radius, } => hasher.update(format!("{sketch_id}-{x}-{y}-{radius}").as_bytes()), - Operation::NewExtrusion { - name, - unique_id, + Operation::CreateExtrusion { nonce } => hasher.update(format!("{nonce}").as_bytes()), + Operation::SetExtrusionName { extrusion_id, name } => { + hasher.update(format!("{extrusion_id}-{name}").as_bytes()) + } + Operation::SetExtrusionSketch { + extrusion_id, sketch_id, - click_x, - click_y, - depth, - } => hasher.update( - format!("{name}-{unique_id}-{sketch_id}-{click_x}-{click_y}-{depth}").as_bytes(), - ), - Operation::ModifyExtrusionDepth { unique_id, depth } => { - hasher.update(format!("{unique_id}-{depth}").as_bytes()) + } => hasher.update(format!("{extrusion_id}-{sketch_id}").as_bytes()), + Operation::SetExtrusionClicks { + extrusion_id, + clicks, + } => { + hasher.update(format!("{extrusion_id}").as_bytes()); + for (x, y) in clicks { + hasher.update(format!("{x}-{y}").as_bytes()) + } } + Operation::SetExtrusionDepth { + extrusion_id, + depth, + } => hasher.update(format!("{extrusion_id}-{depth}").as_bytes()), } format!("{:x}", hasher.finalize()) @@ -233,47 +298,118 @@ impl Operation { Operation::Describe { description, commit, - } => format!("Describe: {} '{}'", commit, description), - Operation::NewPlane { name, plane } => format!("NewPlane: '{}'", name), - Operation::NewSketch { - name, - plane_name, - unique_id, + } => format!( + "Describe: {} '{}'", + commit.to_owned()[..10].to_string(), + description + ), + Operation::Alias { original, new } => { + format!( + "Alias: from {} to {}", + original.to_owned()[..10].to_string(), + new.to_owned()[..10].to_string() + ) + } + Operation::CreatePlane { nonce } => format!("CreatePlane: {}", nonce), + Operation::SetPlaneName { plane_id, name } => { + format!( + "SetPlaneName: {} '{}'", + plane_id.to_owned()[..10].to_string(), + name + ) + } + Operation::SetPlane { plane_id, plane } => { + format!( + "SetPlane: {} {:?}", + plane_id.to_owned()[..10].to_string(), + plane + ) + } + Operation::CreateSketch { nonce } => format!("CreateSketch: {}", nonce), + Operation::SetSketchName { sketch_id, name } => { + format!( + "SetSketchName: {} '{}'", + sketch_id.to_owned()[..10].to_string(), + name + ) + } + Operation::SetSketchPlane { + sketch_id, + plane_id, } => { - format!("NewSketch: '{}' on plane '{}'", name, plane_name) + format!( + "SetSketchPlane: {} {}", + sketch_id.to_owned()[..10].to_string(), + plane_id.to_owned()[..10].to_string() + ) } - Operation::NewRectangle { + Operation::AddSketchRectangle { sketch_id, x, y, width, height, } => format!( - "NewRectangle: {} {} {} {} on '{}'", - x, y, width, height, sketch_id + "AddSketchRectangle: {} ({}, {}) {}x{}", + sketch_id.to_owned()[..10].to_string(), + x, + y, + width, + height ), - Operation::NewCircle { + Operation::AddSketchCircle { sketch_id, x, y, radius, } => format!( - "NewCircle: ({},{}) radius: {} on '{}'", - x, y, radius, sketch_id + "AddSketchCircle: {} ({}, {}) r={}", + sketch_id.to_owned()[..10].to_string(), + x, + y, + radius ), - Operation::NewExtrusion { - name, - unique_id, + Operation::CreateExtrusion { nonce } => format!("CreateExtrusion: {}", nonce), + Operation::SetExtrusionName { extrusion_id, name } => { + format!( + "SetExtrusionName: {} '{}'", + extrusion_id.to_owned()[..10].to_string(), + name + ) + } + Operation::SetExtrusionSketch { + extrusion_id, sketch_id, - click_x, - click_y, + } => { + format!( + "SetExtrusionSketch: {} {}", + extrusion_id.to_owned()[..10].to_string(), + sketch_id.to_owned()[..10].to_string() + ) + } + Operation::SetExtrusionClicks { + extrusion_id, + clicks, + } => { + let mut click_str = String::new(); + for (x, y) in clicks { + click_str.push_str(&format!("({}, {}) ", x, y)); + } + format!( + "SetExtrusionClicks: {} {}", + extrusion_id.to_owned()[..10].to_string(), + click_str + ) + } + Operation::SetExtrusionDepth { + extrusion_id, depth, - } => format!( - "NewExtrusion: '{}' on '{}' ({},{}) depth: {}", - name, sketch_id, click_x, click_y, depth - ), - Operation::ModifyExtrusionDepth { unique_id, depth } => { - format!("ModifyExtrusionDepth: {} to {}", unique_id, depth) + } => { + format!( + "SetExtrusionDepth: {} {}", + extrusion_id.to_owned()[..10].to_string(), + depth + ) } } }