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:
@@ -222,3 +222,81 @@ TEST_CASE("slvs: collinear on already-collinear lines moves nothing", "[slvs][Ca
|
||||
CHECK(ents[i].p1.y() == Approx(before[i].p1.y()).margin(1e-9));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("slvs: distance-x drives the horizontal gap and leaves Y alone", "[slvs][CadDocument]")
|
||||
{
|
||||
std::vector<SketchEntity> ents = { line({0, 0}, {3, 7}) };
|
||||
std::vector<SketchEntityConstraintDef> cons = {
|
||||
con(CT::Fix, 0, R::P0, 0, R::P0),
|
||||
con(CT::DistanceX, 0, R::P0, 0, R::P1, 10.0),
|
||||
};
|
||||
auto res = sketch_solve(ents, cons);
|
||||
REQUIRE(res.ok);
|
||||
// SIGNED, not abs. PROJ_PT_DISTANCE constrains (pB - pA).dot(unit(dir)), and a
|
||||
// LINE_SEGMENT's direction is point[0] - point[1] (slvs entity.cpp), so the reference
|
||||
// line is built head-first to mean +X. Assert on abs and a flipped reference passes
|
||||
// while every dimension lands the point on the wrong side of its anchor.
|
||||
CHECK(ents[0].p1.x() - ents[0].p0.x() == Approx(10.0).margin(1e-9));
|
||||
CHECK(ents[0].p1.y() == Approx(7.0).margin(1e-9)); // Y must not be disturbed
|
||||
}
|
||||
|
||||
TEST_CASE("slvs: distance-y drives the vertical gap and leaves X alone", "[slvs][CadDocument]")
|
||||
{
|
||||
std::vector<SketchEntity> ents = { line({0, 0}, {3, 7}) };
|
||||
std::vector<SketchEntityConstraintDef> cons = {
|
||||
con(CT::Fix, 0, R::P0, 0, R::P0),
|
||||
con(CT::DistanceY, 0, R::P0, 0, R::P1, 10.0),
|
||||
};
|
||||
auto res = sketch_solve(ents, cons);
|
||||
REQUIRE(res.ok);
|
||||
CHECK(ents[0].p1.y() - ents[0].p0.y() == Approx(10.0).margin(1e-9)); // signed: see above
|
||||
CHECK(ents[0].p1.x() == Approx(3.0).margin(1e-9)); // X must not be disturbed
|
||||
}
|
||||
|
||||
TEST_CASE("slvs: distance-x is not the straight-line distance", "[slvs][CadDocument]")
|
||||
{
|
||||
// B is at straight-line distance 10 from A; DistanceX = 6 is already satisfied, so a
|
||||
// correct projection leaves B untouched. This is the case that fails if the constraint
|
||||
// were wired to SLVS_C_PT_PT_DISTANCE, which would drag B onto the radius-6 circle.
|
||||
std::vector<SketchEntity> ents = { line({0, 0}, {6, 8}) };
|
||||
std::vector<SketchEntityConstraintDef> cons = {
|
||||
con(CT::Fix, 0, R::P0, 0, R::P0),
|
||||
con(CT::DistanceX, 0, R::P0, 0, R::P1, 6.0),
|
||||
};
|
||||
auto res = sketch_solve(ents, cons);
|
||||
REQUIRE(res.ok);
|
||||
CHECK(ents[0].p1.x() == Approx(6.0).margin(1e-9));
|
||||
CHECK(ents[0].p1.y() == Approx(8.0).margin(1e-9));
|
||||
}
|
||||
|
||||
TEST_CASE("slvs: distance-x plus distance-y fully locates a point", "[slvs][CadDocument]")
|
||||
{
|
||||
std::vector<SketchEntity> ents = { line({0, 0}, {1, 1}) };
|
||||
std::vector<SketchEntityConstraintDef> cons = {
|
||||
con(CT::Fix, 0, R::P0, 0, R::P0),
|
||||
con(CT::DistanceX, 0, R::P0, 0, R::P1, 4.0),
|
||||
con(CT::DistanceY, 0, R::P0, 0, R::P1, 3.0),
|
||||
};
|
||||
auto res = sketch_solve(ents, cons);
|
||||
REQUIRE(res.ok);
|
||||
CHECK(ents[0].p1.x() - ents[0].p0.x() == Approx(4.0).margin(1e-9)); // signed: see above
|
||||
CHECK(ents[0].p1.y() - ents[0].p0.y() == Approx(3.0).margin(1e-9));
|
||||
}
|
||||
|
||||
// The property the GUI's ref-ordering exists to preserve: DistanceX is SIGNED, so applying
|
||||
// the CURRENT projected delta as the target must not move anything. If the refs are ordered
|
||||
// so the shown value is positive while the actual signed delta is negative, accepting the
|
||||
// value a dimension opens with teleports the point to the other side of its anchor.
|
||||
TEST_CASE("slvs: applying a point's own distance-x is a no-op", "[slvs][CadDocument]")
|
||||
{
|
||||
// p1 sits to the LEFT of p0, so the signed delta p1 - p0 is negative.
|
||||
std::vector<SketchEntity> ents = { line({0, 0}, {-4, 7}) };
|
||||
std::vector<SketchEntityConstraintDef> cons = {
|
||||
con(CT::Fix, 0, R::P0, 0, R::P0),
|
||||
con(CT::DistanceX, 0, R::P0, 0, R::P1, -4.0), // the CURRENT signed delta
|
||||
};
|
||||
auto res = sketch_solve(ents, cons);
|
||||
REQUIRE(res.ok);
|
||||
CHECK(ents[0].p1.x() == Approx(-4.0).margin(1e-9)); // stayed left, did not flip to +4
|
||||
CHECK(ents[0].p1.y() == Approx(7.0).margin(1e-9));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user