Close the Steps of Sloped Surfaces in the Shell and Size Layers by Projection

On a dome or a cone the shell showed holes: dashes of inner wall and overhang
wall through gaps, and darkness behind them. Each layer's ring on a slope is
inset from the one below by less than a grid cell, so the height map cannot see
the step, and the interior of the lower layer that fills it, its first inner
wall above all, had been left out. Inner wall segments whose midpoint lies
within a line and a half of an outer wall segment of the same layer now stay on
the shell, found by exact distance against the outer walls bucketed by cell,
and a segment counts as visible from above or below when any of its cells is
the topmost or bottommost occupant, since the exposed band is narrower than the
chords that cross it. Interior roles that are visible that way stay too.

The layer stride at rest was sized from the camera's zoom value and tilt, which
does not describe a perspective view: zoomed in on the test project it reached
64, so each kept ring stood 6 mm tall while the surface curved away under it.
One layer's height is now projected through the camera's own matrices, at the
centre of the toolpaths and at the camera target, and the stride follows that.

On the test project the shell at rest gains 43 k segments for the first inner
walls, 171 k to 214 k, and the dome and cone draw closed. The nine-cube plate
draws 96 k at the default view and 12 k from above.
This commit is contained in:
Hanif Koh
2026-09-11 17:37:36 +08:00
parent 55ef9d2afd
commit 038e86f02a
3 changed files with 79 additions and 11 deletions
+16 -4
View File
@@ -1947,10 +1947,22 @@ void GCodeViewer::update_rest_layer_stride()
return;
static constexpr double MERGE_BELOW_PX = 2.0;
static constexpr unsigned int MAX_STRIDE = 64;
const Camera& camera = wxGetApp().plater()->get_camera();
const double dz = std::abs(camera.get_dir_forward().z());
const double tilt = std::sqrt(std::max(0.0, 1.0 - dz * dz));
const double layer_px = static_cast<double>(m_typical_layer_height) * camera.get_zoom() * tilt;
Camera& camera = wxGetApp().plater()->get_camera();
// how tall one layer is on screen: a step of one layer height projected through the camera's
// own matrices at the centre of the toolpaths and at the point the camera looks at, whichever
// is taller. Perspective makes the near corners of a tall print larger than that, but merging
// is judged where the user looks, not at the worst corner.
const Matrix4d view_projection = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix();
const std::array<int, 4>& viewport = camera.get_viewport();
const auto to_pixels = [&](const Vec3d& p) {
const Vec4d clip = view_projection * Vec4d(p.x(), p.y(), p.z(), 1.0);
const double w = (std::abs(clip.w()) < 1e-9) ? 1e-9 : clip.w();
return Vec2d(0.5 * viewport[2] * clip.x() / w, 0.5 * viewport[3] * clip.y() / w);
};
const Vec3d step(0.0, 0.0, static_cast<double>(m_typical_layer_height));
double layer_px = 0.0;
for (const Vec3d& p : { m_paths_bounding_box.center(), camera.get_target() })
layer_px = std::max(layer_px, (to_pixels(p + step) - to_pixels(p)).norm());
const unsigned int stride = (layer_px * MAX_STRIDE <= MERGE_BELOW_PX) ? MAX_STRIDE :
std::clamp(static_cast<unsigned int>(MERGE_BELOW_PX / layer_px), 1u, MAX_STRIDE);
m_viewer.set_rest_layer_stride(stride);