Files
OrcaSlicer/src/libslic3r/CAD/SketchInference.hpp
T
Claude 815716a4b5 Merge branch 'main' into claude/inspiring-knuth-7cp6pk-upstream
Conflicts were only in include lists (CadDocument.cpp, SketchEngine.cpp);
both sides' includes are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QK4VgguuCAk2hZLWgcjJb9
2026-10-03 08:12:47 +00:00

62 lines
3.1 KiB
C++

#ifndef slic3r_SketchInference_hpp_
#define slic3r_SketchInference_hpp_
#include "libslic3r/Point.hpp"
#include "libslic3r/CAD/SketchEngine.hpp"
#include <math.h>
#include <vector>
#include <optional>
#include <cmath>
namespace Slic3r {
// Result of snapping a free cursor point onto the most relevant inference target
// among the committed sketch entities and the sketch origin. This is the backbone
// that lets geometry self-constrain as it is drawn: the GUI records the returned
// target at click time and, once the entity it belongs to exists, emits the
// matching constraint (Coincident onto an endpoint/centre, Fix onto the origin,
// PointOnObject onto an edge) so the relation survives a re-solve.
struct InferenceSnap {
enum class Kind { None, Endpoint, Center, Midpoint, OnEdge, Origin };
Kind kind{Kind::None};
int entity{-1}; // hit entity index (-1 = origin/none)
SketchPointRole role{SketchPointRole::P0}; // which point of `entity` (Endpoint/Center)
Vec2d point{0, 0}; // snapped coordinate (== query when None)
bool snapped() const { return kind != Kind::None; }
};
// Snap `query` onto the best inference target within `tol` plane units. Priority,
// highest first: Endpoint, Center, Origin, Midpoint, OnEdge. Construction entities
// participate (you constrain to them too). Returns {None, query} when nothing is in
// range. Pure — no GUI / GL dependencies, so it is unit-testable in libslic3r.
InferenceSnap infer_point_snap(const std::vector<SketchEntity>& entities,
const Vec2d& query, double tol,
bool include_origin = true);
// Relational inference for an in-progress segment anchor->tip. If its direction is
// within `ang_tol_rad` of an axis, returns Horizontal or Vertical (the constraint to
// auto-emit on the committed segment); std::nullopt otherwise. Degenerate (near-zero
// length) segments return nullopt.
// One angular tolerance for every "is this relation already true?" inference, so a pair of
// lines that reads as horizontal to one rule cannot read as not-quite-parallel to the other.
inline constexpr double kSketchInferAngleTol = 3.0 * M_PI / 180.0;
std::optional<SketchConstraintType>
infer_axis_constraint(const Vec2d& anchor, const Vec2d& tip, double ang_tol_rad = kSketchInferAngleTol);
// Relational constraints to auto-emit for a newly drawn entity `new_ei` against the
// entities already in the sketch. Pure, no GUI/GL dependencies, unit-testable.
//
// Deliberately conservative: every rule requires the relation to be ALREADY TRUE within
// tolerance, so an inferred constraint never moves geometry the user drew — it only pins a
// relation that is visibly there. Returns an empty vector when nothing qualifies.
std::vector<SketchEntityConstraintDef>
infer_relations(const std::vector<SketchEntity>& entities, int new_ei,
double ang_tol_rad = kSketchInferAngleTol,
double len_tol_frac = 0.01);
} // namespace Slic3r
#endif // slic3r_SketchInference_hpp_