Skip to content

Commit

Permalink
Add basic regular polygon feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom committed Feb 25, 2024
1 parent 7e52fba commit 64d4a01
Show file tree
Hide file tree
Showing 4 changed files with 292 additions and 1 deletion.
67 changes: 67 additions & 0 deletions detailer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,17 @@ impl<'a> Widget<'a> {
pressure_angle,
meta,
),
Some(Feature::RegularPoly(meta, _p, n, a)) => {
Widget::show_selection_entry_regular_poly(
ui,
&mut commands,
&mut changed,
&k,
a,
n,
meta,
)
}
None => {}
}

Expand Down Expand Up @@ -959,6 +970,62 @@ impl<'a> Widget<'a> {
});
});
}

fn show_selection_entry_regular_poly(
ui: &mut egui::Ui,
commands: &mut Vec<ToolResponse>,
changed: &mut bool,
k: &FeatureKey,
apothem: &mut f32,
n: &mut usize,
meta: &mut FeatureMeta,
) {
ui.horizontal(|ui| {
let r = ui.available_size();
let text_height = egui::TextStyle::Body.resolve(ui.style()).size;

use slotmap::Key;
ui.add(
egui::Label::new(format!("n-poly {:?}", k.data()))
.wrap(false)
.truncate(true),
);
if r.x - ui.available_width() < FEATURE_NAME_WIDTH {
ui.add_space(FEATURE_NAME_WIDTH - (r.x - ui.available_width()));
}

*changed |= ui
.add(egui::Checkbox::without_text(&mut meta.construction))
.changed();
ui.add(egui::Image::new(CONSTRUCTION_IMG).rounding(5.0));

if ui.available_width() > r.x / 2. - ui.spacing().item_spacing.x {
ui.add_space(ui.available_width() - r.x / 2. - ui.spacing().item_spacing.x);
}

*changed |= ui
.add_sized(
[50., text_height * 1.4],
egui::DragValue::new(apothem)
.clamp_range(0.1..=200.0)
.suffix("mm")
.speed(0.2),
)
.changed();
*changed |= ui
.add_sized(
[50., text_height * 1.4],
egui::DragValue::new(n).clamp_range(3..=25).speed(1.0),
)
.changed();
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
if ui.button("⊗").clicked() {
commands.push(ToolResponse::Delete(*k));
}
});
});
}

fn show_groups_tab<F>(&mut self, ui: &mut egui::Ui, export_save: F)
where
F: FnOnce(&'static str, &'static str, Vec<u8>),
Expand Down
167 changes: 166 additions & 1 deletion drawing/src/feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct SerializedFeature {
pub x: f32,
pub y: f32,
pub r: f32,
pub n: Option<usize>,
pub gear_info: Option<GearInfo>,
}

Expand Down Expand Up @@ -57,6 +58,7 @@ pub enum Feature {
Arc(FeatureMeta, FeatureKey, FeatureKey, FeatureKey), // start, center, end
Circle(FeatureMeta, FeatureKey, f32), // center, radius
SpurGear(FeatureMeta, FeatureKey, GearInfo), // center, gear details
RegularPoly(FeatureMeta, FeatureKey, usize, f32), // center, num_sides, apothem
}

