Equal radius and Collinear, and one Equal button that knows what it picked

Port of snaporca 9ec6405e2d. Parity OK: 17 files identical, 8 diverging at their
expected counts (DesignPanel.cpp 32, test_slvs_constraints.cpp 3).

Measured on the CAD-1000-hours corpus: 51.5% of observed CAD time is 2D sketch
work, and dimensioning/constraining alone is 31.9% -- the largest single class.
Two constraints every industrial sketcher has were missing here.

EqualRadius fixes a dead end rather than adding a feature. Picking two circles
and pressing Equal emitted EqualLength, which maps to SLVS_C_EQUAL_LENGTH_LINES
and constrains nothing on a curve: a silent no-op with no error. Equal is now
one button with two meanings, as in Onshape and SolidWorks.

Collinear emits PARALLEL plus PT_LINE_DISTANCE=0 rather than PT_ON_LINE, whose
internal valP param this libslvs port leaves at 0, drifting an already-collinear
pair.

Both types are appended at the END of SketchConstraintType: cereal serializes it
positionally, so inserting elsewhere reinterprets every saved recipe.

VERIFICATION LIMIT, stated rather than implied: this fork's kernel suite could
NOT be run. scripts/CAD/run-kernel-tests.sh fails at CMake configure time on
find_package(assimp), before any source compiles -- a pre-existing deps gap
(snaporca-w80c), not this change. The shared sources are byte-identical to
snaporca's, where the full gate passed: kernel 2588/195 and ALL LADDERS HELD
across all seven rungs.

Also fixes two defects in this fork's scripts/CAD/run-all-checks.sh:
  - `cd $(dirname $0)/..` landed in scripts/ instead of the repo root, so every
    rung looked for itself under scripts/scripts/. Broken since the script moved
    into scripts/CAD/; the three sibling scripts were fixed then and this was
    missed, so the gate has not run since.
  - C defaulted to snaporca-gui, the OTHER fork's rig container, so this fork's
    gate would drive snaporca's app and report green about the wrong binary.
    run-kernel-tests.sh:31 documents the identical defect being fixed once
    already for the build volume; this is the third instance.
This commit is contained in:
Tommaso Bianchi
2026-08-31 01:09:43 +02:00
parent 937437907d
commit a1f2a2687a
7 changed files with 125 additions and 6 deletions
+63
View File
@@ -159,3 +159,66 @@ TEST_CASE("slvs: a sketch past the solver's unknown limit still solves", "[slvs]
auto res3 = sketch_solve(ents, cons);
CHECK_FALSE(res3.ok);
}
TEST_CASE("slvs: equal radius drives two circles to one radius", "[slvs][CadDocument]")
{
std::vector<SketchEntity> ents = { circle({0, 0}, 5.0), circle({10, 0}, 12.0) };
std::vector<SketchEntityConstraintDef> cons = {
con(CT::EqualRadius, 0, R::P0, 1, R::P0),
};
auto res = sketch_solve(ents, cons);
REQUIRE(res.ok);
CHECK(ents[0].radius == Approx(ents[1].radius).margin(1e-9));
CHECK(ents[0].radius > 1e-6); // equal-at-zero would satisfy the line above trivially
}
TEST_CASE("slvs: equal radius plus a radius dimension pins both", "[slvs][CadDocument]")
{
std::vector<SketchEntity> ents = { circle({0, 0}, 5.0), circle({10, 0}, 12.0) };
std::vector<SketchEntityConstraintDef> cons = {
con(CT::EqualRadius, 0, R::P0, 1, R::P0),
con(CT::Radius, 0, R::P0, -1, R::P0, 8.0),
};
auto res = sketch_solve(ents, cons);
REQUIRE(res.ok);
CHECK(ents[0].radius == Approx(8.0).margin(1e-9));
CHECK(ents[1].radius == Approx(8.0).margin(1e-9));
}
TEST_CASE("slvs: collinear makes two offset lines share one line", "[slvs][CadDocument]")
{
std::vector<SketchEntity> ents = { line({0, 0}, {10, 0}), line({0, 4}, {10, 4}) };
std::vector<SketchEntityConstraintDef> cons = {
con(CT::Collinear, 0, R::P0, 1, R::P0),
};
auto res = sketch_solve(ents, cons);
REQUIRE(res.ok);
const Vec2d& a0 = ents[0].p0;
const Vec2d ad = ents[0].p1 - ents[0].p0;
for (int k = 0; k <= 1; ++k) {
const Vec2d& pk = (k == 0) ? ents[1].p0 : ents[1].p1;
const double cross = ad.x() * (pk.y() - a0.y()) - ad.y() * (pk.x() - a0.x());
CHECK(cross == Approx(0.0).margin(1e-9));
}
// A line collapsed to a point is trivially collinear with anything, so the cross
// products above would pass on a degenerate solve. Both lines must survive intact.
CHECK(ad.norm() == Approx(10.0).margin(1e-9));
CHECK((ents[1].p1 - ents[1].p0).norm() == Approx(10.0).margin(1e-9));
}
TEST_CASE("slvs: collinear on already-collinear lines moves nothing", "[slvs][CadDocument]")
{
std::vector<SketchEntity> ents = { line({0, 0}, {10, 0}), line({20, 0}, {30, 0}) };
std::vector<SketchEntityConstraintDef> cons = {
con(CT::Collinear, 0, R::P0, 1, R::P0),
};
std::vector<SketchEntity> before = ents;
auto res = sketch_solve(ents, cons);
REQUIRE(res.ok);
for (size_t i = 0; i < ents.size(); ++i) { // already satisfied: nothing may move
CHECK(ents[i].p0.x() == Approx(before[i].p0.x()).margin(1e-9));
CHECK(ents[i].p0.y() == Approx(before[i].p0.y()).margin(1e-9));
CHECK(ents[i].p1.x() == Approx(before[i].p1.x()).margin(1e-9));
CHECK(ents[i].p1.y() == Approx(before[i].p1.y()).margin(1e-9));
}
}