mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 22:42:37 +00:00
Horizontal and vertical distance dimensions
Port of snaporca 9fa304c77a. Parity OK: 17 files identical, 8 diverging at their expected counts. The everyday dimension in SolidWorks and Onshape, and this kernel had no form of it. Distance constrains the straight-line gap; LockX/LockY pin one point's ABSOLUTE coordinate. Neither relates two points along an axis. DistanceX/DistanceY emit SLVS_C_PROJ_PT_DISTANCE against two unit direction lines built in the solver's G_FIXED group, so they add no degrees of freedom. THE DIRECTION IS SIGNED, and getting it backwards is silent. libslvs defines a LINE_SEGMENT's direction as point[0] - point[1] (entity.cpp) and PROJ_PT_DISTANCE constrains (pB - pA).dot(dir) (constrainteq.cpp:234), so the reference lines are built head-first to mean +X and +Y. The same signedness was a real defect in the GUI: the inline editor was pre-filled with |delta|, so when the closest endpoint pair ran right-to-left, opening the dimension and accepting the number shown would flip the point to the other side of its anchor. Opening a dimension and accepting its own value must be a no-op. The refs are now ordered so the shown value is positive. On the CAD-1000-hours corpus, dimensioning and constraining is 31.9% of all observed CAD time -- the largest single class, 7.6x feature operations. This is the item in the constraint epic that lands most directly on it. VERIFICATION LIMIT, as with the previous commit: this fork's kernel suite still cannot run (find_package(assimp) fails at configure time, snaporca-w80c). The shared sources are byte-identical to snaporca's, where kernel is 2603 assertions / 200 cases and ALL LADDERS HELD across all seven rungs.
This commit is contained in:
@@ -1530,6 +1530,8 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
cbtn("design_c_radius", _L("Radius"), SketchConstraintType::Radius);
|
||||
cbtn("design_c_diameter", _L("Diameter"), SketchConstraintType::Diameter);
|
||||
cbtn("design_c_fix", _L("Fix point (anchor in place)"), SketchConstraintType::Fix);
|
||||
cbtn("design_c_dist_x", _L("Horizontal distance"), SketchConstraintType::DistanceX);
|
||||
cbtn("design_c_dist_y", _L("Vertical distance"), SketchConstraintType::DistanceY);
|
||||
// Trim/Extend are now standalone SKETCH scissors (Mode::Trim/Extend) in the sketch
|
||||
// toolbar, NOT Constrain buttons. The other edit ops (Mirror/Offset/Fillet/Chamfer/
|
||||
// Move/…) are first-class sketch tools too. Done constraining = the action-bar ✓.
|
||||
@@ -7734,7 +7736,8 @@ void DesignPanel::apply_entity_constraint(SketchConstraintType type)
|
||||
type == T::Concentric || type == T::Tangent ||
|
||||
type == T::Angle || type == T::Midpoint ||
|
||||
type == T::Symmetric || type == T::EqualRadius ||
|
||||
type == T::Collinear);
|
||||
type == T::Collinear ||
|
||||
type == T::DistanceX || type == T::DistanceY);
|
||||
if (e0 < 0 || e0 >= int(feat.entities.size()) ||
|
||||
(needs_two && (e1 < 0 || e1 >= int(feat.entities.size())))) {
|
||||
fail(needs_two ? _L("Pick two entities first") : _L("Pick an entity first"));
|
||||
@@ -7772,6 +7775,41 @@ void DesignPanel::apply_entity_constraint(SketchConstraintType type)
|
||||
def.ea = e0; def.ra = ra; def.eb = e1; def.rb = rb;
|
||||
break;
|
||||
}
|
||||
case T::DistanceX:
|
||||
case T::DistanceY: {
|
||||
// Axis-projected distance between the closest endpoint pair of the two picked
|
||||
// entities. Typed in-canvas pre-filled with the current projection, committed on
|
||||
// the typed value (same deferred pattern as Angle).
|
||||
const SketchEntity& A = feat.entities[e0];
|
||||
const SketchEntity& B = feat.entities[e1];
|
||||
const std::pair<R, Vec2d> aps[2] = {{R::P0, A.p0}, {R::P1, A.p1}};
|
||||
const std::pair<R, Vec2d> bps[2] = {{R::P0, B.p0}, {R::P1, B.p1}};
|
||||
R ra = R::P1, rb = R::P0;
|
||||
Vec2d pa = A.p1, pb = B.p0;
|
||||
double best = 1e30;
|
||||
for (const auto& ap : aps)
|
||||
for (const auto& bp : bps) {
|
||||
const double d = (ap.second - bp.second).squaredNorm();
|
||||
if (d < best) { best = d; ra = ap.first; rb = bp.first; pa = ap.second; pb = bp.second; }
|
||||
}
|
||||
// The constraint is SIGNED: PROJ_PT_DISTANCE fixes (pB - pA).dot(axis), not its
|
||||
// magnitude. Showing |delta| while the current signed delta is negative would mean
|
||||
// that opening the dimension and simply accepting the number on screen flips the
|
||||
// point to the other side of its anchor. Opening a dimension and accepting its own
|
||||
// value must be a no-op, so order the two refs to make the shown value the positive
|
||||
// one -- which is also how a dimension ought to read.
|
||||
int a = e0, b = e1;
|
||||
double delta = (type == T::DistanceX) ? (pb.x() - pa.x()) : (pb.y() - pa.y());
|
||||
if (delta < 0.0) { std::swap(a, b); std::swap(ra, rb); delta = -delta; }
|
||||
const double cur = delta;
|
||||
const T tt = type;
|
||||
m_viewport->open_inline_value(cur, [this, a, b, ra, rb, tt](double v) {
|
||||
SketchEntityConstraintDef d;
|
||||
d.type = tt; d.ea = a; d.ra = ra; d.eb = b; d.rb = rb; d.value = v;
|
||||
commit_entity_constraint(d);
|
||||
});
|
||||
return; // deferred: commit runs on the typed value
|
||||
}
|
||||
case T::Concentric: {
|
||||
// Two circles/arcs: make their centres coincide.
|
||||
if (!is_round(feat.entities[e0]) || !is_round(feat.entities[e1])) {
|
||||
|
||||
Reference in New Issue
Block a user