mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-19 06:53:02 +00:00
The origin and the two axes become things you can constrain to
Port of snaporca 5b1294de59. Parity OK: 17 files identical, 8 diverging at their expected counts. Every industrial sketcher gives you the origin and the axes as references. Here the origin was only a SNAP target and the axes did not exist, so Symmetric needed a third picked ENTITY as its mirror axis: symmetry about the sketch's vertical axis first required drawing a construction line. Every constraint reference resolves through four lambdas in the solver (valid/ptOf/primOf/coordOf), so teaching those about three negative sentinel indices makes the origin and both axes available to EVERY constraint type at once. No new SketchEntity type, no serialization change; -1 still means "unset". The references live in G_FIXED and add no degrees of freedom, which a test asserts via the reported DoF. SymmetricAboutY / SymmetricAboutX are two buttons that need no third pick and no construction line. Making the axes clickable in the viewport is deliberately left out: that is canvas hit-testing work with its own risks. Recorded in the tests because it will catch the next person: sys.dragged[] is populated only during a drag, so a plain sketch_solve of an UNDER-constrained system may move any free parameter -- solvespace runs Newton, it does not minimise movement. PointOnLine onto an axis is one equation in two unknowns and the point legitimately slides along it. Those tests pin the free direction instead of asserting the other coordinate is untouched. VERIFICATION LIMIT, as with the previous two commits: this fork's kernel suite still cannot run (find_package(assimp) fails at configure, snaporca-w80c). The shared sources are byte-identical to snaporca's, where kernel is 2624 assertions / 206 cases and ALL LADDERS HELD across all seven rungs.
This commit is contained in:
@@ -1526,6 +1526,8 @@ DesignPanel::DesignPanel(wxWindow* parent)
|
||||
cbtn("design_c_tangent", _L("Tangent"), SketchConstraintType::Tangent);
|
||||
cbtn("design_c_midpoint", _L("Midpoint"), SketchConstraintType::Midpoint);
|
||||
cbtn("design_c_symmetric", _L("Symmetric"), SketchConstraintType::Symmetric);
|
||||
cbtn("design_c_sym_v", _L("Symmetric about the vertical axis"), SketchConstraintType::SymmetricAboutY);
|
||||
cbtn("design_c_sym_h", _L("Symmetric about the horizontal axis"), SketchConstraintType::SymmetricAboutX);
|
||||
cbtn("design_c_angle", _L("Angle"), SketchConstraintType::Angle);
|
||||
cbtn("design_c_radius", _L("Radius"), SketchConstraintType::Radius);
|
||||
cbtn("design_c_diameter", _L("Diameter"), SketchConstraintType::Diameter);
|
||||
@@ -7737,6 +7739,7 @@ void DesignPanel::apply_entity_constraint(SketchConstraintType type)
|
||||
type == T::Angle || type == T::Midpoint ||
|
||||
type == T::Symmetric || type == T::EqualRadius ||
|
||||
type == T::Collinear ||
|
||||
type == T::SymmetricAboutY || type == T::SymmetricAboutX ||
|
||||
type == T::DistanceX || type == T::DistanceY);
|
||||
if (e0 < 0 || e0 >= int(feat.entities.size()) ||
|
||||
(needs_two && (e1 < 0 || e1 >= int(feat.entities.size())))) {
|
||||
@@ -7881,6 +7884,27 @@ void DesignPanel::apply_entity_constraint(SketchConstraintType type)
|
||||
commit_entity_constraints(defs);
|
||||
return; // multi-def commit done here
|
||||
}
|
||||
case T::SymmetricAboutY:
|
||||
case T::SymmetricAboutX: {
|
||||
// Two entities made symmetric about the sketch's vertical/horizontal axis, which
|
||||
// is implicit (no picked axis line). Picks: slot0=A, slot1=B. Two Points -> one
|
||||
// pair; two Lines -> endpoint pairs. The axis is a negative sentinel in ec.
|
||||
using ET = SketchEntity::Type;
|
||||
const int axis = (type == T::SymmetricAboutY) ? kSketchRefAxisY : kSketchRefAxisX;
|
||||
const ET ta = feat.entities[e0].type, tb = feat.entities[e1].type;
|
||||
std::vector<SketchEntityConstraintDef> defs;
|
||||
auto mk = [&](R ra, R rb) {
|
||||
SketchEntityConstraintDef d;
|
||||
d.type = type;
|
||||
d.ea = e0; d.ra = ra; d.eb = e1; d.rb = rb; d.ec = axis;
|
||||
defs.push_back(d);
|
||||
};
|
||||
if (ta == ET::Point && tb == ET::Point) { mk(R::P0, R::P0); }
|
||||
else if (ta == ET::Line && tb == ET::Line) { mk(R::P0, R::P0); mk(R::P1, R::P1); }
|
||||
else { fail(_L("Symmetric needs two points or two lines")); return; }
|
||||
commit_entity_constraints(defs);
|
||||
return; // multi-def commit done here
|
||||
}
|
||||
case T::EqualRadius: {
|
||||
if (!is_round(feat.entities[e0]) || !is_round(feat.entities[e1])) {
|
||||
fail(_L("Equal radius needs two circles or arcs")); return;
|
||||
@@ -8050,6 +8074,10 @@ wxString DesignPanel::constraint_label(const SketchEntityConstraintDef& d) const
|
||||
case T::Midpoint: return two(_L("Midpoint"));
|
||||
case T::Symmetric: return wxString::Format(_L("Symmetric %s — %s / %s"),
|
||||
tag(d.ea, d.ra), tag(d.eb, d.rb), tag(d.ec, d.rc));
|
||||
case T::SymmetricAboutY: return wxString::Format(_L("Symmetric about Y axis %s — %s"),
|
||||
tag(d.ea, d.ra), tag(d.eb, d.rb));
|
||||
case T::SymmetricAboutX: return wxString::Format(_L("Symmetric about X axis %s — %s"),
|
||||
tag(d.ea, d.ra), tag(d.eb, d.rb));
|
||||
case T::Angle: return wxString::Format("%s = %s°", two(_L("Angle")), en_format(d.value * 180.0 / M_PI, 1));
|
||||
case T::Radius: return wxString::Format("%s %s = %s", _L("Radius"), tag(d.ea, d.ra), en_format(d.value));
|
||||
case T::Diameter: return wxString::Format("%s %s = %s", _L("Diameter"), tag(d.ea, d.ra), en_format(d.value));
|
||||
|
||||
Reference in New Issue
Block a user