@mathscan/geometry-engine 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +24 -7
  2. package/dist/core.cjs +1 -1
  3. package/dist/core.mjs +4 -4
  4. package/dist/entries/core.d.cts +1 -1
  5. package/dist/entries/core.d.ts +1 -1
  6. package/dist/entries/core.d.ts.map +1 -1
  7. package/dist/exercise.schema-Bma3qN9P.js +251 -0
  8. package/dist/exercise.schema-Bma3qN9P.js.map +1 -0
  9. package/dist/exercise.schema-Oj5ZH-yO.cjs +2 -0
  10. package/dist/exercise.schema-Oj5ZH-yO.cjs.map +1 -0
  11. package/dist/exerciseLoad-Db9Cigxi.cjs +2 -0
  12. package/dist/exerciseLoad-Db9Cigxi.cjs.map +1 -0
  13. package/dist/{geometryAttemptStatus-5L_q6-9l.js → exerciseLoad-DgeDXYbf.js} +84 -71
  14. package/dist/exerciseLoad-DgeDXYbf.js.map +1 -0
  15. package/dist/geometry/entities/angle.d.cts +56 -0
  16. package/dist/geometry/entities/angle.d.ts +57 -0
  17. package/dist/geometry/entities/angle.d.ts.map +1 -0
  18. package/dist/geometry/entities/circle.d.ts.map +1 -1
  19. package/dist/geometry/entities/index.d.cts +8 -4
  20. package/dist/geometry/entities/index.d.ts +8 -4
  21. package/dist/geometry/entities/index.d.ts.map +1 -1
  22. package/dist/geometry/entities/line.d.ts.map +1 -1
  23. package/dist/geometry/entities/point.d.ts.map +1 -1
  24. package/dist/geometry/entities/relations.d.cts +8 -1
  25. package/dist/geometry/entities/relations.d.ts +8 -1
  26. package/dist/geometry/entities/relations.d.ts.map +1 -1
  27. package/dist/geometry/entities/segment.d.ts.map +1 -1
  28. package/dist/geometry/entityModel.d.cts +21 -3
  29. package/dist/geometry/entityModel.d.ts +21 -3
  30. package/dist/geometry/entityModel.d.ts.map +1 -1
  31. package/dist/geometryState.schema-B5ccMKDa.cjs +2 -0
  32. package/dist/geometryState.schema-B5ccMKDa.cjs.map +1 -0
  33. package/dist/geometryState.schema-CKFPlX8j.js +1177 -0
  34. package/dist/geometryState.schema-CKFPlX8j.js.map +1 -0
  35. package/dist/goals-BlSeniyt.js +563 -0
  36. package/dist/goals-BlSeniyt.js.map +1 -0
  37. package/dist/goals-DLbmBZD8.cjs +2 -0
  38. package/dist/goals-DLbmBZD8.cjs.map +1 -0
  39. package/dist/index.cjs +1 -1
  40. package/dist/index.mjs +8 -8
  41. package/dist/measure/angleType.d.cts +2 -0
  42. package/dist/measure/angleType.d.ts +3 -0
  43. package/dist/measure/angleType.d.ts.map +1 -0
  44. package/dist/measure/geometryAdapter.d.cts +3 -0
  45. package/dist/measure/geometryAdapter.d.ts +3 -0
  46. package/dist/measure/geometryAdapter.d.ts.map +1 -1
  47. package/dist/react-B26_e52I.cjs +2 -0
  48. package/dist/react-B26_e52I.cjs.map +1 -0
  49. package/dist/{react-BEcdx1f6.js → react-B5cGaxH8.js} +738 -513
  50. package/dist/react-B5cGaxH8.js.map +1 -0
  51. package/dist/react.cjs +1 -1
  52. package/dist/react.mjs +1 -1
  53. package/dist/renderer/GeometryCanvas.d.ts.map +1 -1
  54. package/dist/renderer/StudentGeometryCanvas.d.ts.map +1 -1
  55. package/dist/renderer/Toolbar.d.ts.map +1 -1
  56. package/dist/renderer/angleMeasure.d.cts +14 -0
  57. package/dist/renderer/angleMeasure.d.ts +15 -0
  58. package/dist/renderer/angleMeasure.d.ts.map +1 -0
  59. package/dist/renderer/deriveRenderableGeometry.d.cts +1 -0
  60. package/dist/renderer/deriveRenderableGeometry.d.ts +1 -0
  61. package/dist/renderer/deriveRenderableGeometry.d.ts.map +1 -1
  62. package/dist/renderer/deriveSemanticScene.d.ts.map +1 -1
  63. package/dist/renderer/dragSnap.d.cts +14 -0
  64. package/dist/renderer/dragSnap.d.ts +15 -0
  65. package/dist/renderer/dragSnap.d.ts.map +1 -0
  66. package/dist/renderer/shapes/AngleShape.d.cts +19 -0
  67. package/dist/renderer/shapes/AngleShape.d.ts +20 -0
  68. package/dist/renderer/shapes/AngleShape.d.ts.map +1 -0
  69. package/dist/renderer/shapes/EntityLabel.d.cts +9 -1
  70. package/dist/renderer/shapes/EntityLabel.d.ts +9 -1
  71. package/dist/renderer/shapes/EntityLabel.d.ts.map +1 -1
  72. package/dist/renderer/shapes/EntityShape.d.cts +2 -1
  73. package/dist/renderer/shapes/EntityShape.d.ts +2 -1
  74. package/dist/renderer/shapes/EntityShape.d.ts.map +1 -1
  75. package/dist/renderer/useConnectionPreview.d.cts +12 -1
  76. package/dist/renderer/useConnectionPreview.d.ts +12 -1
  77. package/dist/renderer/useConnectionPreview.d.ts.map +1 -1
  78. package/dist/renderer/usePointerGestures.d.cts +1 -1
  79. package/dist/renderer/usePointerGestures.d.ts +1 -1
  80. package/dist/renderer/usePointerGestures.d.ts.map +1 -1
  81. package/dist/schemas/entityDefinition.schema.d.cts +7 -0
  82. package/dist/schemas/entityDefinition.schema.d.ts +7 -0
  83. package/dist/schemas/entityDefinition.schema.d.ts.map +1 -1
  84. package/dist/schemas/entityDocument.d.cts +34 -13
  85. package/dist/schemas/entityDocument.d.ts +34 -13
  86. package/dist/schemas/entityDocument.d.ts.map +1 -1
  87. package/dist/schemas/entityPresentation.schema.d.cts +3 -0
  88. package/dist/schemas/entityPresentation.schema.d.ts +3 -0
  89. package/dist/schemas/entityPresentation.schema.d.ts.map +1 -1
  90. package/dist/schemas/exercise.schema.d.cts +80 -2
  91. package/dist/schemas/exercise.schema.d.ts +80 -2
  92. package/dist/schemas/exercise.schema.d.ts.map +1 -1
  93. package/dist/schemas/exerciseV2.schema.d.cts +57 -0
  94. package/dist/schemas/exerciseV2.schema.d.ts +57 -0
  95. package/dist/schemas/exerciseV2.schema.d.ts.map +1 -1
  96. package/dist/schemas/exerciseV4.schema.d.cts +168 -0
  97. package/dist/schemas/exerciseV4.schema.d.ts +169 -0
  98. package/dist/schemas/exerciseV4.schema.d.ts.map +1 -0
  99. package/dist/schemas/geometryState.schema.d.cts +8 -0
  100. package/dist/schemas/geometryState.schema.d.ts +8 -0
  101. package/dist/schemas/geometryState.schema.d.ts.map +1 -1
  102. package/dist/schemas/goals/angleBisectorGoal.schema.d.cts +15 -0
  103. package/dist/schemas/goals/angleBisectorGoal.schema.d.ts +16 -0
  104. package/dist/schemas/goals/angleBisectorGoal.schema.d.ts.map +1 -0
  105. package/dist/schemas/goals/angleCriterion.schema.d.cts +28 -0
  106. package/dist/schemas/goals/angleCriterion.schema.d.ts +29 -0
  107. package/dist/schemas/goals/angleCriterion.schema.d.ts.map +1 -0
  108. package/dist/schemas/goals/angleMeasureGoal.schema.d.cts +26 -0
  109. package/dist/schemas/goals/angleMeasureGoal.schema.d.ts +27 -0
  110. package/dist/schemas/goals/angleMeasureGoal.schema.d.ts.map +1 -0
  111. package/dist/schemas/goals/createGoal.schema.d.cts +1 -0
  112. package/dist/schemas/goals/createGoal.schema.d.ts +1 -0
  113. package/dist/schemas/goals/createGoal.schema.d.ts.map +1 -1
  114. package/dist/schemas/goals/geometryGoal.schema.d.cts +61 -0
  115. package/dist/schemas/goals/geometryGoal.schema.d.ts +61 -0
  116. package/dist/schemas/goals/geometryGoal.schema.d.ts.map +1 -1
  117. package/dist/schemas/goals/givenAngleGoal.schema.d.cts +35 -0
  118. package/dist/schemas/goals/givenAngleGoal.schema.d.ts +36 -0
  119. package/dist/schemas/goals/givenAngleGoal.schema.d.ts.map +1 -0
  120. package/dist/schemas/goals/goalKindDeclaration.d.cts +7 -0
  121. package/dist/schemas/goals/goalKindDeclaration.d.ts +7 -0
  122. package/dist/schemas/goals/goalKindDeclaration.d.ts.map +1 -1
  123. package/dist/schemas/goals/parallelGoal.schema.d.cts +1 -0
  124. package/dist/schemas/goals/parallelGoal.schema.d.ts +1 -0
  125. package/dist/schemas/goals/parallelGoal.schema.d.ts.map +1 -1
  126. package/dist/schemas/goals/perpendicularGoal.schema.d.cts +1 -0
  127. package/dist/schemas/goals/perpendicularGoal.schema.d.ts +1 -0
  128. package/dist/schemas/goals/perpendicularGoal.schema.d.ts.map +1 -1
  129. package/dist/schemas/goals/throughPointsGoal.schema.d.cts +1 -0
  130. package/dist/schemas/goals/throughPointsGoal.schema.d.ts +1 -0
  131. package/dist/schemas/goals/throughPointsGoal.schema.d.ts.map +1 -1
  132. package/dist/schemas/objectTypeName.schema.d.cts +1 -0
  133. package/dist/schemas/objectTypeName.schema.d.ts +1 -0
  134. package/dist/schemas/objectTypeName.schema.d.ts.map +1 -1
  135. package/dist/schemas/v2ToV3.d.cts +15 -1
  136. package/dist/schemas/v2ToV3.d.ts +15 -1
  137. package/dist/schemas/v2ToV3.d.ts.map +1 -1
  138. package/dist/schemas/v3ToV4.d.cts +2 -1
  139. package/dist/schemas/v3ToV4.d.ts +2 -1
  140. package/dist/schemas/v3ToV4.d.ts.map +1 -1
  141. package/dist/schemas/v4ToV5.d.cts +7 -0
  142. package/dist/schemas/v4ToV5.d.ts +8 -0
  143. package/dist/schemas/v4ToV5.d.ts.map +1 -0
  144. package/dist/schemas.cjs +1 -1
  145. package/dist/schemas.mjs +3 -3
  146. package/dist/snapping/computeDragSnap.d.cts +30 -0
  147. package/dist/snapping/computeDragSnap.d.ts +31 -0
  148. package/dist/snapping/computeDragSnap.d.ts.map +1 -0
  149. package/dist/state/geometryContext.d.ts.map +1 -1
  150. package/dist/store/attemptChange.d.cts +1 -1
  151. package/dist/store/attemptChange.d.ts +1 -1
  152. package/dist/store/attemptChange.d.ts.map +1 -1
  153. package/dist/store/constructionCommand.d.cts +14 -2
  154. package/dist/store/constructionCommand.d.ts +14 -2
  155. package/dist/store/constructionCommand.d.ts.map +1 -1
  156. package/dist/store/constructionIdentity.d.cts +9 -0
  157. package/dist/store/constructionIdentity.d.ts +9 -0
  158. package/dist/store/constructionIdentity.d.ts.map +1 -1
  159. package/dist/store/studentStore.d.cts +7 -0
  160. package/dist/store/studentStore.d.ts +7 -0
  161. package/dist/store/studentStore.d.ts.map +1 -1
  162. package/dist/store/teacherStore.d.cts +16 -0
  163. package/dist/store/teacherStore.d.ts +16 -0
  164. package/dist/store/teacherStore.d.ts.map +1 -1
  165. package/dist/{studentStore-CEKTtMCh.js → studentStore-CyYa0N93.js} +502 -370
  166. package/dist/studentStore-CyYa0N93.js.map +1 -0
  167. package/dist/studentStore-ubldy4PJ.cjs +2 -0
  168. package/dist/studentStore-ubldy4PJ.cjs.map +1 -0
  169. package/dist/validation/getGeometryExerciseWarnings.d.cts +3 -2
  170. package/dist/validation/getGeometryExerciseWarnings.d.ts +3 -2
  171. package/dist/validation/getGeometryExerciseWarnings.d.ts.map +1 -1
  172. package/dist/validation/goals/angleBisector.d.cts +3 -0
  173. package/dist/validation/goals/angleBisector.d.ts +4 -0
  174. package/dist/validation/goals/angleBisector.d.ts.map +1 -0
  175. package/dist/validation/goals/angleCriterion.d.cts +12 -0
  176. package/dist/validation/goals/angleCriterion.d.ts +13 -0
  177. package/dist/validation/goals/angleCriterion.d.ts.map +1 -0
  178. package/dist/validation/goals/angleMeasure.d.cts +9 -0
  179. package/dist/validation/goals/angleMeasure.d.ts +10 -0
  180. package/dist/validation/goals/angleMeasure.d.ts.map +1 -0
  181. package/dist/validation/goals/create.d.cts +2 -2
  182. package/dist/validation/goals/create.d.ts +2 -2
  183. package/dist/validation/goals/create.d.ts.map +1 -1
  184. package/dist/validation/goals/givenAngle.d.cts +11 -0
  185. package/dist/validation/goals/givenAngle.d.ts +12 -0
  186. package/dist/validation/goals/givenAngle.d.ts.map +1 -0
  187. package/dist/validation/goals/goalKindHandler.d.cts +38 -1
  188. package/dist/validation/goals/goalKindHandler.d.ts +38 -1
  189. package/dist/validation/goals/goalKindHandler.d.ts.map +1 -1
  190. package/dist/validation/goals/index.d.cts +9 -2
  191. package/dist/validation/goals/index.d.ts +9 -2
  192. package/dist/validation/goals/index.d.ts.map +1 -1
  193. package/dist/validation/goals/midpoint.d.cts +2 -2
  194. package/dist/validation/goals/midpoint.d.ts +2 -2
  195. package/dist/validation/goals/midpoint.d.ts.map +1 -1
  196. package/dist/validation/goals/parallel.d.cts +2 -2
  197. package/dist/validation/goals/parallel.d.ts +2 -2
  198. package/dist/validation/goals/parallel.d.ts.map +1 -1
  199. package/dist/validation/goals/perpendicular.d.cts +2 -2
  200. package/dist/validation/goals/perpendicular.d.ts +2 -2
  201. package/dist/validation/goals/perpendicular.d.ts.map +1 -1
  202. package/dist/validation/goals/segmentLength.d.cts +2 -2
  203. package/dist/validation/goals/segmentLength.d.ts +2 -2
  204. package/dist/validation/goals/segmentLength.d.ts.map +1 -1
  205. package/dist/validation/goals/throughPoints.d.cts +2 -2
  206. package/dist/validation/goals/throughPoints.d.ts +2 -2
  207. package/dist/validation/goals/throughPoints.d.ts.map +1 -1
  208. package/dist/validation/types.d.cts +5 -1
  209. package/dist/validation/types.d.ts +5 -1
  210. package/dist/validation/types.d.ts.map +1 -1
  211. package/dist/validation/validateGeometryState.d.ts.map +1 -1
  212. package/dist/validation/validateGeometryStateInput.d.ts.map +1 -1
  213. package/dist/validation.cjs +1 -1
  214. package/dist/validation.cjs.map +1 -1
  215. package/dist/validation.mjs +106 -85
  216. package/dist/validation.mjs.map +1 -1
  217. package/package.json +1 -1
  218. package/dist/exercise.schema-BV2b7rtN.cjs +0 -2
  219. package/dist/exercise.schema-BV2b7rtN.cjs.map +0 -1
  220. package/dist/exercise.schema-ckVBW9XA.js +0 -212
  221. package/dist/exercise.schema-ckVBW9XA.js.map +0 -1
  222. package/dist/geometryAttemptStatus-5L_q6-9l.js.map +0 -1
  223. package/dist/geometryAttemptStatus-N_XHIkiS.cjs +0 -2
  224. package/dist/geometryAttemptStatus-N_XHIkiS.cjs.map +0 -1
  225. package/dist/geometryState.schema-D0ixyGYE.js +0 -955
  226. package/dist/geometryState.schema-D0ixyGYE.js.map +0 -1
  227. package/dist/geometryState.schema-DKQ-durx.cjs +0 -2
  228. package/dist/geometryState.schema-DKQ-durx.cjs.map +0 -1
  229. package/dist/goals-C3ZwbEh_.js +0 -451
  230. package/dist/goals-C3ZwbEh_.js.map +0 -1
  231. package/dist/goals-CxR5qPDC.cjs +0 -2
  232. package/dist/goals-CxR5qPDC.cjs.map +0 -1
  233. package/dist/react-BEcdx1f6.js.map +0 -1
  234. package/dist/react-Pp_VSk--.cjs +0 -2
  235. package/dist/react-Pp_VSk--.cjs.map +0 -1
  236. package/dist/studentStore-CEKTtMCh.js.map +0 -1
  237. package/dist/studentStore-DLftfFAl.cjs +0 -2
  238. package/dist/studentStore-DLftfFAl.cjs.map +0 -1