impl Default for Feature {
Expand All @@ -67,7 +69,7 @@ impl Default for Feature {

impl PartialEq<Feature> for Feature {
fn eq(&self, other: &Feature) -> bool {
use Feature::{Arc, Circle, LineSegment, Point, SpurGear};
use Feature::{Arc, Circle, LineSegment, Point, RegularPoly, SpurGear};
match (self, other) {
(Point(_, x1, y1), Point(_, x2, y2)) => x1 == x2 && y1 == y2,
(LineSegment(_, p00, p01), LineSegment(_, p10, p11)) => {
Expand Down Expand Up @@ -99,6 +101,9 @@ impl PartialEq<Feature> for Feature {
},
),
) => p0 == p1 && (m0 - m1).abs() < 0.005 && (pa0 - pa1).abs() < 0.005 && t0 == t1,
(RegularPoly(_, p0, n0, a0, ..), RegularPoly(_, p1, n1, a1, ..)) => {
p0 == p1 && n0 == n1 && (a1 - a0).abs() < 0.005
}
_ => false,
}
}
Expand All @@ -115,6 +120,7 @@ impl Feature {
Feature::Arc(meta, ..) => meta.construction,
Feature::Circle(meta, ..) => meta.construction,
Feature::SpurGear(meta, ..) => meta.construction,
Feature::RegularPoly(meta, ..) => meta.construction,
}
}

Expand All @@ -125,6 +131,7 @@ impl Feature {
Feature::Arc(_, p1, p2, p3) => [Some(*p1), Some(*p2), Some(*p3)],
Feature::Circle(_, p, ..) => [Some(*p), None, None],
Feature::SpurGear(_, p, ..) => [Some(*p), None, None],
Feature::RegularPoly(_, p, ..) => [Some(*p), None, None],
}
}

Expand Down Expand Up @@ -180,6 +187,11 @@ impl Feature {
.r_tip(),
)
}
Feature::RegularPoly(_, p, n, a, ..) => {
let p = drawing.features.get(*p).unwrap();
let r = a / (std::f32::consts::PI / *n as f32).cos();
p.bb(drawing).expand(r)
}
}
}

Expand Down Expand Up @@ -265,6 +277,20 @@ impl Feature {
.powi(2)
.min(((x_diff.powi(2) + y_diff.powi(2)).sqrt() - r_tip / vp.zoom).powi(2))
}

Feature::RegularPoly(_, p, n, a, ..) => {
let r = a / (std::f32::consts::PI / *n as f32).cos();

let p = vp.translate_point(match drawing.features.get(*p).unwrap() {
Feature::Point(_, x1, y1) => egui::Pos2 { x: *x1, y: *y1 },
_ => unreachable!(),
});
let (x_diff, y_diff) = (hp.x - p.x, hp.y - p.y);

((x_diff.powi(2) + y_diff.powi(2)).sqrt() - r / vp.zoom)
.powi(2)
.min(((x_diff.powi(2) + y_diff.powi(2)).sqrt() - a / vp.zoom).powi(2))
}
}
}

Expand Down Expand Up @@ -494,6 +520,42 @@ impl Feature {
}
}
}

Feature::RegularPoly(meta, p, n, a, ..) => {
let f = drawing.features.get(*p).unwrap();
let p = match f {
Feature::Point(_, x1, y1) => {
params.vp.translate_point(egui::Pos2 { x: *x1, y: *y1 })
}
_ => panic!("unexpected subkey type: {:?}", f),
};
let a = a / params.vp.zoom;

let stroke = egui::Stroke {
width: 1.,
color: if params.selected {
params.colors.selected
} else if params.hovered {
params.colors.hover
} else if meta.construction {
params.colors.line.gamma_multiply(0.35)
} else {
params.colors.line
},
};
use std::f32::consts::PI;
let r = a / (PI / *n as f32).cos();
let a = 2.0 * PI / *n as f32;

for i in 0..*n {
let x0 = r * (i as f32 * a).cos() + p.x;
let y0 = r * (i as f32 * a).sin() + p.y;
let x1 = r * ((i + 1) as f32 * a).cos() + p.x;
let y1 = r * ((i + 1) as f32 * a).sin() + p.y;

painter.line_segment([(x0, y0).into(), (x1, y1).into()], stroke);
}
}
}
}

Expand Down Expand Up @@ -562,6 +624,18 @@ impl Feature {
..SerializedFeature::default()
})
}
Feature::RegularPoly(meta, p, n, a) => {
let p_idx = fk_to_idx.get(p).ok_or(())?;

Ok(SerializedFeature {
kind: "regular_poly".to_string(),
meta: meta.clone(),
using_idx: vec![*p_idx],
r: *a,
n: Some(*n),
..SerializedFeature::default()
})
}
}
}

