1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! S / SKETCH — the profile-producing construction feature.
//!
//! The 2D constraint
//! SOLVER already lives in Rust (`solvers/sketch_solver.rs`); what was missing —
//! and what this feature adds — is turning a solved sketch into an extractable
//! 3D PROFILE the add-material features (extrude/revolve/loft/sweep/rib +
//! sheet-metal tab/contour-flange) consume by name.
//!
//! Pipeline:
//! 1. Read the raw sketch (`persistentData.sketch` = `{points, geometries,
//! constraints}`) and the plane `basis` (`persistentData.basis`). The basis
//! is computed SCENE-SIDE (from object
//! transforms / face normals) and marshaled in — directive §1 keeps the
//! reference/plane resolution scene-side; Rust just consumes the frame.
//! 2. Pre-evaluate expression-string coordinates/values against the shared
//! pipeline `Env` (a point `x`/`y` or a constraint `value`/`valueExpr` may be
//! `"width/2"`) — the solver only understands numbers. An expression that
//! does NOT resolve FAILS the sketch: the solver's `coerce_coord` reads a
//! surviving string by its leading numeric PREFIX (`"20*Hh"` → `20`), which
//! silently built a watertight solid of the wrong size.
//! 3. `solve_sketch` → solved point coordinates.
//! 4. Reconstruct the model geometries (skip `construction`), chain them into
//! maximal endpoint-connected runs. CLOSED runs become profile loops
//! (outer-vs-hole by containment); OPEN runs become the sketch PATH — the
//! `loops` and `openChains` are built side by side,
//! so a single sketch legally carries a closed profile PLUS a separate open
//! sweep trajectory, and neither invalidates the other.
//! 5. Emit each loop as `NurbsCurve`s placed in the plane frame; store the
//! `SketchProfile` in the scene under the sketch's id (contract: no solid,
//! like a construction pass-through, but carrying a profile).
//!
//! Geometry point semantics are the ground truth from the edge builder:
//! `line = [p0, p1]`; `arc = [center, start, end]`
//! sweeping CCW start→end (the pipeline normalizes the sweep into `[0, 2π)`); `circle =
//! [center, radiusPoint]` (a closed loop by itself); `ellipse = [center,
//! majorAxisEnd, minorAxisEnd]` (the affine image of the unit circle, a closed
//! loop by itself); `bezier = [p0, c1, c2, p1, …]`
//! (`3n+1` control points, chained cubic spans) rebuilds as one clamped degree-3
//! B-spline (see [`SegKind::Bezier`] / [`bezier_chain_curve`]). Any OTHER geometry
//! type errors loudly (no-fallback); the sketcher's freehand/curve tool emits
//! `bezier` (the standalone 3D spline is a separate feature, not a sketch
//! geometry).
use ;
use cratecommon;
use crate;
use crate::;
use Value;
/// Endpoint-coincidence tolerance for chaining loop segments (sketch units = mm).
/// Matches the join tolerance — `PROFILE_ENDPOINT_EPS = 1e-5` and 5-decimal
/// endpoint keying. The kernel itself demands 1e-6 closure
/// (`extrude_profile_brep`), so after chaining every emitted run is WELDED
/// exactly head-to-tail by [`weld_chain`].
const JOIN_TOL: f64 = 1e-5;
// BREP private tests: 5060d54b5a840829
pub use assign_sketch_loop_ids;
pub use ;
/// Context-bar applicability ([`crate::feature_pipeline::context_offer`]):
/// a selected face OR construction plane/datum can seat `sketchPlane` (the
/// `sketchPlane` field's `["PLANE","FACE"]` filter, resolved frame-or-face by
/// [`frame::resolve_frame`]), and edges can seed `projectedEdges` (in-context
/// sketching on model geometry).