@@ -1,451 +0,0 @@
1
- import { E as e, F as t, H as n, L as r, N as i, O as a, R as o, U as s, V as c, W as l, f as u, gt as d, ht as f, mt as p, p as m, pt as h } from "./geometryState.schema-D0ixyGYE.js";
2
- //#region src/geometry/goalCandidate.ts
3
- function g(e) {
4
- return e.definition.kind === "point";
5
- }
6
- //#endregion
7
- //#region src/geometry/evaluateGraph.ts
8
- var _ = Object.freeze([]);
9
- function v(e) {
10
- let t = e[0] && i(e[0]), n = e[1] && i(e[1]);
11
- return !t || !n ? "degenerate" : c(l(t), l(n)).length > 0 ? "out-of-domain" : "degenerate";
12
- }
13
- function y(e) {
14
- let n = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set(), a = [], o = [];
15
- function s(t) {
16
- let n = e.pathOf?.(t);
17
- return n === void 0 ? {} : { path: n };
18
- }
19
- function c(l) {
20
- let u = n.get(l);
21
- if (u) return u;
22
- if (i.has(l)) return null;
23
- let d = e.definitionOf(l);
24
- if (!d) return null;
25
- let f = o.indexOf(l);
26
- if (f !== -1) return a.push({
27
- entityId: l,
28
- reason: "cycle",
29
- cycle: o.slice(f),
30
- ...s(l)
31
- }), i.add(l), null;
32
- let p = t(d), m = _, h = !0;
33
- if (p.length > 0) {
34
- o.push(l);
35
- let e = [];
36
- for (let t of p) {
37
- let n = c(t);
38
- n ? e.push(n) : h = !1;
39
- }
40
- o.pop(), m = e;
41
- }
42
- if (!h) {
43
- for (let t of p) e.definitionOf(t) === void 0 && a.push({
44
- entityId: l,
45
- reason: "missing-parent",
46
- parentId: t,
47
- ...s(l)
48
- });
49
- return i.add(l), null;
50
- }
51
- let g = r(d, m);
52
- return g ? (n.set(l, g), g) : (a.push({
53
- entityId: l,
54
- reason: v(m),
55
- ...s(l)
56
- }), i.add(l), null);
57
- }
58
- return {
59
- resolve: c,
60
- resolved: n,
61
- issues: a
62
- };
63
- }
64
- //#endregion
65
- //#region src/state/geometryContext.ts
66
- var b = { role: "implicit" }, x = { role: "explicit" }, S = Object.freeze([]), C = class {
67
- constructor(e, t, n, r, i, a, o, s, c, l, u) {
68
- this.exercise = e, this.geometry = t, this.pinned = n, this.draggable = r, this.attemptPoints = i, this.objects = a, this.points = o, this.declaresPoint = s, this.definitionSource = c, this.resolveEntity = l, this.issues = u, this.dependents = null, this.pointIdList = null, this.entityIdList = null;
69
- }
70
- get entityIds() {
71
- return this.entityIdList ?? (this.entityIdList = Object.freeze([...this.pointIds(), ...this.objects.keys()])), this.entityIdList;
72
- }
73
- definitionOf(e) {
74
- return this.definitionSource(e);
75
- }
76
- resolvedOf(e) {
77
- return this.resolveEntity(e) ?? void 0;
78
- }
79
- shapeOf(e) {
80
- let t = this.resolvedOf(e);
81
- return t ? o(t) : void 0;
82
- }
83
- measuredOf(e) {
84
- if (!this.objects.has(e)) return null;
85
- let t = this.resolveEntity(e);
86
- return t ? i(t) : null;
87
- }
88
- kindOf(e) {
89
- return this.declaresPoint(e) ? "point" : this.objects.get(e)?.kind;
90
- }
91
- presentationOf(e) {
92
- return a(this.geometry.presentation, e) || a(this.exercise.presentation, e) || (Object.prototype.hasOwnProperty.call(this.exercise.entities, e) ? x : b);
93
- }
94
- isGiven(e) {
95
- return Object.prototype.hasOwnProperty.call(this.exercise.entities, e);
96
- }
97
- parentsOf(e) {
98
- let n = this.definitionOf(e);
99
- if (!n) return S;
100
- let r = t(n);
101
- return r.length === 0 ? S : [...r];
102
- }
103
- dependentsOf(e) {
104
- return this.dependentsIndex().get(e) ?? S;
105
- }
106
- removalClosureOf(e) {
107
- if (!this.declaresPoint(e) && !this.objects.has(e)) return S;
108
- let t = this.dependentsIndex(), n = [e], r = /* @__PURE__ */ new Set([e]);
109
- for (let e = 0; e < n.length; e += 1) for (let i of t.get(n[e]) ?? S) r.has(i) || (r.add(i), n.push(i));
110
- return n;
111
- }
112
- allowsObjectType(e) {
113
- return this.exercise.allowedObjects.includes(e);
114
- }
115
- allowsTool(e) {
116
- return this.exercise.tools.includes(e);
117
- }
118
- isBuiltFrom(e, t) {
119
- return e === this.exercise && t === this.geometry;
120
- }
121
- pointIds() {
122
- if (this.pointIdList) return this.pointIdList;
123
- let e = [...this.pinned.keys(), ...this.draggable.keys()], t = new Set(e);
124
- for (let n of this.attemptPoints.keys()) t.has(n) || e.push(n);
125
- return this.pointIdList = e, e;
126
- }
127
- dependentsIndex() {
128
- if (this.dependents) return this.dependents;
129
- let e = /* @__PURE__ */ new Map(), t = (t, n) => {
130
- let r = e.get(t);
131
- r ? r.push(n) : e.set(t, [n]);
132
- };
133
- for (let e of this.entityIds) for (let n of this.parentsOf(e)) t(n, e);
134
- return this.dependents = e, e;
135
- }
136
- };
137
- function w(n, r) {
138
- let i = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), l = [];
139
- for (let e in n.entities) {
140
- let t = a(n.entities, e);
141
- t && (t.kind === "point" ? n.draggableEntityIds.includes(e) ? o.set(e, t) : i.set(e, t) : c.set(e, t));
142
- }
143
- for (let t in r.entities) {
144
- let i = a(r.entities, t);
145
- if (!i) continue;
146
- let o = a(n.entities, t);
147
- if (o && e(o, i)) {
148
- l.push({
149
- entityId: t,
150
- reason: "duplicate-id",
151
- path: `geometry.entities.${t}`
152
- });
153
- continue;
154
- }
155
- i.kind === "point" ? s.set(t, i) : c.set(t, i);
156
- }
157
- function u(e) {
158
- return i.get(e) || (s.get(e) ?? o.get(e));
159
- }
160
- function d(e) {
161
- return i.has(e) || s.has(e) || o.has(e);
162
- }
163
- function f(e) {
164
- return u(e) ?? c.get(e);
165
- }
166
- function p(e) {
167
- let t = Object.prototype.hasOwnProperty.call(n.entities, e);
168
- return (s.has(e) ? !i.has(e) : c.has(e) && !t) ? `geometry.entities.${e}` : t ? `exercise.entities.${e}` : void 0;
169
- }
170
- let m = y({
171
- definitionOf: f,
172
- pathOf: p
173
- });
174
- function h(e) {
175
- return d(e) || c.has(e);
176
- }
177
- for (let [e, n] of c) {
178
- let r = p(e);
179
- if (r !== void 0) for (let i of t(n)) h(i) || l.push({
180
- entityId: e,
181
- reason: "missing-parent",
182
- parentId: i,
183
- path: r
184
- });
185
- }
186
- for (let e of i.keys()) m.resolve(e);
187
- for (let e of o.keys()) m.resolve(e);
188
- for (let e of s.keys()) m.resolve(e);
189
- let g = /* @__PURE__ */ new Map();
190
- for (let [e, t] of m.resolved) t.kind === "point" && g.set(e, t.at);
191
- return l.push(...m.issues), new C(n, r, i, o, s, c, g, d, f, m.resolve, Object.freeze(l));
192
- }
193
- //#endregion
194
- //#region src/state/resolvePoints.ts
195
- function T(e, t) {
196
- let n = /* @__PURE__ */ new Map();
197
- for (let [t, r] of Object.entries(e.entities)) r.kind !== "point" && n.set(t, {
198
- id: t,
199
- definition: r
200
- });
201
- for (let [e, r] of Object.entries(t.entities)) r.kind !== "point" && !n.has(e) && n.set(e, {
202
- id: e,
203
- definition: r
204
- });
205
- return n;
206
- }
207
- function E(e, t) {
208
- return w(e, t).points;
209
- }
210
- function D(e) {
211
- return O(e).points;
212
- }
213
- function O(e) {
214
- return w(e, k);
215
- }
216
- var k = {
217
- schemaVersion: 2,
218
- entities: {},
219
- presentation: {},
220
- answerEntityIds: []
221
- }, A = {
222
- ...u.create,
223
- accepts(e, t) {
224
- return e.definition.kind === t.objectType;
225
- },
226
- satisfies() {
227
- return !0;
228
- },
229
- isRelevantAttempt() {
230
- return !0;
231
- },
232
- buildRevealedAnswer() {
233
- return null;
234
- }
235
- };
236
- //#endregion
237
- //#region src/validation/goals/goalContext.ts
238
- function j(e, t) {
239
- let n = e.get(t);
240
- if (!n) throw Error(`Unknown point "${t}" during validation.`);
241
- return n;
242
- }
243
- function M(e, t) {
244
- return [j(e, t[0]), j(e, t[1])];
245
- }
246
- function N(e, n) {
247
- let r = a(e.exercise.entities, n);
248
- if (!r || !m(r.kind)) throw Error(`Unknown reference object "${n}" during validation.`);
249
- let [i, o] = t(r);
250
- if (i === void 0 || o === void 0) throw Error(`Reference object "${n}" has no endpoint pair.`);
251
- return M(e.points, [i, o]);
252
- }
253
- function P(e, t) {
254
- return !g(e) && e.definition.kind === t;
255
- }
256
- function F(e, t) {
257
- return m(t) && P(e, t);
258
- }
259
- function I(e) {
260
- let n = t(e.definition), [r, i] = n;
261
- if (n.length !== 2 || r === void 0 || i === void 0) throw Error(`candidateEndpoints: ${e.definition.kind} is not defined by two points.`);
262
- return [r, i];
263
- }
264
- //#endregion
265
- //#region src/validation/goals/midpoint.ts
266
- function L(e, t) {
267
- let [n, r] = N(t, e.referenceObjectId);
268
- return d(n, r);
269
- }
270
- var R = {
271
- ...u.midpoint,
272
- accepts(e) {
273
- return g(e);
274
- },
275
- satisfies(e, t, n) {
276
- let r = j(n.points, e.id), i = f(r, L(t, n));
277
- return h(i, t.toleranceUnits);
278
- },
279
- isRelevantAttempt() {
280
- return !0;
281
- },
282
- buildRevealedAnswer(e, t) {
283
- return {
284
- type: "point",
285
- at: L(e, t)
286
- };
287
- }
288
- };
289
- //#endregion
290
- //#region src/validation/goals/previewGeometry.ts
291
- function z(e, t, n) {
292
- return {
293
- x: e.x + Math.cos(t) * n,
294
- y: e.y + Math.sin(t) * n
295
- };
296
- }
297
- function B(e, t) {
298
- let [n, r, i, a] = t;
299
- if (e.x >= n && e.x <= i && e.y >= r && e.y <= a) return Math.min(e.x - n, i - e.x, e.y - r, a - e.y);
300
- let o = Math.max(n, Math.min(i, e.x)), s = Math.max(r, Math.min(a, e.y));
301
- return -Math.hypot(e.x - o, e.y - s);
302
- }
303
- function V(e, t) {
304
- let n = e[0];
305
- if (!n) throw Error("mostVisibleInViewport requires at least one candidate.");
306
- let r = B(n, t);
307
- for (let i of e.slice(1)) {
308
- let e = B(i, t);
309
- e > r && (n = i, r = e);
310
- }
311
- return n;
312
- }
313
- function H(e, t) {
314
- let [n, r, i, a] = e, o = Math.max(.5, Math.min(i - n, a - r) * .28);
315
- return Math.min(t || 1, o);
316
- }
317
- function U(e, t, n) {
318
- return e === "line" ? {
319
- type: "line",
320
- through: [t, n]
321
- } : {
322
- type: "segment",
323
- from: t,
324
- to: n
325
- };
326
- }
327
- //#endregion
328
- //#region src/validation/goals/parallel.ts
329
- var W = {
330
- ...u.parallel,
331
- accepts(e, t) {
332
- return F(e, t.objectType);
333
- },
334
- satisfies(e, t, r) {
335
- let i = I(e);
336
- if (!i.includes(t.throughPointId)) return !1;
337
- let [a, o] = N(r, t.referenceObjectId), [s, c] = M(r.points, i), l = n(a, o, s, c);
338
- return h(l, t.toleranceDegrees);
339
- },
340
- isRelevantAttempt(e, n) {
341
- return t(e.definition).includes(n.throughPointId);
342
- },
343
- buildRevealedAnswer(e, t) {
344
- let [n, r] = N(t, e.referenceObjectId), i = j(t.points, e.throughPointId), a = Math.atan2(r.y - n.y, r.x - n.x), o = H(t.exercise.viewport, f(n, r)), s = V([z(i, a, o), z(i, a + Math.PI, o)], t.exercise.viewport);
345
- return U(e.objectType, i, s);
346
- }
347
- }, G = {
348
- ...u.perpendicular,
349
- accepts(e, t) {
350
- return F(e, t.objectType);
351
- },
352
- satisfies(e, t, r) {
353
- let i = I(e);
354
- if (!i.includes(t.throughPointId)) return !1;
355
- let [a, o] = N(r, t.referenceObjectId), [s, c] = M(r.points, i), l = n(a, o, s, c);
356
- return p(l, 90, t.toleranceDegrees);
357
- },
358
- isRelevantAttempt(e, n) {
359
- return t(e.definition).includes(n.throughPointId);
360
- },
361
- buildRevealedAnswer(e, t) {
362
- let [n, r] = N(t, e.referenceObjectId), i = j(t.points, e.throughPointId), a = Math.atan2(r.y - n.y, r.x - n.x), o = H(t.exercise.viewport, f(n, r)), s = V([z(i, a + Math.PI / 2, o), z(i, a - Math.PI / 2, o)], t.exercise.viewport);
363
- return U(e.objectType, i, s);
364
- }
365
- }, K = {
366
- ...u.segmentLength,
367
- accepts(e, t) {
368
- return P(e, t.objectType);
369
- },
370
- satisfies(e, t, n) {
371
- let [r, i] = M(n.points, I(e));
372
- return p(f(r, i), t.targetLength, t.toleranceUnits);
373
- },
374
- isRelevantAttempt() {
375
- return !0;
376
- },
377
- buildRevealedAnswer(e, t) {
378
- let [n, r, i, a] = t.exercise.viewport, o = (n + i) / 2, s = (r + a) / 2;
379
- return {
380
- type: "segment",
381
- from: {
382
- x: o - e.targetLength / 2,
383
- y: s
384
- },
385
- to: {
386
- x: o + e.targetLength / 2,
387
- y: s
388
- }
389
- };
390
- }
391
- };
392
- //#endregion
393
- //#region src/validation/goals/throughPoints.ts
394
- function q(e, t) {
395
- if (e.length !== t.length) return !1;
396
- if (e.length === 2) {
397
- let [n, r] = e, [i, a] = t;
398
- return s(n, i) && s(r, a) || s(n, a) && s(r, i);
399
- }
400
- throw Error(`satisfiesThroughPoints: unsupported point count ${e.length}`);
401
- }
402
- var J = {
403
- ...u.throughPoints,
404
- accepts(e, t) {
405
- return F(e, t.objectType);
406
- },
407
- satisfies(e, n, r) {
408
- return q(t(e.definition).map((e) => j(r.points, e)), n.pointIds.map((e) => j(r.points, e)));
409
- },
410
- isRelevantAttempt(e, n, r) {
411
- let i = t(e.definition).map((e) => j(r.points, e)), a = n.pointIds.map((e) => j(r.points, e));
412
- return i.some((e) => a.some((t) => s(e, t)));
413
- },
414
- buildRevealedAnswer(e, t) {
415
- let [n, r] = e.pointIds.map((e) => j(t.points, e));
416
- return U(e.objectType, n, r);
417
- }
418
- }, Y = Object.freeze({
419
- create: A,
420
- throughPoints: J,
421
- perpendicular: G,
422
- parallel: W,
423
- segmentLength: K,
424
- midpoint: R
425
- });
426
- function X(e) {
427
- let t = Y[e];
428
- if (!t) throw Error(`No goal kind handler registered for "${e}"`);
429
- return t;
430
- }
431
- function Z(e) {
432
- return X(e.type).referencedGivenIds(e);
433
- }
434
- function Q(e, t) {
435
- return X(t.type).accepts(e, t);
436
- }
437
- function $(e, t, n) {
438
- let r = X(t.type);
439
- return r.accepts(e, t) && r.satisfies(e, t, n);
440
- }
441
- function ee(e, t, n) {
442
- let r = X(t.type);
443
- return r.accepts(e, t) && r.isRelevantAttempt(e, t, n);
444
- }
445
- function te(e, t) {
446
- return X(e.type).buildRevealedAnswer(e, t);
447
- }
448
- //#endregion
449
- export { Z as a, T as c, w as d, g as f, ee as i, D as l, Q as n, te as o, $ as r, O as s, X as t, E as u };
450
-
451
- //# sourceMappingURL=goals-C3ZwbEh_.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"goals-C3ZwbEh_.js","names":[],"sources":["../src/geometry/goalCandidate.ts","../src/geometry/evaluateGraph.ts","../src/state/geometryContext.ts","../src/state/resolvePoints.ts","../src/validation/goals/create.ts","../src/validation/goals/goalContext.ts","../src/validation/goals/midpoint.ts","../src/validation/goals/previewGeometry.ts","../src/validation/goals/parallel.ts","../src/validation/goals/perpendicular.ts","../src/validation/goals/segmentLength.ts","../src/validation/goals/throughPoints.ts","../src/validation/goals/index.ts"],"sourcesContent":["import type { PointDefinition } from './entityModel'\nimport type { SceneEntity } from './hitTest'\n\n// What a goal handler is asked to judge: one entity of the student's answer, as\n// the `{ id, definition }` pair every other consumer already receives a stored\n// entity as.\n//\n// It was a union — a v1 `GeometryObject` or a `CandidatePoint` carrying its own\n// coordinates — because student work was two lists, `constructions` and\n// `constructedPointIds`, and a goal kind may care about either. A v2 attempt\n// keeps one `entities` record and one `answerEntityIds` list, so a candidate is\n// one shape and its kind is the entity's own (M2.6.c.2). Coordinates are not on\n// it: every candidate a handler is given resolves, and `ValidationContext.points`\n// is where the scene says where it is.\nexport type GoalCandidate = SceneEntity\n\n/** A candidate that is a point — the only narrowing a handler asks for. */\nexport type CandidatePoint = GoalCandidate & { definition: PointDefinition }\n\nexport function isCandidatePoint(candidate: GoalCandidate): candidate is CandidatePoint {\n return candidate.definition.kind === 'point'\n}\n","// The construction graph evaluation (M2.4) — RFC 0001 § Dependency traversal.\n//\n// One walk for the whole graph, kind-blind. Before this file the traversal\n// lived inside `state/geometryContext.ts` as two mutually recursive halves that\n// each knew what the other could be: a point resolved *objects* for parents, an\n// object resolved *points*. Those are facts about v1's stored shape — origins\n// name objects, constructions name points — not about the graph, and they are\n// what a circle derived from a centre point, or a point on a circle, would each\n// have had to edit.\n//\n// Here a parent is an entity. `resolve()` asks the source for a definition,\n// resolves whatever that definition names, and hands the resolved parents to\n// the registry in declaration order. Adding a kind adds no line to this file:\n// what a kind is built on is `parents()`, and what it does with them is\n// `resolve()`, both in `geometry/entities/`.\n//\n// **Nothing here reads a document.** The source is `definitionOf(id)`, so the\n// v1 rules that decide which declaration wins an id — a pinned given outranks\n// an attempt's copy of it, an object outranks a point claiming the same id —\n// stay in the context that owns those documents, and this module is the same\n// walk in a browser, in bare Node and in a test that hands it a literal map.\n//\n// **Failure is absence** (RFC 0001 § Q4): an entity that cannot be placed is\n// missing from `resolved`, and why it is missing is an issue. Nothing throws,\n// because a student mid-construction is allowed to have a figure that briefly\n// makes no sense.\nimport { measuredOfResolved, parentsOfDefinition, resolveDefinition } from './entities'\nimport type {\n EntityDefinition,\n EntityId,\n Evaluation,\n EvaluationIssue,\n ResolvedEntity,\n} from './entityModel'\nimport { intersectionsOf, withoutBounds } from '../measure/geometryAdapter'\n\nconst NO_PARENTS: readonly ResolvedEntity[] = Object.freeze([])\n\n/**\n * Where definitions come from. A `GeometryContext` implements this over two v1\n * documents; a test implements it over a `Map`.\n *\n * `definitionOf` returning `undefined` is what \"nothing declares that id\" means,\n * and it is the only thing the walk treats as a missing parent — a parent that\n * exists but cannot be used is a degenerate construction, not a missing one.\n */\nexport interface GraphSource {\n definitionOf(id: EntityId): EntityDefinition | undefined\n\n // Where the declaration lives, for an issue's `path`. Optional: a map of\n // definitions has no document to point at.\n pathOf?(id: EntityId): string | undefined\n}\n\n/**\n * A memoized walk over one source. Resolution is lazy — a caller drives it by\n * asking — and every answer is cached, including a failure, so evaluation is\n * linear in the graph's edges rather than exponential on a diamond.\n *\n * An evaluator is single-use and holds the results of its own walk. It is not a\n * cache across scenes: the context builds one per snapshot, because a cache\n * keyed on document identity would make every benchmark measure a cache hit.\n */\nexport interface GraphEvaluator {\n // A property rather than a method: it is a closure over the walk's own state,\n // and the context hands it straight to its index, unbound.\n readonly resolve: (id: EntityId) => ResolvedEntity | null\n\n // Everything resolved so far, in the order the walk completed it — a parent\n // before the entity built on it.\n readonly resolved: ReadonlyMap<EntityId, ResolvedEntity>\n\n // Grows as the walk proceeds; read it once the caller has driven the walk.\n readonly issues: readonly EvaluationIssue[]\n}\n\n// Why a construction that named everything it needed still produced nothing.\n// `intersectionsOf()` returns an empty array both for \"they never meet\" and for\n// \"they meet past the end of a segment\", so the two are told apart by asking the\n// same seam again with the operands unbounded: still empty means genuinely\n// parallel, collinear, or — once circles exist — disjoint, nested or coincident.\n// Which kinds have an unbounded form is the seam's own knowledge\n// (`withoutBounds`), so this stayed kind-blind when the circle arrived.\n//\n// Reached only after the registry has already declined to resolve, so it costs\n// nothing on the path where the construction is fine.\nfunction resolutionFailure(parents: readonly ResolvedEntity[]): 'degenerate' | 'out-of-domain' {\n const first = parents[0] && measuredOfResolved(parents[0])\n const second = parents[1] && measuredOfResolved(parents[1])\n if (!first || !second) return 'degenerate'\n const unbounded = intersectionsOf(withoutBounds(first), withoutBounds(second))\n return unbounded.length > 0 ? 'out-of-domain' : 'degenerate'\n}\n\nexport function createGraphEvaluator(source: GraphSource): GraphEvaluator {\n const resolved = new Map<EntityId, ResolvedEntity>()\n const failed = new Set<EntityId>()\n const issues: EvaluationIssue[] = []\n // A stack rather than a set, so a cycle can be reported as the ring it is.\n const visiting: EntityId[] = []\n\n function locate(id: EntityId): { path?: string } {\n const path = source.pathOf?.(id)\n return path === undefined ? {} : { path }\n }\n\n function resolve(id: EntityId): ResolvedEntity | null {\n const cached = resolved.get(id)\n if (cached) return cached\n // A failure is cached too: an entity that could not be placed is asked\n // about once per entity built on it, and re-walking its parents would turn\n // a shared broken ancestor into repeated work and repeated issues.\n if (failed.has(id)) return null\n\n const definition = source.definitionOf(id)\n // Nothing declares this id. Whoever named it says so — with the path of the\n // declaration that did the naming, which is the one worth pointing at.\n if (!definition) return null\n\n // The stack carries every kind, which is what makes a point defined on an\n // object defined on that point report as the ring it is rather than as a\n // point that mysteriously failed to place.\n const cycleStart = visiting.indexOf(id)\n if (cycleStart !== -1) {\n issues.push({\n entityId: id,\n reason: 'cycle',\n cycle: visiting.slice(cycleStart),\n ...locate(id),\n })\n failed.add(id)\n return null\n }\n\n const parentIds = parentsOfDefinition(definition)\n // A free point is most of the points in any figure and has no parents at\n // all; it pays for neither the array nor the stack frame.\n let parents: readonly ResolvedEntity[] = NO_PARENTS\n let complete = true\n if (parentIds.length > 0) {\n visiting.push(id)\n const resolvedParents: ResolvedEntity[] = []\n // Every parent is visited even after one has failed: resolving the second\n // one is what reports its own cycle or vanished intersection.\n for (const parentId of parentIds) {\n const parent = resolve(parentId)\n if (parent) resolvedParents.push(parent)\n else complete = false\n }\n visiting.pop()\n parents = resolvedParents\n }\n\n if (!complete) {\n for (const parentId of parentIds) {\n if (source.definitionOf(parentId) === undefined) {\n issues.push({ entityId: id, reason: 'missing-parent', parentId, ...locate(id) })\n }\n }\n failed.add(id)\n return null\n }\n\n // `resolve()` reads its parents positionally, so an incomplete construction\n // is never offered to the registry: a short list would slide the parents\n // that did resolve into the wrong slots and produce geometry the document\n // never described.\n const value = resolveDefinition(definition, parents)\n if (!value) {\n // Every parent was there and the construction still defines nothing:\n // parallel now, or the crossing slid off the end of a segment. Which of\n // the two it is is worth saying.\n issues.push({ entityId: id, reason: resolutionFailure(parents), ...locate(id) })\n failed.add(id)\n return null\n }\n resolved.set(id, value)\n return value\n }\n\n return { resolve, resolved, issues }\n}\n\n/**\n * The whole graph at once — RFC 0001's `evaluate()`, and the entry point for a\n * caller holding definitions rather than documents.\n *\n * Deterministic and free of any environment: the same map produces the same\n * resolved scene and the same issues in a browser and in bare Node, because the\n * only inputs are the definitions and the only order is the map's own.\n */\nexport function evaluateGraph(definitions: ReadonlyMap<EntityId, EntityDefinition>): Evaluation {\n const evaluator = createGraphEvaluator({ definitionOf: (id) => definitions.get(id) })\n for (const id of definitions.keys()) evaluator.resolve(id)\n return { resolved: evaluator.resolved, issues: Object.freeze([...evaluator.issues]) }\n}\n","// The indexed scene every consumer reads (RFC 0001 § scene, M2.2).\n//\n// Before this file, four consumers each rebuilt the same knowledge from the\n// two documents on every call: `resolvePoints()` scanned the givens twice and\n// walked the graph, `validateGeometryState()` re-checked endpoints against the\n// resolved map, `studentStore.ts` ran a fixpoint loop over `endpointsOf()` and\n// `originParents()` to find a deletion cascade, and `moveStudentPoint()` built\n// `objectsInScope()` and resolved every point again to slide one point along\n// one object. Each was correct and none of them shared an index.\n//\n// One pass now builds all of it: the point origins with the exercise's\n// grading-integrity rules already applied, the objects in scope, ownership,\n// the resolved coordinates, and the structured issues that indexing is the\n// first thing able to see — an id collision is only visible to something\n// reading the exercise and the attempt at once.\n//\n// **Both documents are v2** (M2.6.c.2). Each is an `entities` record of\n// definitions with a sibling `presentation` record, so this file no longer\n// translates anything: what is left of the two halves is the part that was\n// never about a stored shape — which declaration wins a contested id, which\n// order the points are resolved in, and which document each `presentation`\n// default comes from. Since ADR 0008 § Amendment an attempt carries only\n// student work, so the ids the two documents share are exactly the given points\n// the student has moved.\n//\n// **What is eager and what is not, and why.** `resolvePoints()` runs per\n// pointer event and is the hottest path in the M1.8 baseline, so the build\n// pass does what resolution needs and nothing else: the two lookup maps, the\n// issues, and the resolved entities in v1's order. The reverse edges are built\n// the first time a deletion asks for them, ownership the first time something\n// asks who owns an entity, and no id list is materialized until it is read —\n// allocating several collections for every entity in the scene is what a\n// 100-object figure cannot afford.\n//\n// Objects still resolve on demand, and M2.4 measured what happens when they do\n// not: walking every object a figure merely *draws* — rather than every object\n// something is built on — cost about as much again as the whole resolution pass\n// at 100 objects. So an object nothing depends on is scanned rather than\n// resolved, which is enough to report the one thing a broken declaration can\n// say without coordinates: a parent that was never declared.\n//\n// **Per-kind behaviour left this file at M2.3.** Resolution, shapes, the measured\n// reduction and the distances are the registry's (`geometry/entities/`), and the\n// walk that drives them no longer knows what a segment is made of; the v1\n// declaration → definition translation moved out to `geometry/v1Bridge.ts` at\n// M2.3.b, when hit testing and snapping turned out to need the same one.\n//\n// **The walk itself left this file at M2.4.** `geometry/evaluateGraph.ts` holds\n// it, kind-blind and document-free; what stays here is everything that is about\n// *these two documents* — which declaration wins a contested id, which order the\n// points are resolved in, and where in the source a broken declaration lives.\n// The two mutually recursive halves that used to live here, one resolving\n// objects for a point's parents and one resolving points for an object's, were\n// v1's stored shape written into the graph.\n//\n// **A context is a snapshot, never a subscription.** It holds the exercise and\n// geometry it was built from; the student store replaces geometry on every\n// commit rather than mutating it, so `isBuiltFrom()` is an identity check and\n// a context that answers `false` is stale and must be rebuilt. Nothing here\n// caches across calls — a hidden cache keyed on document identity would make\n// every benchmark measure a cache hit.\nimport { measuredOfResolved, parentsOfDefinition, shapeOfResolved } from '../geometry/entities'\nimport type {\n EntityDefinition,\n EntityId,\n EntityKind,\n EntityPresentation,\n EvaluationIssue,\n GeometryContext,\n PointDefinition,\n ResolvedEntity,\n ShapeDescriptor,\n} from '../geometry/entityModel'\nimport { createGraphEvaluator } from '../geometry/evaluateGraph'\nimport { entryOf } from '../geometry/entityRecord'\nimport type { Point, PointId } from '../geometry/point'\nimport type { MeasuredObject } from '../measure/geometryAdapter'\nimport { isCrossDocumentIdCollision } from '../schemas/entityDocument'\nimport type { GeometryExercise, ToolName } from '../schemas/exercise.schema'\nimport type { GeometryState } from '../schemas/geometryState.schema'\nimport type { ObjectTypeName } from '../schemas/objectTypeName.schema'\n\n/**\n * What M2.2 adds on top of the frozen `GeometryContext` minimum. The extra\n * members are the lookups the four consumers actually asked for — the graph\n * edges in both directions, the measured form the JSXGraph seam wants, the\n * exercise's own capabilities, and the staleness check.\n *\n * Read-only to consumers: every collection is handed out as `readonly` or as a\n * fresh array, and no index another consumer is reading is ever exposed.\n */\nexport interface IndexedGeometryContext extends GeometryContext {\n // The kind of an entity without materializing its definition.\n kindOf(id: EntityId): EntityKind | undefined\n\n // What `id` is built on, in declaration order — the registry's `parents()`,\n // answered for a stored id.\n parentsOf(id: EntityId): readonly EntityId[]\n\n // Everything that disappears with `id`, transitively, `id` included. The\n // fixpoint loop in `studentStore.ts` was this.\n removalClosureOf(id: EntityId): readonly EntityId[]\n\n // Resolved points in v1 resolution order — pinned givens, draggable givens,\n // then the attempt's own — because `findPointAt()` promotes the first point\n // it finds within reuse tolerance and the order decides which one that is.\n readonly points: ReadonlyMap<PointId, Point>\n\n // The two-point reduction the measurement seam accepts, `null` for anything\n // that has no coordinates right now — the registry's `toMeasured()`, applied\n // to the resolved form this context already holds.\n measuredOf(id: EntityId): MeasuredObject | null\n\n // Exercise capabilities, so a caller asking \"may the student draw a line?\"\n // reads the question off the scene it already has.\n allowsObjectType(type: ObjectTypeName): boolean\n allowsTool(tool: ToolName): boolean\n\n // False once either document has been replaced: rebuild rather than answer\n // from a snapshot of a figure that no longer exists.\n isBuiltFrom(exercise: GeometryExercise, geometry: GeometryState): boolean\n}\n\nconst IMPLICIT: EntityPresentation = { role: 'implicit' }\nconst EXPLICIT: EntityPresentation = { role: 'explicit' }\nconst NO_IDS: readonly EntityId[] = Object.freeze([])\n\n// The index itself. A class rather than an object of closures because a\n// context is built on every pointer event, and prototype methods cost one\n// allocation where a dozen closures cost a dozen.\n//\n// The three point sources are kept apart rather than merged into one map, in\n// that order of precedence: merging them costs an `Object.entries()` over the\n// attempt's whole point record, which measures slower than the entire\n// resolution pass it was meant to speed up. `pointDefinitionOf()` is the merge,\n// done per lookup.\nclass SceneIndex implements IndexedGeometryContext {\n private dependents: Map<EntityId, EntityId[]> | null = null\n private pointIdList: readonly PointId[] | null = null\n private entityIdList: readonly EntityId[] | null = null\n\n constructor(\n private readonly exercise: GeometryExercise,\n private readonly geometry: GeometryState,\n // Given points the attempt may not move, and given points it may. A\n // position is a valid free origin, which is why both are origin sources.\n private readonly pinned: Map<PointId, PointDefinition>,\n private readonly draggable: Map<PointId, PointDefinition>,\n // The attempt's own points, plus its copy of a given point it has moved.\n private readonly attemptPoints: Map<PointId, PointDefinition>,\n private readonly objects: Map<EntityId, EntityDefinition>,\n readonly points: ReadonlyMap<PointId, Point>,\n // The two views of one rule about which declaration wins a contested id,\n // both built where the documents are read; see `buildGeometryContext()`.\n // `declaresPoint()` is the membership half, asked where materializing a\n // definition to learn one field would allocate on the hot path.\n private readonly declaresPoint: (id: EntityId) => boolean,\n private readonly definitionSource: (id: EntityId) => EntityDefinition | undefined,\n // The walk's memo, already driven over the whole scene: every lookup below\n // is a cache hit, and an entity that could not be placed answers `null`.\n private readonly resolveEntity: (id: EntityId) => ResolvedEntity | null,\n readonly issues: readonly EvaluationIssue[],\n ) {}\n\n // Points first, in resolution order, then the objects in scope: one\n // namespace, listed the way the two halves of it were indexed.\n get entityIds(): readonly EntityId[] {\n this.entityIdList ??= Object.freeze([...this.pointIds(), ...this.objects.keys()])\n return this.entityIdList\n }\n\n definitionOf(id: EntityId): EntityDefinition | undefined {\n return this.definitionSource(id)\n }\n\n // Every resolved form is the one the walk already produced, points included:\n // one memo for the whole graph is what made the traversal kind-blind, and it\n // is why a repeated lookup allocates nothing.\n resolvedOf(id: EntityId): ResolvedEntity | undefined {\n return this.resolveEntity(id) ?? undefined\n }\n\n shapeOf(id: EntityId): ShapeDescriptor | undefined {\n const resolved = this.resolvedOf(id)\n return resolved ? shapeOfResolved(resolved) : undefined\n }\n\n // Guarded on `objects` rather than asked of every entity, because the answer\n // for a point is `null` and finding that out would allocate its resolved form\n // first — and `moveStudentPoint()` asks this per pointer event.\n measuredOf(id: EntityId): MeasuredObject | null {\n if (!this.objects.has(id)) return null\n const resolved = this.resolveEntity(id)\n return resolved ? measuredOfResolved(resolved) : null\n }\n\n kindOf(id: EntityId): EntityKind | undefined {\n if (this.declaresPoint(id)) return 'point'\n return this.objects.get(id)?.kind\n }\n\n // Two sibling `presentation` records and two different defaults, which is the\n // one place the documents are not interchangeable (ADR 0008): an exercise\n // entity with no entry is `explicit`, because an exercise draws what it\n // declares, while an attempt entity with no entry is `implicit`, because a\n // student's figure is full of scaffolding nobody asked to see.\n //\n // The attempt's entry is read first, and the *exercise's* entry — not either\n // default — is what a missing one falls back to: the only id both documents\n // declare is a given point the student has moved, and moving a labelled given\n // does not unlabel it.\n presentationOf(id: EntityId): EntityPresentation {\n const attemptEntry = entryOf(this.geometry.presentation, id)\n if (attemptEntry) return attemptEntry\n const exerciseEntry = entryOf(this.exercise.presentation, id)\n if (exerciseEntry) return exerciseEntry\n if (Object.prototype.hasOwnProperty.call(this.exercise.entities, id)) return EXPLICIT\n return IMPLICIT\n }\n\n // Which document declares it, which is the whole of ownership (RFC 0001 § Q2).\n // The lazy id set this replaces existed only because v1 kept the givens in an\n // array; a record answers it without one.\n isGiven(id: EntityId): boolean {\n return Object.prototype.hasOwnProperty.call(this.exercise.entities, id)\n }\n\n // Copied, not handed through. Since M2.6.c.1 the exercise's definitions are\n // the parsed document's own values, so a segment's `parents` tuple *is* the\n // stored one — and this is the member whose contract says an edge list is\n // materialized per call and editing one edits nothing. Deletion is the only\n // caller that asks it per entity, and it asks once.\n parentsOf(id: EntityId): readonly EntityId[] {\n const definition = this.definitionOf(id)\n if (!definition) return NO_IDS\n const parents = parentsOfDefinition(definition)\n return parents.length === 0 ? NO_IDS : [...parents]\n }\n\n dependentsOf(id: EntityId): readonly EntityId[] {\n return this.dependentsIndex().get(id) ?? NO_IDS\n }\n\n removalClosureOf(id: EntityId): readonly EntityId[] {\n if (!this.declaresPoint(id) && !this.objects.has(id)) return NO_IDS\n const index = this.dependentsIndex()\n const closure: EntityId[] = [id]\n const seen = new Set<EntityId>([id])\n // Breadth-first over the reverse edges. The fixpoint loop this replaces\n // rescanned both documents once per entity it removed; here every edge is\n // visited once.\n for (let cursor = 0; cursor < closure.length; cursor += 1) {\n for (const dependentId of index.get(closure[cursor]!) ?? NO_IDS) {\n if (seen.has(dependentId)) continue\n seen.add(dependentId)\n closure.push(dependentId)\n }\n }\n return closure\n }\n\n allowsObjectType(type: ObjectTypeName): boolean {\n return this.exercise.allowedObjects.includes(type)\n }\n\n allowsTool(tool: ToolName): boolean {\n return this.exercise.tools.includes(tool)\n }\n\n isBuiltFrom(exercise: GeometryExercise, geometry: GeometryState): boolean {\n return exercise === this.exercise && geometry === this.geometry\n }\n\n // Every point id, in resolution order, failures included.\n private pointIds(): readonly PointId[] {\n if (this.pointIdList) return this.pointIdList\n const ids = [...this.pinned.keys(), ...this.draggable.keys()]\n const seen = new Set(ids)\n for (const id of this.attemptPoints.keys()) {\n if (!seen.has(id)) ids.push(id)\n }\n this.pointIdList = ids\n return ids\n }\n\n // Only deletion asks for the reverse edges, and paying for them inside every\n // `resolvePoints()` call would spend the resolution budget on a question\n // resolution never asks.\n private dependentsIndex(): Map<EntityId, EntityId[]> {\n if (this.dependents) return this.dependents\n const index = new Map<EntityId, EntityId[]>()\n const add = (parentId: EntityId, id: EntityId): void => {\n const existing = index.get(parentId)\n if (existing) existing.push(id)\n else index.set(parentId, [id])\n }\n // One loop over one namespace: the edges a deletion inverts are the same\n // edges the walk followed, read through the same `parents()`.\n for (const id of this.entityIds) {\n for (const parentId of this.parentsOf(id)) add(parentId, id)\n }\n this.dependents = index\n return index\n }\n}\n\n/**\n * Indexes an exercise and one attempt against it into a single read-only\n * scene, resolving every point once.\n *\n * Both arguments are the parsed, schema-checked types, which is what \"built\n * only from validated data\" means here: there is no second builder taking\n * `unknown`, and a caller holding untrusted JSON goes through\n * `validateGeometryStateInput()` first, exactly as it does today.\n *\n * Nothing throws. A document the schemas would reject — a duplicate id, a\n * parent that does not exist, a cycle — indexes anyway and reports what it\n * found in `issues`, because the authoring warnings and the dev page must\n * describe a broken exercise rather than disappear on it.\n */\nexport function buildGeometryContext(\n exercise: GeometryExercise,\n geometry: GeometryState,\n): IndexedGeometryContext {\n const pinned = new Map<PointId, PointDefinition>()\n const draggable = new Map<PointId, PointDefinition>()\n const attemptPoints = new Map<PointId, PointDefinition>()\n const objects = new Map<EntityId, EntityDefinition>()\n const issues: EvaluationIssue[] = []\n\n // Where the exercise, not the attempt, decides a point's coordinates.\n //\n // A stored GeometryState is untrusted input: it arrives from a browser, a\n // database row, or a request body. Reading a *pinned* given point's position\n // out of it would let a submission move the very reference its goals are\n // measured against — rotate the given segment and any answer is\n // perpendicular to it. So a given point the student cannot drag is always\n // placed by the exercise, whatever the attempt claims.\n //\n // A draggable given is the opposite case: moving it is the student's\n // prerogative, so the attempt's position wins and the exercise only supplies\n // a starting position for one the attempt never mentions. Neither case is an\n // id collision: re-declaring a given point is how the student moves it.\n // What splits the exercise in three is `draggableEntityIds`, which the schema\n // has already restricted to points: a point named there is the student's to\n // move, every other point is the exercise's, and everything else is an object.\n //\n // `for...in` rather than `Object.entries()`, and `includes()` rather than a\n // `Set`, for the reason the rest of this pass is written the way it is: the\n // build runs per pointer event, `Object.entries()` allocates a pair array as\n // long as the document, and an exercise's draggable list is a handful of ids\n // at most — a `Set` over it costs more to build than the scans it saves.\n for (const id in exercise.entities) {\n const definition = entryOf(exercise.entities, id)\n if (!definition) continue\n if (definition.kind !== 'point') {\n objects.set(id, definition)\n } else if (exercise.draggableEntityIds.includes(id)) {\n draggable.set(id, definition)\n } else {\n pinned.set(id, definition)\n }\n }\n\n // The attempt's own declarations, with the one rule only a reader of both\n // documents can apply (ADR 0008 § Structural invariants): re-declaring a\n // *given point* as a point is how the student moves it and is not a\n // collision, while every other id the two documents share is one — an\n // attempt object claiming a given's id, or a point claiming a given object's.\n // A dropped duplicate stays dropped everywhere below, so nothing it names is\n // reported a second time.\n //\n // Both documents are records, so an id cannot be claimed twice *inside*\n // either one and the duplicate passes v1 needed over its two arrays are gone\n // with the arrays.\n for (const id in geometry.entities) {\n const definition = entryOf(geometry.entities, id)\n if (!definition) continue\n const given = entryOf(exercise.entities, id)\n // The same rule `validateGeometryStateInput()` refuses the document over,\n // asked in one place so a loaded document and an indexed one cannot\n // disagree about which shared ids are collisions (M2.G.2).\n if (given && isCrossDocumentIdCollision(given, definition)) {\n issues.push({ entityId: id, reason: 'duplicate-id', path: `geometry.entities.${id}` })\n continue\n }\n if (definition.kind === 'point') attemptPoints.set(id, definition)\n else objects.set(id, definition)\n }\n\n // Which declaration wins a contested id, in one place. The exercise places a\n // pinned given whatever the attempt claims; everything else the attempt\n // declares is its own, and a draggable given the attempt never mentioned\n // keeps the starting position the exercise gave it — the rule the index\n // answers lookups with and the rule the walk resolves through, so the two can\n // no longer disagree.\n function pointDefinitionOf(id: EntityId): PointDefinition | undefined {\n const pinnedDefinition = pinned.get(id)\n if (pinnedDefinition) return pinnedDefinition\n return attemptPoints.get(id) ?? draggable.get(id)\n }\n\n // The membership half of the same rule, for the callers that only need to\n // know whether anything declares `id` as a point — `kindOf()` and\n // `presentationOf()` are asked per entity while a figure is drawn, and\n // materializing a definition to answer them would allocate one object per\n // lookup.\n function declaresPoint(id: EntityId): boolean {\n return pinned.has(id) || attemptPoints.has(id) || draggable.has(id)\n }\n\n // The whole rule, in the vocabulary the graph speaks.\n function definitionOf(id: EntityId): EntityDefinition | undefined {\n return pointDefinitionOf(id) ?? objects.get(id)\n }\n\n // Only an issue pays for this, and only the issues the walk finds, which is\n // why the build itself never indexes the document paths. It names the\n // declaration that *won* the id: a pinned given is the exercise's whatever\n // the attempt claims, so pointing at the attempt's dropped copy would send a\n // reader to a line that changes nothing.\n function pathOf(id: EntityId): string | undefined {\n const declaredByExercise = Object.prototype.hasOwnProperty.call(exercise.entities, id)\n // A pinned given is the exercise's whatever the attempt claims, and an\n // attempt entity the claim pass dropped as a duplicate is not a line worth\n // sending a reader to either; both are read off the maps that pass built\n // rather than off the documents.\n const attemptWon = attemptPoints.has(id)\n ? !pinned.has(id)\n : objects.has(id) && !declaredByExercise\n if (attemptWon) return `geometry.entities.${id}`\n return declaredByExercise ? `exercise.entities.${id}` : undefined\n }\n\n const evaluator = createGraphEvaluator({ definitionOf, pathOf })\n\n // An object naming a parent that was never declared, reported against the\n // declaration that names it — walked from the documents rather than from the\n // graph, because that is where each issue's path comes from, and because an\n // authoring warning about a broken given must not depend on a student having\n // happened to build something on it.\n //\n // Scanned rather than resolved, which is the same decision as leaving objects\n // on demand: driving the walk over every object a figure merely *draws* added\n // about 70% to a 100-object build, and a missing parent is the one thing a\n // broken declaration can say without any coordinates at all.\n //\n // **Objects only.** Every point of either document is driven through the walk\n // below, which reports its missing parents against the same path — a point\n // scanned here as well would be reported twice for one fault.\n\n // Whether anything declares `id`, without materializing what it declares:\n // three lookups against the maps the claim pass already built, where asking\n // `definitionOf()` would allocate a definition per parent of every object in\n // the figure.\n function isDeclared(id: EntityId): boolean {\n return declaresPoint(id) || objects.has(id)\n }\n\n for (const [id, definition] of objects) {\n const path = pathOf(id)\n if (path === undefined) continue\n for (const parentId of parentsOfDefinition(definition)) {\n if (!isDeclared(parentId)) {\n issues.push({ entityId: id, reason: 'missing-parent', parentId, path })\n }\n }\n }\n\n // Points first and givens before them, so a given point the attempt never\n // stored still renders and can still anchor a goal, and so that the resolved\n // order is v1's: `findPointAt()` promotes the first point within reuse\n // tolerance, and the order decides which one that is.\n for (const id of pinned.keys()) evaluator.resolve(id)\n for (const id of draggable.keys()) evaluator.resolve(id)\n for (const id of attemptPoints.keys()) evaluator.resolve(id)\n // The point-shaped view of the walk's memo, which resolvers, renderers and\n // goal handlers still ask for. Insertion order is the order the walk\n // completed each entity in, so v1's resolution order survives the filter.\n const points = new Map<PointId, Point>()\n for (const [id, resolved] of evaluator.resolved) {\n if (resolved.kind === 'point') points.set(id, resolved.at)\n }\n\n // The issues the documents alone could show — an id claimed twice, a parent\n // nothing declares — then what the walk found. An object resolved later, on\n // demand, adds to the evaluator's own list and not to this frozen one: what a\n // context reports must not depend on which lookups a consumer happened to\n // make.\n issues.push(...evaluator.issues)\n\n return new SceneIndex(\n exercise,\n geometry,\n pinned,\n draggable,\n attemptPoints,\n objects,\n points,\n declaresPoint,\n definitionOf,\n evaluator.resolve,\n Object.freeze(issues),\n )\n}\n","// Turns stored point origins into coordinates by walking the dependency graph.\n// Coordinates are never stored for a derived point, so there is no cached copy\n// to go stale: dragging a parent changes its children on the next resolve.\n//\n// One-directional derivation only (parents -> children). This is not a\n// constraint solver: nothing here maintains a relationship while the student\n// drags, which would solve the exercise for them (see FUTURE.md 1.3a).\n//\n// The graph walk itself moved to `geometryContext.ts` at M2.2, where the same\n// pass also indexes ownership, the parent and reverse edges and the structured\n// issues. What is left here is the point-shaped view of it, which is what\n// renderers, goal handlers and the store still ask for.\nimport type { EntityId } from '../geometry/entityModel'\nimport type { SceneEntity } from '../geometry/hitTest'\nimport type { Point, PointId } from '../geometry/point'\nimport type { GeometryExercise } from '../schemas/exercise.schema'\nimport type { GeometryState } from '../schemas/geometryState.schema'\nimport { buildGeometryContext, type IndexedGeometryContext } from './geometryContext'\n\n/**\n * Every object a point can be built on: the exercise's own entities plus the\n * student's constructions, as the `{ id, definition }` pairs a hit-test or snap\n * scene is made of.\n *\n * Keyed by id and in declaration order, exercise first, because a construction\n * re-declaring a given id loses to it exactly as it does in the context.\n */\nexport function objectsInScope(\n exercise: GeometryExercise,\n geometry: GeometryState,\n): Map<EntityId, SceneEntity> {\n const objects = new Map<EntityId, SceneEntity>()\n for (const [id, definition] of Object.entries(exercise.entities)) {\n if (definition.kind !== 'point') objects.set(id, { id, definition })\n }\n for (const [id, definition] of Object.entries(geometry.entities)) {\n if (definition.kind !== 'point' && !objects.has(id)) objects.set(id, { id, definition })\n }\n return objects\n}\n\n/**\n * Resolves every point to coordinates. A point is simply absent from the\n * result when it cannot be resolved — its object was deleted, its two objects\n * became parallel so the intersection vanished, or its origins form a cycle.\n * Callers treat \"absent\" as \"not on screen\": renderers skip it, validation\n * skips candidates and constructions built on it. Nothing throws, because a\n * student mid-construction is allowed to have a figure that briefly makes no\n * sense.\n *\n * Given points come from `exercise`, not from `geometry` — a pinned given is\n * placed by the exercise whatever a submitted attempt claims, which is a\n * grading-integrity rule and is enforced while the context is indexed.\n *\n * Iteration order is part of the contract: pinned givens, then draggable\n * givens, then the attempt's own points. `findPointAt()` in the student store\n * promotes the first point within reuse tolerance, so the order decides which\n * point a revealed answer lands on.\n */\nexport function resolvePoints(\n exercise: GeometryExercise,\n geometry: GeometryState,\n): ReadonlyMap<PointId, Point> {\n // Read-only, and handed over without a copy: the context is built for this\n // call and nothing else holds it, so the only way the map could go wrong is\n // a caller writing to the scene it is reading. A caller that needs to add\n // points of its own — revealStudentAnswer invents them as it goes — copies\n // it, which makes that intent visible where it happens.\n return buildGeometryContext(exercise, geometry).points\n}\n\n// Convenience for the common \"one point, right now\" lookup.\nexport function resolvePoint(\n exercise: GeometryExercise,\n geometry: GeometryState,\n id: PointId,\n): Point | null {\n return resolvePoints(exercise, geometry).get(id) ?? null\n}\n\n/**\n * Every point an exercise places on its own, with no attempt against it — what\n * the teacher canvas draws and what a revealed answer is measured against.\n *\n * A v1 given carried its coordinates and needed no resolution; a v2 exercise\n * entity is a definition, so a given point sitting on a given segment has a\n * position only once the graph has been walked (M2.6.c.1).\n */\nexport function resolveExercisePoints(exercise: GeometryExercise): ReadonlyMap<PointId, Point> {\n return exerciseGeometryContext(exercise).points\n}\n\n/**\n * The same walk, kept whole rather than reduced to its points: a teacher-side\n * caller that also needs presentation — which is every renderer, since M2.G.4\n * routes drawing through the capability triple — would otherwise index the\n * exercise a second time to answer what the context already knows.\n */\nexport function exerciseGeometryContext(exercise: GeometryExercise): IndexedGeometryContext {\n return buildGeometryContext(exercise, NO_ATTEMPT)\n}\n\n// The attempt half of a scene that has no attempt: one empty v2 document,\n// defined once rather than rebuilt per call, so a teacher-side resolve\n// allocates nothing the walk does not need.\nconst NO_ATTEMPT: GeometryState = {\n schemaVersion: 2,\n entities: {},\n presentation: {},\n answerEntityIds: [],\n}\n","import { goalKindDeclarations } from '../../schemas/goals/goalKindDeclaration'\nimport type { CreateGoal } from '../../schemas/goals/createGoal.schema'\nimport type { GoalCandidate } from '../../geometry/goalCandidate'\nimport type { GoalKindHandler } from './goalKindHandler'\n\n// Satisfied by mere existence of an object of the right type — no\n// coordinate comparison at all, so unlike every other handler this one\n// measures nothing. It is also the only kind whose `objectType` may be\n// `point`, so its compatibility test is the candidate's own discriminant\n// rather than \"a construction of this type\".\nexport const createGoalHandler: GoalKindHandler<CreateGoal> = {\n ...goalKindDeclarations.create,\n accepts(candidate: GoalCandidate, goal: CreateGoal): candidate is GoalCandidate {\n return candidate.definition.kind === goal.objectType\n },\n satisfies() {\n return true\n },\n isRelevantAttempt() {\n return true\n },\n buildRevealedAnswer() {\n // Any object of the right type satisfies this goal — there is no\n // single canonical answer to reveal.\n return null\n },\n}\n","// Context lookups shared by every goal handler: resolving ids to the live\n// coordinates and given objects a handler needs. Structural bookkeeping only —\n// geometric measurement stays in measure/geometryAdapter.ts.\nimport { parentsOfDefinition } from '../../geometry/entities'\nimport { entryOf } from '../../geometry/entityRecord'\nimport { isCandidatePoint, type GoalCandidate } from '../../geometry/goalCandidate'\nimport { isDirectedObjectType } from '../../schemas/goals/goalKindDeclaration'\nimport type { ObjectTypeName } from '../../schemas/objectTypeName.schema'\nimport type { Point, PointId } from '../../geometry/point'\nimport type { ValidationContext } from '../types'\n\nexport function requirePoint(points: ReadonlyMap<string, Point>, id: string): Point {\n const point = points.get(id)\n if (!point) throw new Error(`Unknown point \"${id}\" during validation.`)\n return point\n}\n\nexport function requirePoints(\n points: ReadonlyMap<string, Point>,\n ids: [PointId, PointId],\n): [Point, Point] {\n return [requirePoint(points, ids[0]), requirePoint(points, ids[1])]\n}\n\n/**\n * The two live points a goal's reference object runs between.\n *\n * Every kind that names a reference wanted exactly this — the endpoint pair,\n * resolved — so the lookup, the type test and the resolution are one call\n * rather than three lines repeated in four handlers. It reads the exercise's\n * entity record directly since M2.6.c.1: a given object is an\n * `EntityDefinition` like any other and its endpoints are its parents, which\n * is the reference API generalization M2.3.c made and the reason no handler\n * has to know what a segment is made of.\n *\n * Throws, as the point lookups here do: a goal naming a reference the exercise\n * does not declare — or one with no direction, a point or a circle — is refused\n * by the schema, so reaching this is a bug rather than bad data.\n */\nexport function requireReferenceEndpoints(\n ctx: ValidationContext,\n referenceObjectId: string,\n): [Point, Point] {\n const reference = entryOf(ctx.exercise.entities, referenceObjectId)\n if (!reference || !isDirectedObjectType(reference.kind)) {\n throw new Error(`Unknown reference object \"${referenceObjectId}\" during validation.`)\n }\n const [from, to] = parentsOfDefinition(reference)\n if (from === undefined || to === undefined) {\n throw new Error(`Reference object \"${referenceObjectId}\" has no endpoint pair.`)\n }\n return requirePoints(ctx.points, [from, to])\n}\n\n// The candidate compatibility every kind that grades a *construction* uses: a\n// point is never one of those, whatever `objectType` an exercise asked for.\nexport function isConstructionOfType(\n candidate: GoalCandidate,\n objectType: ObjectTypeName,\n): boolean {\n return !isCandidatePoint(candidate) && candidate.definition.kind === objectType\n}\n\n/**\n * The same, for the three kinds that measure a *direction* rather than a shape:\n * the requested type must be one that has one.\n *\n * The exercise schema already refuses `objectType: 'circle'` on these kinds\n * (M2.G.3). This repeats the test because grading takes its exercise from any\n * caller — a host that migrated a stored document without parsing it, or a\n * store in memory — and a circle read through `candidateEndpoints()` is graded\n * as the segment from its centre to its through-point.\n */\nexport function isDirectedConstructionOfType(\n candidate: GoalCandidate,\n objectType: ObjectTypeName,\n): boolean {\n return isDirectedObjectType(objectType) && isConstructionOfType(candidate, objectType)\n}\n\n/**\n * The two points a candidate construction runs between — `endpointsOf()` over a\n * v1 `GeometryObject`, asked of a definition instead (M2.6.c.2).\n *\n * A pair, because that is what the measurement seam takes: a length, an angle\n * or a midpoint has nowhere to put a third parent, so a kind that names one or\n * three is refused rather than silently truncated. A caller that merely asks\n * *which* points a candidate names calls `parentsOfDefinition()`.\n */\nexport function candidateEndpoints(candidate: GoalCandidate): [PointId, PointId] {\n const parents = parentsOfDefinition(candidate.definition)\n const [from, to] = parents\n if (parents.length !== 2 || from === undefined || to === undefined) {\n throw new Error(\n `candidateEndpoints: ${candidate.definition.kind} is not defined by two points.`,\n )\n }\n return [from, to]\n}\n","import {\n isCandidatePoint,\n type CandidatePoint,\n type GoalCandidate,\n} from '../../geometry/goalCandidate'\nimport { goalKindDeclarations } from '../../schemas/goals/goalKindDeclaration'\nimport { distanceBetween, midpointOf } from '../../geometry/point'\nimport type { MidpointGoal } from '../../schemas/goals/midpointGoal.schema'\nimport { withinAuthoredDeviation } from '../../numerics/policy'\nimport type { RevealContext, RevealedAnswerShape, ValidationContext } from '../types'\nimport { requirePoint, requireReferenceEndpoints } from './goalContext'\nimport type { GoalKindHandler } from './goalKindHandler'\n\nfunction referenceMidpoint(goal: MidpointGoal, ctx: ValidationContext) {\n const [from, to] = requireReferenceEndpoints(ctx, goal.referenceObjectId)\n return midpointOf(from, to)\n}\n\n// The candidate is a constructed point, not a construction. Midpoint and\n// distance are elementary coordinate arithmetic, so both come from\n// geometry/point.ts rather than the JSXGraph adapter — see FUTURE.md 1.1.\nexport const midpointGoalHandler: GoalKindHandler<MidpointGoal, CandidatePoint> = {\n ...goalKindDeclarations.midpoint,\n // The candidate is a constructed point; `objectType` is fixed to `point`.\n accepts(candidate: GoalCandidate): candidate is CandidatePoint {\n return isCandidatePoint(candidate)\n },\n satisfies(candidate: CandidatePoint, goal: MidpointGoal, ctx: ValidationContext): boolean {\n // The scene says where the candidate is: a v2 definition carries a free\n // point's own coordinates and nothing else, and a constructed point is\n // routinely derived.\n const at = requirePoint(ctx.points, candidate.id)\n const distance = distanceBetween(at, referenceMidpoint(goal, ctx))\n return withinAuthoredDeviation(distance, goal.toleranceUnits)\n },\n // Every point the student placed is an attempt at the one point asked for.\n isRelevantAttempt(): boolean {\n return true\n },\n buildRevealedAnswer(goal: MidpointGoal, ctx: RevealContext): RevealedAnswerShape {\n return { type: 'point', at: referenceMidpoint(goal, ctx) }\n },\n}\n","// Helpers for buildRevealedAnswer(): synthesizing a canonical answer shape and\n// choosing the variant that stays visible in the exercise viewport. Pure\n// presentation math — nothing here decides whether an answer is correct.\nimport type { ObjectTypeName } from '../../schemas/objectTypeName.schema'\nimport type { MathViewport } from '../../schemas/viewport.schema'\nimport type { Point } from '../../geometry/point'\nimport type { RevealedAnswerShape } from '../types'\n\nexport function pointAtAngleAndLength(origin: Point, angleRadians: number, length: number): Point {\n return {\n x: origin.x + Math.cos(angleRadians) * length,\n y: origin.y + Math.sin(angleRadians) * length,\n }\n}\n\n// Positive inside the viewport (distance to the nearest edge), negative outside\n// (distance to the viewport). Comparable across both cases, so a single max\n// picks the most comfortably visible candidate.\nexport function viewportVisibilityScore(point: Point, viewport: MathViewport): number {\n const [xMin, yMin, xMax, yMax] = viewport\n if (point.x >= xMin && point.x <= xMax && point.y >= yMin && point.y <= yMax) {\n return Math.min(point.x - xMin, xMax - point.x, point.y - yMin, yMax - point.y)\n }\n const clampedX = Math.max(xMin, Math.min(xMax, point.x))\n const clampedY = Math.max(yMin, Math.min(yMax, point.y))\n return -Math.hypot(point.x - clampedX, point.y - clampedY)\n}\n\n// Ties keep the first candidate, so handlers can order their candidates by\n// preferred direction.\nexport function mostVisibleInViewport(candidates: Point[], viewport: MathViewport): Point {\n let best = candidates[0]\n if (!best) throw new Error('mostVisibleInViewport requires at least one candidate.')\n let bestScore = viewportVisibilityScore(best, viewport)\n for (const candidate of candidates.slice(1)) {\n const score = viewportVisibilityScore(candidate, viewport)\n if (score > bestScore) {\n best = candidate\n bestScore = score\n }\n }\n return best\n}\n\n// Long enough to read as a construction, short enough to stay on screen.\nexport function previewLength(viewport: MathViewport, referenceLength: number): number {\n const [xMin, yMin, xMax, yMax] = viewport\n const maximumPreviewLength = Math.max(0.5, Math.min(xMax - xMin, yMax - yMin) * 0.28)\n return Math.min(referenceLength || 1, maximumPreviewLength)\n}\n\nexport function revealedShapeThrough(\n objectType: ObjectTypeName,\n from: Point,\n to: Point,\n): RevealedAnswerShape {\n return objectType === 'line'\n ? { type: 'line', through: [from, to] }\n : { type: 'segment', from, to }\n}\n","import { parentsOfDefinition } from '../../geometry/entities'\nimport type { GoalCandidate } from '../../geometry/goalCandidate'\nimport { distanceBetween } from '../../geometry/point'\nimport type { ParallelGoal } from '../../schemas/goals/parallelGoal.schema'\nimport { goalKindDeclarations } from '../../schemas/goals/goalKindDeclaration'\nimport { linesAngleBetweenDegrees } from '../../measure/geometryAdapter'\nimport { withinAuthoredDeviation } from '../../numerics/policy'\nimport type { RevealContext, RevealedAnswerShape, ValidationContext } from '../types'\nimport {\n candidateEndpoints,\n isDirectedConstructionOfType,\n requirePoint,\n requirePoints,\n requireReferenceEndpoints,\n} from './goalContext'\nimport type { GoalKindHandler } from './goalKindHandler'\nimport {\n mostVisibleInViewport,\n pointAtAngleAndLength,\n previewLength,\n revealedShapeThrough,\n} from './previewGeometry'\n\nexport const parallelGoalHandler: GoalKindHandler<ParallelGoal> = {\n ...goalKindDeclarations.parallel,\n accepts(candidate: GoalCandidate, goal: ParallelGoal): candidate is GoalCandidate {\n return isDirectedConstructionOfType(candidate, goal.objectType)\n },\n satisfies(candidate: GoalCandidate, goal: ParallelGoal, ctx: ValidationContext): boolean {\n const endpoints = candidateEndpoints(candidate)\n if (!endpoints.includes(goal.throughPointId)) return false\n\n const [referenceFrom, referenceTo] = requireReferenceEndpoints(ctx, goal.referenceObjectId)\n const [candidateFrom, candidateTo] = requirePoints(ctx.points, endpoints)\n\n // Already folded into [0, 90]: 179° apart is 1° apart for undirected lines.\n const angleBetweenDegrees = linesAngleBetweenDegrees(\n referenceFrom,\n referenceTo,\n candidateFrom,\n candidateTo,\n )\n return withinAuthoredDeviation(angleBetweenDegrees, goal.toleranceDegrees)\n },\n isRelevantAttempt(candidate: GoalCandidate, goal: ParallelGoal): boolean {\n return parentsOfDefinition(candidate.definition).includes(goal.throughPointId)\n },\n buildRevealedAnswer(goal: ParallelGoal, ctx: RevealContext): RevealedAnswerShape {\n const [referenceFrom, referenceTo] = requireReferenceEndpoints(ctx, goal.referenceObjectId)\n const throughPoint = requirePoint(ctx.points, goal.throughPointId)\n\n const referenceAngle = Math.atan2(\n referenceTo.y - referenceFrom.y,\n referenceTo.x - referenceFrom.x,\n )\n const length = previewLength(ctx.exercise.viewport, distanceBetween(referenceFrom, referenceTo))\n // Both directions along the reference direction are equally parallel; pick\n // whichever endpoint stays inside the viewport.\n const secondPoint = mostVisibleInViewport(\n [\n pointAtAngleAndLength(throughPoint, referenceAngle, length),\n pointAtAngleAndLength(throughPoint, referenceAngle + Math.PI, length),\n ],\n ctx.exercise.viewport,\n )\n\n return revealedShapeThrough(goal.objectType, throughPoint, secondPoint)\n },\n}\n","import { parentsOfDefinition } from '../../geometry/entities'\nimport type { GoalCandidate } from '../../geometry/goalCandidate'\nimport { distanceBetween } from '../../geometry/point'\nimport type { PerpendicularGoal } from '../../schemas/goals/perpendicularGoal.schema'\nimport { goalKindDeclarations } from '../../schemas/goals/goalKindDeclaration'\nimport { linesAngleBetweenDegrees } from '../../measure/geometryAdapter'\nimport { withinAuthoredTolerance } from '../../numerics/policy'\nimport type { RevealContext, RevealedAnswerShape, ValidationContext } from '../types'\nimport {\n candidateEndpoints,\n isDirectedConstructionOfType,\n requirePoint,\n requirePoints,\n requireReferenceEndpoints,\n} from './goalContext'\nimport type { GoalKindHandler } from './goalKindHandler'\nimport {\n mostVisibleInViewport,\n pointAtAngleAndLength,\n previewLength,\n revealedShapeThrough,\n} from './previewGeometry'\n\nexport const perpendicularGoalHandler: GoalKindHandler<PerpendicularGoal> = {\n ...goalKindDeclarations.perpendicular,\n accepts(candidate: GoalCandidate, goal: PerpendicularGoal): candidate is GoalCandidate {\n return isDirectedConstructionOfType(candidate, goal.objectType)\n },\n satisfies(candidate: GoalCandidate, goal: PerpendicularGoal, ctx: ValidationContext): boolean {\n const endpoints = candidateEndpoints(candidate)\n if (!endpoints.includes(goal.throughPointId)) return false\n\n const [referenceFrom, referenceTo] = requireReferenceEndpoints(ctx, goal.referenceObjectId)\n const [candidateFrom, candidateTo] = requirePoints(ctx.points, endpoints)\n\n const angleBetweenDegrees = linesAngleBetweenDegrees(\n referenceFrom,\n referenceTo,\n candidateFrom,\n candidateTo,\n )\n return withinAuthoredTolerance(angleBetweenDegrees, 90, goal.toleranceDegrees)\n },\n isRelevantAttempt(candidate: GoalCandidate, goal: PerpendicularGoal): boolean {\n return parentsOfDefinition(candidate.definition).includes(goal.throughPointId)\n },\n buildRevealedAnswer(goal: PerpendicularGoal, ctx: RevealContext): RevealedAnswerShape {\n const [referenceFrom, referenceTo] = requireReferenceEndpoints(ctx, goal.referenceObjectId)\n const throughPoint = requirePoint(ctx.points, goal.throughPointId)\n\n const referenceAngle = Math.atan2(\n referenceTo.y - referenceFrom.y,\n referenceTo.x - referenceFrom.x,\n )\n const length = previewLength(ctx.exercise.viewport, distanceBetween(referenceFrom, referenceTo))\n const secondPoint = mostVisibleInViewport(\n [\n pointAtAngleAndLength(throughPoint, referenceAngle + Math.PI / 2, length),\n pointAtAngleAndLength(throughPoint, referenceAngle - Math.PI / 2, length),\n ],\n ctx.exercise.viewport,\n )\n\n return revealedShapeThrough(goal.objectType, throughPoint, secondPoint)\n },\n}\n","import type { GoalCandidate } from '../../geometry/goalCandidate'\nimport { distanceBetween } from '../../geometry/point'\nimport type { SegmentLengthGoal } from '../../schemas/goals/segmentLengthGoal.schema'\nimport { goalKindDeclarations } from '../../schemas/goals/goalKindDeclaration'\nimport { withinAuthoredTolerance } from '../../numerics/policy'\nimport type { RevealContext, RevealedAnswerShape, ValidationContext } from '../types'\nimport { candidateEndpoints, isConstructionOfType, requirePoints } from './goalContext'\nimport type { GoalKindHandler } from './goalKindHandler'\n\n// Length is elementary coordinate arithmetic, so it comes from geometry/point.ts\n// rather than the JSXGraph adapter — see FUTURE.md 1.1.\nexport const segmentLengthGoalHandler: GoalKindHandler<SegmentLengthGoal> = {\n ...goalKindDeclarations.segmentLength,\n accepts(candidate: GoalCandidate, goal: SegmentLengthGoal): candidate is GoalCandidate {\n return isConstructionOfType(candidate, goal.objectType)\n },\n satisfies(candidate: GoalCandidate, goal: SegmentLengthGoal, ctx: ValidationContext): boolean {\n const [from, to] = requirePoints(ctx.points, candidateEndpoints(candidate))\n return withinAuthoredTolerance(\n distanceBetween(from, to),\n goal.targetLength,\n goal.toleranceUnits,\n )\n },\n // Any segment is an honest attempt at \"draw a segment of length L\": there is\n // no anchor point to narrow it down the way perpendicular has.\n isRelevantAttempt(): boolean {\n return true\n },\n buildRevealedAnswer(goal: SegmentLengthGoal, ctx: RevealContext): RevealedAnswerShape {\n // No position is required, so the canonical answer is drawn horizontally\n // through the middle of the viewport: it shows the length and nothing more.\n //\n // Length is never traded for visibility. A target longer than the viewport\n // renders with its ends off canvas, which looks wrong — but shrinking it\n // to fit would reveal a segment that does not satisfy the goal it answers,\n // and the student can re-check a reveal. An unreachable target is an\n // authoring problem, and belongs in exercise warnings rather than here.\n const [xMin, yMin, xMax, yMax] = ctx.exercise.viewport\n const centerX = (xMin + xMax) / 2\n const centerY = (yMin + yMax) / 2\n return {\n type: 'segment',\n from: { x: centerX - goal.targetLength / 2, y: centerY },\n to: { x: centerX + goal.targetLength / 2, y: centerY },\n }\n },\n}\n","import { parentsOfDefinition } from '../../geometry/entities'\nimport type { GoalCandidate } from '../../geometry/goalCandidate'\nimport type { Point } from '../../geometry/point'\nimport type { ThroughPointsGoal } from '../../schemas/goals/throughPointsGoal.schema'\nimport { goalKindDeclarations } from '../../schemas/goals/goalKindDeclaration'\nimport { pointsCoincide } from '../../measure/geometryAdapter'\nimport type { RevealContext, RevealedAnswerShape, ValidationContext } from '../types'\nimport { isDirectedConstructionOfType, requirePoint } from './goalContext'\nimport type { GoalKindHandler } from './goalKindHandler'\nimport { revealedShapeThrough } from './previewGeometry'\n\n// Coordinates in, not PointIds — reusable by both validation and by\n// buildRevealedAnswer self-consistency tests, without fake id plumbing.\n//\n// Order-insensitive set comparison. Both objectTypes this kind accepts —\n// segment and line, the directed ones — are defined by exactly 2 points, so\n// this special-cases length 2 rather than implementing a general N-point\n// permutation matcher nobody needs yet — the signature stays honestly generic\n// for when that changes.\nexport function satisfiesThroughPoints(candidatePoints: Point[], goalPoints: Point[]): boolean {\n if (candidatePoints.length !== goalPoints.length) return false\n if (candidatePoints.length === 2) {\n const [c0, c1] = candidatePoints as [Point, Point]\n const [g0, g1] = goalPoints as [Point, Point]\n return (\n (pointsCoincide(c0, g0) && pointsCoincide(c1, g1)) ||\n (pointsCoincide(c0, g1) && pointsCoincide(c1, g0))\n )\n }\n throw new Error(`satisfiesThroughPoints: unsupported point count ${candidatePoints.length}`)\n}\n\nexport const throughPointsGoalHandler: GoalKindHandler<ThroughPointsGoal> = {\n ...goalKindDeclarations.throughPoints,\n accepts(candidate: GoalCandidate, goal: ThroughPointsGoal): candidate is GoalCandidate {\n return isDirectedConstructionOfType(candidate, goal.objectType)\n },\n satisfies(candidate: GoalCandidate, goal: ThroughPointsGoal, ctx: ValidationContext): boolean {\n const candidatePoints = parentsOfDefinition(candidate.definition).map((id) =>\n requirePoint(ctx.points, id),\n )\n const goalPoints = goal.pointIds.map((id) => requirePoint(ctx.points, id))\n return satisfiesThroughPoints(candidatePoints, goalPoints)\n },\n isRelevantAttempt(\n candidate: GoalCandidate,\n goal: ThroughPointsGoal,\n ctx: ValidationContext,\n ): boolean {\n const candidatePoints = parentsOfDefinition(candidate.definition).map((id) =>\n requirePoint(ctx.points, id),\n )\n const goalPoints = goal.pointIds.map((id) => requirePoint(ctx.points, id))\n return candidatePoints.some((candidatePoint) =>\n goalPoints.some((goalPoint) => pointsCoincide(candidatePoint, goalPoint)),\n )\n },\n buildRevealedAnswer(goal: ThroughPointsGoal, ctx: RevealContext): RevealedAnswerShape {\n const [a, b] = goal.pointIds.map((id) => requirePoint(ctx.points, id)) as [Point, Point]\n return revealedShapeThrough(goal.objectType, a, b)\n },\n}\n","// The goal kind registry (M2.5).\n//\n// One entry per kind, each the whole of what that kind can answer: its\n// declaration from the schema layer (kind, schema, referenced givens,\n// cross-reference rules) spread into the behaviour that needs measurement\n// (candidate compatibility, satisfaction, relevance, revealed answer).\n//\n// **The registry is a frozen object literal, not a registration pass**, for\n// the reason `geometry/entities/index.ts` gives: a `register()` call makes a\n// kind reachable only once its module has been evaluated, so completeness\n// depends on import order, and registering a kind twice is expressible. Here\n// the table *is* the module's value and `GoalKindRegistry` is a mapped type\n// over the goal union, so a kind added to `geometryGoalSchema` without an\n// entry is a compile error and a duplicate key cannot be written.\nimport { createGoalHandler } from './create'\nimport { midpointGoalHandler } from './midpoint'\nimport { parallelGoalHandler } from './parallel'\nimport { perpendicularGoalHandler } from './perpendicular'\nimport { segmentLengthGoalHandler } from './segmentLength'\nimport { throughPointsGoalHandler } from './throughPoints'\nimport type { GoalKindHandler, GoalKindRegistry } from './goalKindHandler'\nimport type { GeometryGoal } from '../../schemas/goals/geometryGoal.schema'\nimport type { GoalCandidate } from '../../geometry/goalCandidate'\nimport type { RevealContext, RevealedAnswerShape, ValidationContext } from '../types'\n\nexport type { GoalKindHandler, GoalKindRegistry } from './goalKindHandler'\n\nexport const goalKindRegistry: GoalKindRegistry = Object.freeze({\n create: createGoalHandler,\n throughPoints: throughPointsGoalHandler,\n perpendicular: perpendicularGoalHandler,\n parallel: parallelGoalHandler,\n segmentLength: segmentLengthGoalHandler,\n midpoint: midpointGoalHandler,\n})\n\n// The one place a kind's concrete goal and candidate types are erased, the\n// same trade `entities/index.ts` makes: lookup stays sound because the key is\n// the goal's own discriminant, so the entry selected is by construction the\n// one whose signature that goal satisfies, and every handler below is reached\n// only for a candidate its own `accepts()` admitted.\nexport function getGoalKindHandler(kind: string): GoalKindHandler {\n const handler = (goalKindRegistry as Record<string, GoalKindHandler | undefined>)[kind]\n if (!handler) throw new Error(`No goal kind handler registered for \"${kind}\"`)\n return handler\n}\n\n/** Every given the goal names — what removing one of them would orphan. */\nexport function referencedGivenIds(goal: GeometryGoal): readonly string[] {\n return getGoalKindHandler(goal.type).referencedGivenIds(goal)\n}\n\n/** Whether this candidate could satisfy this goal at all, before measuring. */\nexport function goalAcceptsCandidate(candidate: GoalCandidate, goal: GeometryGoal): boolean {\n return getGoalKindHandler(goal.type).accepts(candidate, goal)\n}\n\nexport function goalSatisfiedBy(\n candidate: GoalCandidate,\n goal: GeometryGoal,\n ctx: ValidationContext,\n): boolean {\n const handler = getGoalKindHandler(goal.type)\n return handler.accepts(candidate, goal) && handler.satisfies(candidate, goal, ctx)\n}\n\nexport function isRelevantGoalAttempt(\n candidate: GoalCandidate,\n goal: GeometryGoal,\n ctx: ValidationContext,\n): boolean {\n const handler = getGoalKindHandler(goal.type)\n return handler.accepts(candidate, goal) && handler.isRelevantAttempt(candidate, goal, ctx)\n}\n\nexport function revealedAnswerFor(\n goal: GeometryGoal,\n ctx: RevealContext,\n): RevealedAnswerShape | null {\n return getGoalKindHandler(goal.type).buildRevealedAnswer(goal, ctx)\n}\n"],"mappings":"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"}