Expand Down Expand Up @@ -615,6 +689,20 @@ impl Feature {
sf.gear_info.unwrap(),
))
}
"regular_poly" => {
if sf.using_idx.len() < 1 {
return Err(());
}
if sf.n.is_none() {
return Err(());
}
Ok(Self::RegularPoly(
sf.meta,
*idx_to_fk.get(&sf.using_idx[0]).ok_or(())?,
sf.n.unwrap(),
sf.r,
))
}
_ => Err(()),
}
}
Expand Down Expand Up @@ -738,6 +826,35 @@ impl Feature {
p.x as f64, p.y as f64,
)));
}

Feature::RegularPoly(_meta, p, n, a, ..) => {
let f = drawing.features.get(*p).unwrap();
let p = match f {
Feature::Point(_, x1, y1) => egui::Pos2 { x: *x1, y: *y1 },
_ => panic!("unexpected subkey type: {:?}", f),
};

use std::f32::consts::PI;
let r = a / (PI / *n as f32).cos();
let a = 2.0 * PI / *n as f32;

for i in 0..(*n + 1) {
let x = r * (i as f32 * a).cos() + p.x;
let y = r * (i as f32 * a).sin() + p.y;

if i == 0 {
out.move_to(kurbo::Point {
x: x as f64,
y: y as f64,
});
} else {
out.line_to(kurbo::Point {
x: x as f64,
y: y as f64,
});
}
}
}
};
out
}
Expand Down Expand Up @@ -786,6 +903,15 @@ impl Feature {
y: 0.0,
}
}

Feature::RegularPoly(_, p, n, a) => {
// TODO: fixme
drawing.features.get(*p).unwrap().start_point(drawing)
+ egui::Vec2 {
x: a / (std::f32::consts::PI / *n as f32).cos(),
y: 0.0,
}
}
}
}

Expand Down Expand Up @@ -832,6 +958,15 @@ impl Feature {
y: 0.0,
}
}

Feature::RegularPoly(_, p, n, a) => {
// TODO: fixme
drawing.features.get(*p).unwrap().start_point(drawing)
+ egui::Vec2 {
x: a / (std::f32::consts::PI / *n as f32).cos(),
y: 0.0,
}
}
}
}
}
Expand Down Expand Up @@ -897,6 +1032,18 @@ mod tests {
..SerializedFeature::default()
}),
);
assert_eq!(
Feature::RegularPoly(FeatureMeta::default(), point_key, 6, 6.9)
.serialize(&HashMap::from([(point_key, 42)])),
Ok(SerializedFeature {
kind: "regular_poly".to_string(),
meta: FeatureMeta::default(),
using_idx: vec![42],
r: 6.9,
n: Some(6),
..SerializedFeature::default()
}),
);
}

#[test]
Expand Down Expand Up @@ -960,5 +1107,23 @@ mod tests {
6.9,
)),
);
assert_eq!(
Feature::deserialize(
SerializedFeature {
kind: "regular_poly".to_string(),
using_idx: vec![1],
r: 6.9,
n: Some(6),
..SerializedFeature::default()
},
&HashMap::from([(1, FeatureKey::null())]),
),
Ok(Feature::RegularPoly(
FeatureMeta::default(),
FeatureKey::null(),
6,
6.9,
)),
);
}
}
11 changes: 11 additions & 0 deletions drawing/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum ToolResponse {
NewArc(FeatureKey, FeatureKey),
NewCircle(FeatureKey, egui::Pos2),
NewSpurGear(FeatureKey),
NewRegularPoly(FeatureKey),
Delete(FeatureKey),

NewFixedConstraint(FeatureKey),
Expand Down Expand Up @@ -135,6 +136,16 @@ impl Handler {
drawing.features.insert(g);
tools.clear();
}
ToolResponse::NewRegularPoly(p_center) => {
let g = Feature::RegularPoly(FeatureMeta::default(), p_center, 6, 4.0);

if drawing.feature_exists(&g) {
return;
}

drawing.features.insert(g);
tools.clear();
}

ToolResponse::Delete(k) => {
drawing.delete_feature(k);
Expand Down
Loading

0 comments on commit 64d4a01

Please sign in to comment.