mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
Compare commits
2 Commits
render
...
release-0.16.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ddf48ca16 | |||
| d2f6848377 |
Generated
+17
-17
@@ -4078,7 +4078,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"block2 0.6.2",
|
||||
"eframe",
|
||||
@@ -4109,11 +4109,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-3dx-client"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-cli"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"image",
|
||||
"serde_json",
|
||||
@@ -4124,7 +4124,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-derive"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4133,7 +4133,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-doc"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -4150,7 +4150,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-engine"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -4167,7 +4167,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-geom"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4176,7 +4176,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-gpu"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"naga",
|
||||
@@ -4193,7 +4193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-io"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"cadmpeg-core",
|
||||
"cadmpeg-ir",
|
||||
@@ -4213,7 +4213,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-kernel"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"proptest",
|
||||
@@ -4233,7 +4233,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-mcp"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"solidcraft-engine",
|
||||
@@ -4242,7 +4242,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-render"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"image",
|
||||
"moxcms",
|
||||
@@ -4256,7 +4256,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-sketch"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4267,11 +4267,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-space-mouse"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-ui-egui"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"egui",
|
||||
@@ -4296,7 +4296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-web"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"eframe",
|
||||
"egui",
|
||||
@@ -5826,7 +5826,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ members = ["crates/*", "apps/*", "xtask"]
|
||||
exclude = ["vendor"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
rust-version = "1.95"
|
||||
|
||||
@@ -849,47 +849,18 @@ pub fn zoom_sign(app: &SolveApp) -> f64 {
|
||||
}
|
||||
|
||||
/// The model point under a screen position. Over empty space: the centre of the visible bodies
|
||||
/// and sketches (what Fit frames) while it is on screen; zoomed in so far that it isn't, the
|
||||
/// model point at the view's centre, so what you look at stays in view (#2138); and the view's
|
||||
/// centre when neither is there.
|
||||
/// and sketches (what Fit frames), or the view's centre when nothing is visible.
|
||||
pub(crate) fn pivot_under(app: &SolveApp, proj: &crate::viewport::Proj, at: Pos2) -> Vec3 {
|
||||
let under = |at: Pos2| {
|
||||
use crate::viewport::Hit;
|
||||
crate::viewport::pick(app, proj, at).into_iter().find_map(|h| match h {
|
||||
Hit::Face { point, .. } | Hit::Vertex { point, .. } => Some(point),
|
||||
// The point of the edge under the cursor: a long edge's midpoint can be far off screen.
|
||||
Hit::Edge { body, index, mid } => Some(edge_point_near(app, proj, &body, index, at).unwrap_or(mid)),
|
||||
_ => None,
|
||||
})
|
||||
};
|
||||
if let Some(p) = under(at) {
|
||||
return p;
|
||||
}
|
||||
let b = crate::viewport::view_bounds(app);
|
||||
if !b.is_empty() && proj.to_screen(b.center()).is_some_and(|s| proj.rect.contains(s)) {
|
||||
return b.center();
|
||||
}
|
||||
under(proj.rect.center()).unwrap_or(app.cam.target)
|
||||
}
|
||||
|
||||
/// The point of a body's edge nearest `at` on screen (each segment of its polyline measured on
|
||||
/// screen, the nearest point taken along the segment in the model).
|
||||
fn edge_point_near(app: &SolveApp, proj: &crate::viewport::Proj, body: &str, index: usize, at: Pos2) -> Option<Vec3> {
|
||||
let st = app.session.world_state();
|
||||
let mesh = st.body(body)?.mesh();
|
||||
let edge = mesh.edges.get(index)?;
|
||||
let mut best: Option<(f32, Vec3)> = None;
|
||||
for w in edge.windows(2) {
|
||||
let (Some(a), Some(b)) = (w.first().copied(), w.get(1).copied()) else { continue };
|
||||
let (Some(sa), Some(sb)) = (proj.to_screen(a), proj.to_screen(b)) else { continue };
|
||||
let d = sb - sa;
|
||||
let t = if d.length_sq() > 1e-6 { ((at - sa).dot(d) / d.length_sq()).clamp(0.0, 1.0) } else { 0.0 };
|
||||
let dist = (sa + d * t).distance(at);
|
||||
if best.is_none_or(|(bd, _)| dist < bd) {
|
||||
best = Some((dist, a + (b - a) * f64::from(t)));
|
||||
use crate::viewport::Hit;
|
||||
for h in crate::viewport::pick(app, proj, at) {
|
||||
match h {
|
||||
Hit::Face { point, .. } | Hit::Vertex { point, .. } => return point,
|
||||
Hit::Edge { mid, .. } => return mid,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
best.map(|(_, p)| p)
|
||||
let b = crate::viewport::view_bounds(app);
|
||||
if b.is_empty() { app.cam.target } else { b.center() }
|
||||
}
|
||||
|
||||
/// A plain number typed into a field, with a decimal point or a decimal comma (#1347): "2.5"
|
||||
@@ -2424,35 +2395,6 @@ mod tests {
|
||||
assert_eq!(app.viewport.orbit_pivot, Some(solidcraft_engine::geom::Vec3::new(5.0, -3.0, 2.0)));
|
||||
}
|
||||
|
||||
/// #2138: zoomed in on one end of a long part, the visible geometry's centre is off screen. A
|
||||
/// drag from empty space must not turn around it, or the end you are looking at swings out of
|
||||
/// view; it turns around the model point at the view's centre instead.
|
||||
#[test]
|
||||
fn orbiting_from_empty_space_keeps_a_zoomed_in_view_on_screen() {
|
||||
use solidcraft_engine::geom::Vec3;
|
||||
let mut app = SolveApp::new(solidcraft_engine::Session::default(), Default::default());
|
||||
app.run("solid.box", json!({"length": 400, "width": 10, "height": 10})).unwrap();
|
||||
app.preferences.orbit_around = OrbitAround::Cursor;
|
||||
let rect = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(800.0, 600.0));
|
||||
app.fit_view();
|
||||
// Look closely at the end near the origin.
|
||||
let end = Vec3::new(5.0, 5.0, 5.0);
|
||||
app.cam.target = end;
|
||||
app.cam.distance = 60.0;
|
||||
let proj = crate::viewport::projection(&app, rect);
|
||||
let centre = crate::viewport::view_bounds(&app).center();
|
||||
assert!(proj.to_screen(centre).is_none_or(|s| !rect.contains(s)), "the part's centre is off screen");
|
||||
let corner = egui::pos2(10.0, 10.0);
|
||||
use crate::viewport::Hit;
|
||||
assert!(!crate::viewport::pick(&app, &proj, corner).iter().any(|h| matches!(h, Hit::Face { .. } | Hit::Edge { .. } | Hit::Vertex { .. })));
|
||||
for _ in 0..4 {
|
||||
orbit(&mut app, rect, 60.0, 20.0, Some(corner));
|
||||
}
|
||||
assert_ne!(app.viewport.orbit_pivot, Some(centre));
|
||||
let s = crate::viewport::projection(&app, rect).to_screen(end);
|
||||
assert!(s.is_some_and(|s| rect.contains(s)), "the end stays in view: {s:?}");
|
||||
}
|
||||
|
||||
/// The Y up preference turns the view: the camera's up axis follows it, startup included.
|
||||
#[test]
|
||||
fn up_axis_preference_turns_the_view() {
|
||||
|
||||
Reference in New Issue
Block a user