use ogeom_algo::{Built, make_prism, make_revolution};
use ogeom_core::{OgeomResult, Tolerances, ogeom_bail};
use ogeom_math::{Axis, Vector};
use ogeom_topo::{Model, Shape, ShapeType};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Feature {
Added,
Removed,
}
pub fn feature_prism(
model: &mut Model,
solid: &Shape,
profile: &Shape,
vector: Vector,
sense: Feature,
tol: Tolerances,
) -> OgeomResult<Built> {
if model.kind_of(profile)? != ShapeType::Face {
ogeom_bail!(
Construction,
"a form feature sweeps a face; a wire is the boundary of one, \
not a tool"
);
}
let tool = make_prism(model, profile, vector, tol)?;
applied(model, solid, &tool.shape, profile, sense, tol)
}
pub fn feature_revol(
model: &mut Model,
solid: &Shape,
profile: &Shape,
axis: Axis,
angle: f64,
sense: Feature,
tol: Tolerances,
) -> OgeomResult<Built> {
if model.kind_of(profile)? != ShapeType::Face {
ogeom_bail!(
Construction,
"a form feature turns a face; a wire is the boundary of one, \
not a tool"
);
}
let tool = make_revolution(model, profile, axis, angle, tol)?;
applied(model, solid, &tool.shape, profile, sense, tol)
}
pub fn feature_rib(
model: &mut Model,
solid: &Shape,
profile: &Shape,
normal: Vector,
thickness: f64,
tol: Tolerances,
) -> OgeomResult<Built> {
if !thickness.is_finite() || thickness <= tol.confusion() {
ogeom_bail!(Construction, "a rib of {thickness} thickness holds nothing");
}
let magnitude = normal.magnitude();
if magnitude <= tol.confusion() {
ogeom_bail!(Construction, "a rib needs a direction to stand in");
}
feature_prism(
model,
solid,
profile,
normal / magnitude * thickness,
Feature::Added,
tol,
)
}
pub fn feature_slot(
model: &mut Model,
solid: &Shape,
profile: &Shape,
along: Vector,
depth: f64,
tol: Tolerances,
) -> OgeomResult<Built> {
if !depth.is_finite() || depth <= tol.confusion() {
ogeom_bail!(Construction, "a slot of depth {depth} cuts nothing");
}
let magnitude = along.magnitude();
if magnitude <= tol.confusion() {
ogeom_bail!(Construction, "a slot needs a direction to run in");
}
let direction = along / magnitude;
let started = ogeom_algo::transformed(
model,
profile,
ogeom_math::Transform::translation(-direction * depth),
)?;
feature_prism(
model,
solid,
&started.shape,
direction * (depth * 2.0),
Feature::Removed,
tol,
)
}
fn applied(
model: &mut Model,
solid: &Shape,
tool: &Shape,
profile: &Shape,
sense: Feature,
tol: Tolerances,
) -> OgeomResult<Built> {
let mut result = match sense {
Feature::Added => ogeom_bool::fuse(model, solid, tool, tol)?,
Feature::Removed => ogeom_bool::cut(model, solid, tool, tol)?,
};
result.history.generate(profile, result.shape.clone());
Ok(result)
}