@xom11/whiteboard 0.31.0 → 0.33.0
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.
- package/dist/ai.d.mts +149 -28
- package/dist/ai.d.ts +149 -28
- package/dist/ai.js +2652 -430
- package/dist/ai.js.map +1 -1
- package/dist/ai.mjs +2482 -426
- package/dist/ai.mjs.map +1 -1
- package/dist/catalog.json +4 -4
- package/dist/{chunk-JJ4FPCBE.mjs → chunk-4EXRNZRX.mjs} +641 -75
- package/dist/chunk-4EXRNZRX.mjs.map +1 -0
- package/dist/{chunk-TMRFSOM7.mjs → chunk-4NJUTCFF.mjs} +4 -4
- package/dist/{chunk-TMRFSOM7.mjs.map → chunk-4NJUTCFF.mjs.map} +1 -1
- package/dist/{chunk-LTLLQUMN.mjs → chunk-BZZ5BROM.mjs} +6 -7
- package/dist/chunk-BZZ5BROM.mjs.map +1 -0
- package/dist/{host-KMWP7KBT.mjs → chunk-C3RDFBQ5.mjs} +20 -35
- package/dist/chunk-C3RDFBQ5.mjs.map +1 -0
- package/dist/chunk-C7C66BAV.mjs +11 -0
- package/dist/chunk-C7C66BAV.mjs.map +1 -0
- package/dist/{chunk-T3N4BSJV.mjs → chunk-DCFZTKFE.mjs} +13 -5
- package/dist/chunk-DCFZTKFE.mjs.map +1 -0
- package/dist/{chunk-44JY2AKC.mjs → chunk-F42MZ745.mjs} +3 -3
- package/dist/{chunk-44JY2AKC.mjs.map → chunk-F42MZ745.mjs.map} +1 -1
- package/dist/{chunk-BMYC2ILT.mjs → chunk-FOPZOVI3.mjs} +5 -4
- package/dist/chunk-FOPZOVI3.mjs.map +1 -0
- package/dist/{chunk-K5BS2H56.mjs → chunk-GKDQ5IV7.mjs} +4 -4
- package/dist/{chunk-K5BS2H56.mjs.map → chunk-GKDQ5IV7.mjs.map} +1 -1
- package/dist/{chunk-73Q7ADVL.mjs → chunk-MNHOFOM5.mjs} +2 -2
- package/dist/{chunk-73Q7ADVL.mjs.map → chunk-MNHOFOM5.mjs.map} +1 -1
- package/dist/{chunk-KOXOC2FI.mjs → chunk-NBMYET5H.mjs} +11 -15
- package/dist/chunk-NBMYET5H.mjs.map +1 -0
- package/dist/{chunk-DWIEVCGK.mjs → chunk-NTFG7ZRN.mjs} +53 -3
- package/dist/chunk-NTFG7ZRN.mjs.map +1 -0
- package/dist/{chunk-C76SOFXF.mjs → chunk-QCK3Z5WN.mjs} +3 -3
- package/dist/{chunk-C76SOFXF.mjs.map → chunk-QCK3Z5WN.mjs.map} +1 -1
- package/dist/chunk-SUXIMLYN.mjs +238 -0
- package/dist/chunk-SUXIMLYN.mjs.map +1 -0
- package/dist/geometry-2d.d.mts +1 -1
- package/dist/geometry-2d.d.ts +1 -1
- package/dist/geometry-2d.js +1026 -231
- package/dist/geometry-2d.js.map +1 -1
- package/dist/geometry-2d.mjs +6 -5
- package/dist/geometry-3d.d.mts +1 -1
- package/dist/geometry-3d.d.ts +1 -1
- package/dist/geometry-3d.js +4001 -475
- package/dist/geometry-3d.js.map +1 -1
- package/dist/geometry-3d.mjs +5 -5
- package/dist/graph-2d.d.mts +1 -1
- package/dist/graph-2d.d.ts +1 -1
- package/dist/graph-2d.js +712 -115
- package/dist/graph-2d.js.map +1 -1
- package/dist/graph-2d.mjs +5 -5
- package/dist/{handleExtractProblem-BrDY9ifM.d.ts → handleExtractProblem-mtJyhEw3.d.mts} +2 -0
- package/dist/{handleExtractProblem-BrDY9ifM.d.mts → handleExtractProblem-mtJyhEw3.d.ts} +2 -0
- package/dist/host-6WTLCXUE.mjs +62 -0
- package/dist/host-6WTLCXUE.mjs.map +1 -0
- package/dist/{host-H2IGOKJU.mjs → host-BWIXT5TR.mjs} +3 -3
- package/dist/{host-H2IGOKJU.mjs.map → host-BWIXT5TR.mjs.map} +1 -1
- package/dist/{host-4FIUNIDQ.mjs → host-QDVRULJV.mjs} +14 -11
- package/dist/host-QDVRULJV.mjs.map +1 -0
- package/dist/host-USOIVTQB.mjs +4976 -0
- package/dist/host-USOIVTQB.mjs.map +1 -0
- package/dist/index.d.mts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +4273 -521
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48 -27
- package/dist/index.mjs.map +1 -1
- package/dist/latex.d.mts +1 -1
- package/dist/latex.d.ts +1 -1
- package/dist/latex.mjs +1 -1
- package/dist/serialize-7UZWQQ4I.mjs +9 -0
- package/dist/{serialize-PGHQZEPV.mjs.map → serialize-7UZWQQ4I.mjs.map} +1 -1
- package/dist/studio.d.mts +35 -0
- package/dist/studio.d.ts +35 -0
- package/dist/studio.js +10883 -0
- package/dist/studio.js.map +1 -0
- package/dist/studio.mjs +28 -0
- package/dist/studio.mjs.map +1 -0
- package/dist/{types-tePd94vW.d.ts → types-eEEEVsLF.d.mts} +1 -1
- package/dist/{types-tePd94vW.d.mts → types-eEEEVsLF.d.ts} +1 -1
- package/package.json +12 -2
- package/dist/chunk-BMYC2ILT.mjs.map +0 -1
- package/dist/chunk-DWIEVCGK.mjs.map +0 -1
- package/dist/chunk-JJ4FPCBE.mjs.map +0 -1
- package/dist/chunk-KOXOC2FI.mjs.map +0 -1
- package/dist/chunk-LTLLQUMN.mjs.map +0 -1
- package/dist/chunk-QK6OVDLC.mjs +0 -103
- package/dist/chunk-QK6OVDLC.mjs.map +0 -1
- package/dist/chunk-T3N4BSJV.mjs.map +0 -1
- package/dist/host-4FIUNIDQ.mjs.map +0 -1
- package/dist/host-4ZB4XD4S.mjs +0 -2378
- package/dist/host-4ZB4XD4S.mjs.map +0 -1
- package/dist/host-KMWP7KBT.mjs.map +0 -1
- package/dist/serialize-PGHQZEPV.mjs +0 -9
package/dist/graph-2d.js
CHANGED
|
@@ -37,16 +37,16 @@ var __export = (target, all) => {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
// src/core/scene/registry.ts
|
|
40
|
-
function registerKind(
|
|
41
|
-
if (registry.has(
|
|
42
|
-
console.warn(`[scene] kind "${
|
|
40
|
+
function registerKind(def24) {
|
|
41
|
+
if (registry.has(def24.type)) {
|
|
42
|
+
console.warn(`[scene] kind "${def24.type}" \u0111\xE3 \u0111\u01B0\u1EE3c \u0111\u0103ng k\xFD \u2014 ghi \u0111\xE8 \u0111\u1ECBnh ngh\u0129a c\u0169`);
|
|
43
43
|
}
|
|
44
|
-
registry.set(
|
|
44
|
+
registry.set(def24.type, def24);
|
|
45
45
|
}
|
|
46
46
|
function getKind(type) {
|
|
47
|
-
const
|
|
48
|
-
if (!
|
|
49
|
-
return
|
|
47
|
+
const def24 = registry.get(type);
|
|
48
|
+
if (!def24) throw new Error(`[scene] unknown kind: ${type}`);
|
|
49
|
+
return def24;
|
|
50
50
|
}
|
|
51
51
|
var registry;
|
|
52
52
|
var init_registry = __esm({
|
|
@@ -132,8 +132,8 @@ function reduce(draft, action) {
|
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
134
|
case "TRANSACTION": {
|
|
135
|
-
for (const
|
|
136
|
-
reduce(draft,
|
|
135
|
+
for (const sub2 of action.payload.actions) {
|
|
136
|
+
reduce(draft, sub2);
|
|
137
137
|
}
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
@@ -479,8 +479,8 @@ var init_JxgRenderer = __esm({
|
|
|
479
479
|
}
|
|
480
480
|
create(obj) {
|
|
481
481
|
try {
|
|
482
|
-
const
|
|
483
|
-
const el =
|
|
482
|
+
const def24 = getKind(obj.kind);
|
|
483
|
+
const el = def24.render(obj, this.ctx());
|
|
484
484
|
this.elements.set(obj.id, el);
|
|
485
485
|
this.attachFreePointDragSync(obj, el);
|
|
486
486
|
this.attachGliderDragSync(obj, el);
|
|
@@ -684,11 +684,11 @@ var init_JxgRenderer = __esm({
|
|
|
684
684
|
continue;
|
|
685
685
|
}
|
|
686
686
|
if (Object.is(old, cur)) continue;
|
|
687
|
-
const
|
|
687
|
+
const def24 = getKind(cur.kind);
|
|
688
688
|
const existing = this.elements.get(id);
|
|
689
|
-
if (
|
|
689
|
+
if (def24.update && existing) {
|
|
690
690
|
try {
|
|
691
|
-
|
|
691
|
+
def24.update(cur, old, this.ctx(), existing);
|
|
692
692
|
continue;
|
|
693
693
|
} catch (err) {
|
|
694
694
|
console.warn(`[scene/render/2d] update fail, recreate:`, err);
|
|
@@ -1157,8 +1157,36 @@ function constraintRefs(c) {
|
|
|
1157
1157
|
return [c.polygonId];
|
|
1158
1158
|
case "onSphere":
|
|
1159
1159
|
return [c.sphereId];
|
|
1160
|
-
|
|
1160
|
+
case "midpoint":
|
|
1161
|
+
return [c.p1, c.p2];
|
|
1162
|
+
case "centroid":
|
|
1163
|
+
return [...c.vertices];
|
|
1164
|
+
case "intersectionLines":
|
|
1165
|
+
return [c.a1, c.b1, c.a2, c.b2];
|
|
1166
|
+
case "intersectionLinePlane":
|
|
1167
|
+
return [c.a, c.b, c.plane];
|
|
1168
|
+
case "perpFootLine":
|
|
1169
|
+
return [c.from, c.a, c.b];
|
|
1170
|
+
case "perpFootPlane":
|
|
1171
|
+
return [c.from, c.plane];
|
|
1172
|
+
case "circumsphereCenter":
|
|
1173
|
+
return [...c.vertices];
|
|
1174
|
+
case "pyramidInsphereCenter":
|
|
1175
|
+
return [c.apex, ...c.vertices];
|
|
1176
|
+
case "faceCircumcenter":
|
|
1177
|
+
return [...c.vertices];
|
|
1178
|
+
case "pointAboveFace":
|
|
1179
|
+
return [c.base, c.apex, ...c.vertices];
|
|
1180
|
+
// Kind KHÔNG có ref scene-object (toạ độ literal): liệt kê TƯỜNG MINH để
|
|
1181
|
+
// exhaustive never-guard bên dưới buộc khai báo khi thêm constraint kind mới
|
|
1182
|
+
// (mô phỏng constraintRefs2D — quên case = cascade-delete/deps sai âm thầm).
|
|
1183
|
+
case "free":
|
|
1184
|
+
case "onGround":
|
|
1185
|
+
case "onAxis":
|
|
1161
1186
|
return [];
|
|
1187
|
+
default: {
|
|
1188
|
+
return [];
|
|
1189
|
+
}
|
|
1162
1190
|
}
|
|
1163
1191
|
}
|
|
1164
1192
|
var init_d_constraint = __esm({
|
|
@@ -1166,12 +1194,359 @@ var init_d_constraint = __esm({
|
|
|
1166
1194
|
}
|
|
1167
1195
|
});
|
|
1168
1196
|
|
|
1197
|
+
// src/core/scene/kinds/constraint3d-math.ts
|
|
1198
|
+
function sub(a, b) {
|
|
1199
|
+
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
1200
|
+
}
|
|
1201
|
+
function add(a, b) {
|
|
1202
|
+
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
1203
|
+
}
|
|
1204
|
+
function scale(a, k) {
|
|
1205
|
+
return [a[0] * k, a[1] * k, a[2] * k];
|
|
1206
|
+
}
|
|
1207
|
+
function dot(a, b) {
|
|
1208
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
1209
|
+
}
|
|
1210
|
+
function cross(a, b) {
|
|
1211
|
+
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
1212
|
+
}
|
|
1213
|
+
function norm(a) {
|
|
1214
|
+
return Math.sqrt(dot(a, a));
|
|
1215
|
+
}
|
|
1216
|
+
function normalize(a) {
|
|
1217
|
+
const n = norm(a);
|
|
1218
|
+
return n === 0 ? a : scale(a, 1 / n);
|
|
1219
|
+
}
|
|
1220
|
+
function getPointWorld(id, state) {
|
|
1221
|
+
const obj = state.objects[id];
|
|
1222
|
+
if (!obj || obj.kind !== "point3d") {
|
|
1223
|
+
throw new Error(`constraintMath: point ${id} not found`);
|
|
1224
|
+
}
|
|
1225
|
+
const attrs = obj.attrs;
|
|
1226
|
+
return constraintToWorld(attrs.constraint, state);
|
|
1227
|
+
}
|
|
1228
|
+
function getPlaneBasis(planeObj, state) {
|
|
1229
|
+
const a = planeObj.attrs;
|
|
1230
|
+
let p1, p2, p3;
|
|
1231
|
+
if (a.construction) {
|
|
1232
|
+
const r = planeConstructionWorld(a.construction, state);
|
|
1233
|
+
p1 = r.p1;
|
|
1234
|
+
p2 = r.p2;
|
|
1235
|
+
p3 = r.p3;
|
|
1236
|
+
} else {
|
|
1237
|
+
p1 = getPointWorld(a.p1, state);
|
|
1238
|
+
p2 = getPointWorld(a.p2, state);
|
|
1239
|
+
p3 = getPointWorld(a.p3, state);
|
|
1240
|
+
}
|
|
1241
|
+
const basis1 = sub(p2, p1);
|
|
1242
|
+
const tmp = sub(p3, p1);
|
|
1243
|
+
const normal = normalize(cross(basis1, tmp));
|
|
1244
|
+
const basis2 = cross(normal, basis1);
|
|
1245
|
+
return { origin: p1, basis1, basis2, normal };
|
|
1246
|
+
}
|
|
1247
|
+
function orthoBasisFromNormal(n) {
|
|
1248
|
+
const seed = Math.abs(n[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
1249
|
+
const basis1 = normalize(cross(n, seed));
|
|
1250
|
+
const basis2 = cross(n, basis1);
|
|
1251
|
+
return { basis1, basis2 };
|
|
1252
|
+
}
|
|
1253
|
+
function planeConstructionWorld(c, state) {
|
|
1254
|
+
if (_recDepth >= MAX_REC_DEPTH) throw new Error("planeConstructionWorld: \u0111\u1EC7 quy qu\xE1 s\xE2u \u2014 chu tr\xECnh tham chi\u1EBFu m\u1EB7t?");
|
|
1255
|
+
_recDepth++;
|
|
1256
|
+
try {
|
|
1257
|
+
return planeConstructionWorldInner(c, state);
|
|
1258
|
+
} finally {
|
|
1259
|
+
_recDepth--;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
function planeConstructionWorldInner(c, state) {
|
|
1263
|
+
switch (c.kind) {
|
|
1264
|
+
case "planeParallelThrough": {
|
|
1265
|
+
const P = getPointWorld(c.point, state);
|
|
1266
|
+
const ref = state.objects[c.refPlane];
|
|
1267
|
+
if (!ref || ref.kind !== "plane3d") throw new Error("planeParallelThrough: m\u1EB7t tham chi\u1EBFu thi\u1EBFu");
|
|
1268
|
+
const { basis1, basis2 } = getPlaneBasis(ref, state);
|
|
1269
|
+
if (norm(basis1) < 1e-12 || norm(basis2) < 1e-12) {
|
|
1270
|
+
return { p1: P, p2: add(P, [1, 0, 0]), p3: add(P, [0, 1, 0]) };
|
|
1271
|
+
}
|
|
1272
|
+
return { p1: P, p2: add(P, basis1), p3: add(P, basis2) };
|
|
1273
|
+
}
|
|
1274
|
+
case "planePerpToLine": {
|
|
1275
|
+
const P = getPointWorld(c.point, state);
|
|
1276
|
+
const dir = sub(getPointWorld(c.lineB, state), getPointWorld(c.lineA, state));
|
|
1277
|
+
const dn = norm(dir);
|
|
1278
|
+
if (dn < 1e-12) return { p1: P, p2: add(P, [1, 0, 0]), p3: add(P, [0, 1, 0]) };
|
|
1279
|
+
const { basis1, basis2 } = orthoBasisFromNormal(scale(dir, 1 / dn));
|
|
1280
|
+
return { p1: P, p2: add(P, basis1), p3: add(P, basis2) };
|
|
1281
|
+
}
|
|
1282
|
+
default: {
|
|
1283
|
+
throw new Error("planeConstructionWorld: kind kh\xF4ng h\u1ED7 tr\u1EE3");
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
function lineDefiningPointIds(line) {
|
|
1288
|
+
if (line.kind === "line3d" || line.kind === "segment3d") {
|
|
1289
|
+
const a = line.attrs;
|
|
1290
|
+
return a.p1 && a.p2 ? [a.p1, a.p2] : null;
|
|
1291
|
+
}
|
|
1292
|
+
if (line.kind === "ray3d") {
|
|
1293
|
+
const a = line.attrs;
|
|
1294
|
+
return [a.origin, a.through];
|
|
1295
|
+
}
|
|
1296
|
+
if (line.kind === "vector3d") {
|
|
1297
|
+
const a = line.attrs;
|
|
1298
|
+
return [a.from, a.to];
|
|
1299
|
+
}
|
|
1300
|
+
return null;
|
|
1301
|
+
}
|
|
1302
|
+
function lineEndpointsWorld(lineId, state, ctx) {
|
|
1303
|
+
const line = state.objects[lineId];
|
|
1304
|
+
if (!line) throw new Error(`${ctx}: \u0111\u01B0\u1EDDng ${lineId} kh\xF4ng t\u1ED3n t\u1EA1i`);
|
|
1305
|
+
const ids = lineDefiningPointIds(line);
|
|
1306
|
+
if (!ids) throw new Error(`${ctx}: kind ${line.kind} kh\xF4ng ph\u1EA3i \u0111\u01B0\u1EDDng`);
|
|
1307
|
+
return { a: getPointWorld(ids[0], state), b: getPointWorld(ids[1], state) };
|
|
1308
|
+
}
|
|
1309
|
+
function lineLineClosestMidpoint(A, B, C, D) {
|
|
1310
|
+
const u = sub(B, A), v = sub(D, C), w0 = sub(A, C);
|
|
1311
|
+
const a = dot(u, u), b = dot(u, v), cc = dot(v, v), d = dot(u, w0), e = dot(v, w0);
|
|
1312
|
+
const denom = a * cc - b * b;
|
|
1313
|
+
if (Math.abs(denom) < 1e-12) return scale(add(A, C), 0.5);
|
|
1314
|
+
const sc = (b * e - cc * d) / denom;
|
|
1315
|
+
const tc = (a * e - b * d) / denom;
|
|
1316
|
+
return scale(add(add(A, scale(u, sc)), add(C, scale(v, tc))), 0.5);
|
|
1317
|
+
}
|
|
1318
|
+
function planeOriginNormal(planeId, state, ctx) {
|
|
1319
|
+
const plane = state.objects[planeId];
|
|
1320
|
+
if (!plane || plane.kind !== "plane3d") throw new Error(`${ctx}: m\u1EB7t ph\u1EB3ng ${planeId} thi\u1EBFu`);
|
|
1321
|
+
const { origin, normal } = getPlaneBasis(plane, state);
|
|
1322
|
+
return { origin, normal };
|
|
1323
|
+
}
|
|
1324
|
+
function lineConstructionWorld(c, state) {
|
|
1325
|
+
switch (c.kind) {
|
|
1326
|
+
case "planePlaneIntersection": {
|
|
1327
|
+
const P1 = planeOriginNormal(c.plane1, state, "planePlaneIntersection");
|
|
1328
|
+
const P2 = planeOriginNormal(c.plane2, state, "planePlaneIntersection");
|
|
1329
|
+
const d = cross(P1.normal, P2.normal);
|
|
1330
|
+
const dd = dot(d, d);
|
|
1331
|
+
if (dd < 1e-12) {
|
|
1332
|
+
return { a: P1.origin, b: add(P1.origin, P2.normal) };
|
|
1333
|
+
}
|
|
1334
|
+
const c1 = dot(P1.normal, P1.origin);
|
|
1335
|
+
const c2 = dot(P2.normal, P2.origin);
|
|
1336
|
+
const p0 = scale(add(scale(cross(P2.normal, d), c1), scale(cross(d, P1.normal), c2)), 1 / dd);
|
|
1337
|
+
return { a: p0, b: add(p0, d) };
|
|
1338
|
+
}
|
|
1339
|
+
case "lineParallelThrough": {
|
|
1340
|
+
const P = getPointWorld(c.point, state);
|
|
1341
|
+
const dir = sub(getPointWorld(c.dirB, state), getPointWorld(c.dirA, state));
|
|
1342
|
+
if (norm(dir) < 1e-12) return { a: P, b: add(P, [1, 0, 0]) };
|
|
1343
|
+
return { a: P, b: add(P, dir) };
|
|
1344
|
+
}
|
|
1345
|
+
case "linePerpToPlane": {
|
|
1346
|
+
const P = getPointWorld(c.point, state);
|
|
1347
|
+
const { normal } = planeOriginNormal(c.plane, state, "linePerpToPlane");
|
|
1348
|
+
return { a: P, b: add(P, normal) };
|
|
1349
|
+
}
|
|
1350
|
+
default: {
|
|
1351
|
+
throw new Error("lineConstructionWorld: kind kh\xF4ng h\u1ED7 tr\u1EE3");
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
function solve3(M, b) {
|
|
1356
|
+
const det3 = (m) => m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
|
|
1357
|
+
const det = det3(M);
|
|
1358
|
+
if (Math.abs(det) < 1e-9) return null;
|
|
1359
|
+
const colDet = (j) => {
|
|
1360
|
+
const A = M.map((r) => r.slice());
|
|
1361
|
+
for (let i = 0; i < 3; i++) A[i][j] = b[i];
|
|
1362
|
+
return det3(A);
|
|
1363
|
+
};
|
|
1364
|
+
return [colDet(0) / det, colDet(1) / det, colDet(2) / det];
|
|
1365
|
+
}
|
|
1366
|
+
function constraintToWorld(c, state) {
|
|
1367
|
+
if (_recDepth >= MAX_REC_DEPTH) throw new Error("constraintToWorld: \u0111\u1EC7 quy qu\xE1 s\xE2u \u2014 chu tr\xECnh tham chi\u1EBFu?");
|
|
1368
|
+
_recDepth++;
|
|
1369
|
+
try {
|
|
1370
|
+
return constraintToWorldInner(c, state);
|
|
1371
|
+
} finally {
|
|
1372
|
+
_recDepth--;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
function constraintToWorldInner(c, state) {
|
|
1376
|
+
switch (c.kind) {
|
|
1377
|
+
case "free":
|
|
1378
|
+
return [c.x, c.y, c.z];
|
|
1379
|
+
case "onGround":
|
|
1380
|
+
return [c.x, c.y, 0];
|
|
1381
|
+
case "onAxis": {
|
|
1382
|
+
if (c.axis === "x") return [c.t, 0, 0];
|
|
1383
|
+
if (c.axis === "y") return [0, c.t, 0];
|
|
1384
|
+
return [0, 0, c.t];
|
|
1385
|
+
}
|
|
1386
|
+
case "onPlane": {
|
|
1387
|
+
const plane = state.objects[c.planeId];
|
|
1388
|
+
if (!plane || plane.kind !== "plane3d") throw new Error("onPlane: plane missing");
|
|
1389
|
+
const { origin, basis1, basis2 } = getPlaneBasis(plane, state);
|
|
1390
|
+
return add(add(origin, scale(basis1, c.u)), scale(basis2, c.v));
|
|
1391
|
+
}
|
|
1392
|
+
case "onLine": {
|
|
1393
|
+
const { a, b } = lineEndpointsWorld(c.lineId, state, "onLine");
|
|
1394
|
+
return add(a, scale(sub(b, a), c.t));
|
|
1395
|
+
}
|
|
1396
|
+
case "onPolygon": {
|
|
1397
|
+
const pg = state.objects[c.polygonId];
|
|
1398
|
+
if (!pg || pg.kind !== "polygon3d") throw new Error("onPolygon: parent missing");
|
|
1399
|
+
const v = pg.attrs.vertices;
|
|
1400
|
+
if (v.length < 3) throw new Error("onPolygon: < 3 vertices");
|
|
1401
|
+
const p1 = getPointWorld(v[0], state);
|
|
1402
|
+
const p2 = getPointWorld(v[1], state);
|
|
1403
|
+
const p3 = getPointWorld(v[2], state);
|
|
1404
|
+
const basis1 = sub(p2, p1);
|
|
1405
|
+
const tmp = sub(p3, p1);
|
|
1406
|
+
const normal = normalize(cross(basis1, tmp));
|
|
1407
|
+
const basis2 = cross(normal, basis1);
|
|
1408
|
+
return add(add(p1, scale(basis1, c.u)), scale(basis2, c.v));
|
|
1409
|
+
}
|
|
1410
|
+
case "onSphere": {
|
|
1411
|
+
const sph = state.objects[c.sphereId];
|
|
1412
|
+
if (!sph || sph.kind !== "sphere3d") throw new Error("onSphere: parent missing");
|
|
1413
|
+
const a = sph.attrs;
|
|
1414
|
+
const center = getPointWorld(a.center, state);
|
|
1415
|
+
const surface = getPointWorld(a.surfacePoint, state);
|
|
1416
|
+
const radius = norm(sub(surface, center));
|
|
1417
|
+
const x = center[0] + radius * Math.sin(c.phi) * Math.cos(c.theta);
|
|
1418
|
+
const y = center[1] + radius * Math.sin(c.phi) * Math.sin(c.theta);
|
|
1419
|
+
const z = center[2] + radius * Math.cos(c.phi);
|
|
1420
|
+
return [x, y, z];
|
|
1421
|
+
}
|
|
1422
|
+
// ───── Điểm phái sinh (v1) ─────
|
|
1423
|
+
case "midpoint": {
|
|
1424
|
+
const p1 = getPointWorld(c.p1, state);
|
|
1425
|
+
const p2 = getPointWorld(c.p2, state);
|
|
1426
|
+
return scale(add(p1, p2), 0.5);
|
|
1427
|
+
}
|
|
1428
|
+
case "centroid": {
|
|
1429
|
+
const n = c.vertices.length;
|
|
1430
|
+
if (n === 0) return [0, 0, 0];
|
|
1431
|
+
let acc = [0, 0, 0];
|
|
1432
|
+
for (const id of c.vertices) acc = add(acc, getPointWorld(id, state));
|
|
1433
|
+
return scale(acc, 1 / n);
|
|
1434
|
+
}
|
|
1435
|
+
case "circumsphereCenter": {
|
|
1436
|
+
const P = c.vertices.map((id) => getPointWorld(id, state));
|
|
1437
|
+
if (P.length < 4) return P.length ? P[0] : [0, 0, 0];
|
|
1438
|
+
const p0 = P[0];
|
|
1439
|
+
const M = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
|
|
1440
|
+
const rhs = [0, 0, 0];
|
|
1441
|
+
for (let i = 1; i < P.length; i++) {
|
|
1442
|
+
const r = [2 * (P[i][0] - p0[0]), 2 * (P[i][1] - p0[1]), 2 * (P[i][2] - p0[2])];
|
|
1443
|
+
const bi = dot(P[i], P[i]) - dot(p0, p0);
|
|
1444
|
+
for (let a = 0; a < 3; a++) {
|
|
1445
|
+
for (let bcol = 0; bcol < 3; bcol++) M[a][bcol] += r[a] * r[bcol];
|
|
1446
|
+
rhs[a] += r[a] * bi;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
const sol = solve3(M, rhs);
|
|
1450
|
+
if (sol) return sol;
|
|
1451
|
+
let acc = [0, 0, 0];
|
|
1452
|
+
for (const p of P) acc = add(acc, p);
|
|
1453
|
+
return scale(acc, 1 / P.length);
|
|
1454
|
+
}
|
|
1455
|
+
case "pyramidInsphereCenter": {
|
|
1456
|
+
const S = getPointWorld(c.apex, state);
|
|
1457
|
+
const base = c.vertices.map((id) => getPointWorld(id, state));
|
|
1458
|
+
const n = base.length;
|
|
1459
|
+
if (n < 3) return S;
|
|
1460
|
+
let G = [0, 0, 0];
|
|
1461
|
+
for (const p of base) G = add(G, p);
|
|
1462
|
+
G = scale(G, 1 / n);
|
|
1463
|
+
let nb = normalize(cross(sub(base[1], base[0]), sub(base[2], base[0])));
|
|
1464
|
+
if (dot(nb, sub(S, G)) < 0) nb = scale(nb, -1);
|
|
1465
|
+
let m = normalize(cross(sub(base[0], S), sub(base[1], S)));
|
|
1466
|
+
if (dot(m, sub(G, base[0])) < 0) m = scale(m, -1);
|
|
1467
|
+
const denom = 1 - dot(m, nb);
|
|
1468
|
+
const s = Math.abs(denom) < 1e-9 ? NaN : dot(m, sub(G, base[0])) / denom;
|
|
1469
|
+
if (!Number.isFinite(s) || s <= 0) {
|
|
1470
|
+
return scale(add(S, scale(G, n)), 1 / (n + 1));
|
|
1471
|
+
}
|
|
1472
|
+
return add(G, scale(nb, s));
|
|
1473
|
+
}
|
|
1474
|
+
case "faceCircumcenter": {
|
|
1475
|
+
const P = c.vertices.map((id) => getPointWorld(id, state));
|
|
1476
|
+
if (P.length < 3) return P.length ? P[0] : [0, 0, 0];
|
|
1477
|
+
const [p0, p1, p2] = P;
|
|
1478
|
+
const e1 = sub(p1, p0), e2 = sub(p2, p0);
|
|
1479
|
+
const nrm = cross(e1, e2);
|
|
1480
|
+
const M = [
|
|
1481
|
+
[2 * e1[0], 2 * e1[1], 2 * e1[2]],
|
|
1482
|
+
[2 * e2[0], 2 * e2[1], 2 * e2[2]],
|
|
1483
|
+
[nrm[0], nrm[1], nrm[2]]
|
|
1484
|
+
];
|
|
1485
|
+
const rhs = [dot(p1, p1) - dot(p0, p0), dot(p2, p2) - dot(p0, p0), dot(nrm, p0)];
|
|
1486
|
+
const sol = solve3(M, rhs);
|
|
1487
|
+
if (sol) return sol;
|
|
1488
|
+
return scale(add(add(p0, p1), p2), 1 / 3);
|
|
1489
|
+
}
|
|
1490
|
+
case "pointAboveFace": {
|
|
1491
|
+
const G = getPointWorld(c.base, state);
|
|
1492
|
+
const P = c.vertices.map((id) => getPointWorld(id, state));
|
|
1493
|
+
if (P.length < 3) return G;
|
|
1494
|
+
let n = normalize(cross(sub(P[1], P[0]), sub(P[2], P[0])));
|
|
1495
|
+
const S = getPointWorld(c.apex, state);
|
|
1496
|
+
if (dot(n, sub(S, P[0])) < 0) n = scale(n, -1);
|
|
1497
|
+
const h = dot(sub(S, P[0]), n);
|
|
1498
|
+
if (!Number.isFinite(h) || h <= 1e-9) return G;
|
|
1499
|
+
return add(G, scale(n, h));
|
|
1500
|
+
}
|
|
1501
|
+
case "intersectionLines": {
|
|
1502
|
+
const A = getPointWorld(c.a1, state), B = getPointWorld(c.b1, state);
|
|
1503
|
+
const C = getPointWorld(c.a2, state), D = getPointWorld(c.b2, state);
|
|
1504
|
+
return lineLineClosestMidpoint(A, B, C, D);
|
|
1505
|
+
}
|
|
1506
|
+
case "intersectionLinePlane": {
|
|
1507
|
+
const A = getPointWorld(c.a, state), B = getPointWorld(c.b, state);
|
|
1508
|
+
const plane = state.objects[c.plane];
|
|
1509
|
+
if (!plane || plane.kind !== "plane3d") throw new Error("intersectionLinePlane: m\u1EB7t ph\u1EB3ng thi\u1EBFu");
|
|
1510
|
+
const { origin, normal } = getPlaneBasis(plane, state);
|
|
1511
|
+
const dir = sub(B, A);
|
|
1512
|
+
const dn = dot(dir, normal);
|
|
1513
|
+
if (Math.abs(dn) < 1e-12) return A;
|
|
1514
|
+
const t = dot(sub(origin, A), normal) / dn;
|
|
1515
|
+
return add(A, scale(dir, t));
|
|
1516
|
+
}
|
|
1517
|
+
case "perpFootLine": {
|
|
1518
|
+
const P = getPointWorld(c.from, state);
|
|
1519
|
+
const A = getPointWorld(c.a, state), B = getPointWorld(c.b, state);
|
|
1520
|
+
const u = sub(B, A);
|
|
1521
|
+
const uu = dot(u, u);
|
|
1522
|
+
const t = uu === 0 ? 0 : dot(sub(P, A), u) / uu;
|
|
1523
|
+
return add(A, scale(u, t));
|
|
1524
|
+
}
|
|
1525
|
+
case "perpFootPlane": {
|
|
1526
|
+
const P = getPointWorld(c.from, state);
|
|
1527
|
+
const plane = state.objects[c.plane];
|
|
1528
|
+
if (!plane || plane.kind !== "plane3d") throw new Error("perpFootPlane: m\u1EB7t ph\u1EB3ng thi\u1EBFu");
|
|
1529
|
+
const { origin, normal } = getPlaneBasis(plane, state);
|
|
1530
|
+
const dist2 = dot(sub(P, origin), normal);
|
|
1531
|
+
return sub(P, scale(normal, dist2));
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
var MAX_REC_DEPTH, _recDepth;
|
|
1536
|
+
var init_constraint3d_math = __esm({
|
|
1537
|
+
"src/core/scene/kinds/constraint3d-math.ts"() {
|
|
1538
|
+
MAX_REC_DEPTH = 512;
|
|
1539
|
+
_recDepth = 0;
|
|
1540
|
+
}
|
|
1541
|
+
});
|
|
1542
|
+
|
|
1169
1543
|
// src/core/scene/kinds/point3d.ts
|
|
1170
1544
|
var def;
|
|
1171
1545
|
var init_point3d = __esm({
|
|
1172
1546
|
"src/core/scene/kinds/point3d.ts"() {
|
|
1173
1547
|
init_registry();
|
|
1174
1548
|
init_d_constraint();
|
|
1549
|
+
init_constraint3d_math();
|
|
1175
1550
|
def = {
|
|
1176
1551
|
type: "point3d",
|
|
1177
1552
|
schemaVersion: 1,
|
|
@@ -1209,6 +1584,15 @@ var init_point3d = __esm({
|
|
|
1209
1584
|
if (c.kind === "onLine") return `${obj.label} tr\xEAn \u0111\u01B0\u1EDDng ${c.lineId}`;
|
|
1210
1585
|
if (c.kind === "onPolygon") return `${obj.label} tr\xEAn \u0111a gi\xE1c ${c.polygonId}`;
|
|
1211
1586
|
if (c.kind === "onSphere") return `${obj.label} tr\xEAn m\u1EB7t c\u1EA7u ${c.sphereId}`;
|
|
1587
|
+
if (c.kind === "midpoint") return `${obj.label} = trung \u0111i\u1EC3m ${c.p1}${c.p2}`;
|
|
1588
|
+
if (c.kind === "centroid") return `${obj.label} = tr\u1ECDng t\xE2m ${c.vertices.join("")}`;
|
|
1589
|
+
if (c.kind === "intersectionLines") return `${obj.label} = giao 2 \u0111\u01B0\u1EDDng (${c.a1}${c.b1}, ${c.a2}${c.b2})`;
|
|
1590
|
+
if (c.kind === "intersectionLinePlane") return `${obj.label} = giao ${c.a}${c.b} \u2229 ${c.plane}`;
|
|
1591
|
+
if (c.kind === "perpFootLine") return `${obj.label} = ch\xE2n \u22A5 t\u1EEB ${c.from} xu\u1ED1ng ${c.a}${c.b}`;
|
|
1592
|
+
if (c.kind === "perpFootPlane") return `${obj.label} = ch\xE2n \u22A5 t\u1EEB ${c.from} xu\u1ED1ng ${c.plane}`;
|
|
1593
|
+
if (c.kind === "pyramidInsphereCenter") return `${obj.label} = t\xE2m c\u1EA7u n\u1ED9i ti\u1EBFp ch\xF3p ${c.apex}.${c.vertices.join("")}`;
|
|
1594
|
+
if (c.kind === "faceCircumcenter") return `${obj.label} = t\xE2m ngo\u1EA1i ti\u1EBFp ${c.vertices.join("")}`;
|
|
1595
|
+
if (c.kind === "pointAboveFace") return `${obj.label} = \u0111\u1EC9nh tr\u1EE5c tr\u1EE5 \u22A5 m\u1EB7t ${c.vertices.join("")}`;
|
|
1212
1596
|
return obj.label;
|
|
1213
1597
|
},
|
|
1214
1598
|
render: (obj, ctx) => {
|
|
@@ -1258,6 +1642,15 @@ var init_point3d = __esm({
|
|
|
1258
1642
|
() => sph.F(c.theta, c.phi)[2]
|
|
1259
1643
|
], opts);
|
|
1260
1644
|
}
|
|
1645
|
+
const getState = ctx.getState;
|
|
1646
|
+
if (getState) {
|
|
1647
|
+
const cw = () => constraintToWorld(c, getState());
|
|
1648
|
+
return view.create("point3d", [
|
|
1649
|
+
() => cw()[0],
|
|
1650
|
+
() => cw()[1],
|
|
1651
|
+
() => cw()[2]
|
|
1652
|
+
], { ...opts, needsRegularUpdate: true });
|
|
1653
|
+
}
|
|
1261
1654
|
return view.create("point3d", [0, 0, 0], opts);
|
|
1262
1655
|
}
|
|
1263
1656
|
};
|
|
@@ -1319,32 +1712,77 @@ var init_segment3d = __esm({
|
|
|
1319
1712
|
});
|
|
1320
1713
|
|
|
1321
1714
|
// src/core/scene/kinds/line3d.ts
|
|
1715
|
+
function line3dConstructionRefs(c) {
|
|
1716
|
+
switch (c.kind) {
|
|
1717
|
+
case "planePlaneIntersection":
|
|
1718
|
+
return [c.plane1, c.plane2];
|
|
1719
|
+
case "lineParallelThrough":
|
|
1720
|
+
return [c.point, c.dirA, c.dirB];
|
|
1721
|
+
case "linePerpToPlane":
|
|
1722
|
+
return [c.point, c.plane];
|
|
1723
|
+
default: {
|
|
1724
|
+
return [];
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
var def3;
|
|
1322
1729
|
var init_line3d = __esm({
|
|
1323
1730
|
"src/core/scene/kinds/line3d.ts"() {
|
|
1324
1731
|
init_registry();
|
|
1325
1732
|
init_labelOf();
|
|
1326
|
-
|
|
1733
|
+
init_constraint3d_math();
|
|
1734
|
+
def3 = {
|
|
1327
1735
|
type: "line3d",
|
|
1328
1736
|
schemaVersion: 1,
|
|
1329
1737
|
migrate: {},
|
|
1330
1738
|
validate: (a) => {
|
|
1331
|
-
if (
|
|
1739
|
+
if (a?.construction) return;
|
|
1740
|
+
if (!a?.p1 || !a?.p2) throw new Error("line3d: p1/p2 required (ho\u1EB7c construction)");
|
|
1741
|
+
},
|
|
1742
|
+
dependsOn: (a) => a.construction ? line3dConstructionRefs(a.construction) : [a.p1, a.p2],
|
|
1743
|
+
describe: (obj, state) => {
|
|
1744
|
+
const c = obj.attrs.construction;
|
|
1745
|
+
if (!c) return `\u0110\u01B0\u1EDDng ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}`;
|
|
1746
|
+
switch (c.kind) {
|
|
1747
|
+
case "planePlaneIntersection":
|
|
1748
|
+
return `Giao tuy\u1EBFn ${obj.label} = ${labelOf(c.plane1, state)} \u2229 ${labelOf(c.plane2, state)}`;
|
|
1749
|
+
case "lineParallelThrough":
|
|
1750
|
+
return `${obj.label} \u2225 ${labelOf(c.dirA, state)}${labelOf(c.dirB, state)} qua ${labelOf(c.point, state)}`;
|
|
1751
|
+
case "linePerpToPlane":
|
|
1752
|
+
return `${obj.label} \u22A5 ${labelOf(c.plane, state)} qua ${labelOf(c.point, state)}`;
|
|
1753
|
+
default:
|
|
1754
|
+
return obj.label;
|
|
1755
|
+
}
|
|
1332
1756
|
},
|
|
1333
|
-
dependsOn: (a) => [a.p1, a.p2],
|
|
1334
|
-
describe: (obj, state) => `\u0110\u01B0\u1EDDng ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}`,
|
|
1335
1757
|
render: (obj, ctx) => {
|
|
1336
1758
|
const view = ctx.jxg;
|
|
1759
|
+
const baseOpts = {
|
|
1760
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1761
|
+
strokeWidth: 2,
|
|
1762
|
+
visible: obj.visible
|
|
1763
|
+
};
|
|
1764
|
+
const c = obj.attrs.construction;
|
|
1765
|
+
if (c) {
|
|
1766
|
+
const getState = ctx.getState;
|
|
1767
|
+
if (!getState) throw new Error("line3d construction: c\u1EA7n ctx.getState");
|
|
1768
|
+
const lc = () => lineConstructionWorld(c, getState());
|
|
1769
|
+
return view.create("line3d", [() => lc().a, () => lc().b], {
|
|
1770
|
+
...baseOpts,
|
|
1771
|
+
straightFirst: true,
|
|
1772
|
+
straightLast: true,
|
|
1773
|
+
needsRegularUpdate: true
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1337
1776
|
const pA = ctx.resolveRef(obj.attrs.p1);
|
|
1338
1777
|
const pB = ctx.resolveRef(obj.attrs.p2);
|
|
1339
1778
|
return view.create("line3d", [pA, pB], {
|
|
1779
|
+
...baseOpts,
|
|
1340
1780
|
straightFirst: true,
|
|
1341
|
-
straightLast: true
|
|
1342
|
-
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
1343
|
-
strokeWidth: 2,
|
|
1344
|
-
visible: obj.visible
|
|
1781
|
+
straightLast: true
|
|
1345
1782
|
});
|
|
1346
1783
|
}
|
|
1347
|
-
}
|
|
1784
|
+
};
|
|
1785
|
+
registerKind(def3);
|
|
1348
1786
|
}
|
|
1349
1787
|
});
|
|
1350
1788
|
|
|
@@ -1410,33 +1848,77 @@ var init_vector3d = __esm({
|
|
|
1410
1848
|
});
|
|
1411
1849
|
|
|
1412
1850
|
// src/core/scene/kinds/plane3d.ts
|
|
1851
|
+
function plane3dConstructionRefs(c) {
|
|
1852
|
+
switch (c.kind) {
|
|
1853
|
+
case "planeParallelThrough":
|
|
1854
|
+
return [c.point, c.refPlane];
|
|
1855
|
+
case "planePerpToLine":
|
|
1856
|
+
return [c.point, c.lineA, c.lineB];
|
|
1857
|
+
default: {
|
|
1858
|
+
return [];
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
var def4;
|
|
1413
1863
|
var init_plane3d = __esm({
|
|
1414
1864
|
"src/core/scene/kinds/plane3d.ts"() {
|
|
1415
1865
|
init_registry();
|
|
1416
1866
|
init_labelOf();
|
|
1417
|
-
|
|
1867
|
+
init_constraint3d_math();
|
|
1868
|
+
def4 = {
|
|
1418
1869
|
type: "plane3d",
|
|
1419
1870
|
schemaVersion: 1,
|
|
1420
1871
|
migrate: {},
|
|
1421
1872
|
validate: (a) => {
|
|
1422
|
-
if (
|
|
1873
|
+
if (a?.construction) return;
|
|
1874
|
+
if (!a?.p1 || !a?.p2 || !a?.p3) throw new Error("plane3d: c\u1EA7n 3 \u0111i\u1EC3m (ho\u1EB7c construction)");
|
|
1875
|
+
},
|
|
1876
|
+
dependsOn: (a) => a.construction ? plane3dConstructionRefs(a.construction) : [a.p1, a.p2, a.p3],
|
|
1877
|
+
describe: (obj, state) => {
|
|
1878
|
+
const c = obj.attrs.construction;
|
|
1879
|
+
if (!c) {
|
|
1880
|
+
return `M\u1EB7t ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}, ${labelOf(obj.attrs.p3, state)}`;
|
|
1881
|
+
}
|
|
1882
|
+
switch (c.kind) {
|
|
1883
|
+
case "planeParallelThrough":
|
|
1884
|
+
return `${obj.label} \u2225 ${labelOf(c.refPlane, state)} qua ${labelOf(c.point, state)}`;
|
|
1885
|
+
case "planePerpToLine":
|
|
1886
|
+
return `${obj.label} \u22A5 ${labelOf(c.lineA, state)}${labelOf(c.lineB, state)} qua ${labelOf(c.point, state)}`;
|
|
1887
|
+
default:
|
|
1888
|
+
return obj.label;
|
|
1889
|
+
}
|
|
1423
1890
|
},
|
|
1424
|
-
dependsOn: (a) => [a.p1, a.p2, a.p3],
|
|
1425
|
-
describe: (obj, state) => `M\u1EB7t ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}, ${labelOf(obj.attrs.p3, state)}`,
|
|
1426
1891
|
render: (obj, ctx) => {
|
|
1427
1892
|
const view = ctx.jxg;
|
|
1428
|
-
|
|
1429
|
-
ctx.resolveRef(obj.attrs.p1),
|
|
1430
|
-
ctx.resolveRef(obj.attrs.p2),
|
|
1431
|
-
ctx.resolveRef(obj.attrs.p3)
|
|
1432
|
-
], {
|
|
1893
|
+
const opts = {
|
|
1433
1894
|
fillOpacity: 0.15,
|
|
1434
1895
|
fillColor: obj.attrs.color ?? "#60a5fa",
|
|
1435
1896
|
strokeColor: obj.attrs.color ?? "#60a5fa",
|
|
1436
1897
|
visible: obj.visible
|
|
1437
|
-
}
|
|
1898
|
+
};
|
|
1899
|
+
const c = obj.attrs.construction;
|
|
1900
|
+
if (c) {
|
|
1901
|
+
const getState = ctx.getState;
|
|
1902
|
+
if (!getState) throw new Error("plane3d construction: c\u1EA7n ctx.getState");
|
|
1903
|
+
const pc = () => planeConstructionWorld(c, getState());
|
|
1904
|
+
const diff = (which) => {
|
|
1905
|
+
const r = pc();
|
|
1906
|
+
const q = r[which];
|
|
1907
|
+
return [q[0] - r.p1[0], q[1] - r.p1[1], q[2] - r.p1[2]];
|
|
1908
|
+
};
|
|
1909
|
+
return view.create("plane3d", [() => pc().p1, () => diff("p2"), () => diff("p3")], {
|
|
1910
|
+
...opts,
|
|
1911
|
+
needsRegularUpdate: true
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
return view.create("plane3d", [
|
|
1915
|
+
ctx.resolveRef(obj.attrs.p1),
|
|
1916
|
+
ctx.resolveRef(obj.attrs.p2),
|
|
1917
|
+
ctx.resolveRef(obj.attrs.p3)
|
|
1918
|
+
], opts);
|
|
1438
1919
|
}
|
|
1439
|
-
}
|
|
1920
|
+
};
|
|
1921
|
+
registerKind(def4);
|
|
1440
1922
|
}
|
|
1441
1923
|
});
|
|
1442
1924
|
|
|
@@ -1535,11 +2017,37 @@ var init_polyhedron3d = __esm({
|
|
|
1535
2017
|
}
|
|
1536
2018
|
});
|
|
1537
2019
|
|
|
2020
|
+
// src/core/scene/kinds/_ringBasis.ts
|
|
2021
|
+
function perpBasis(axis) {
|
|
2022
|
+
const n = Math.hypot(axis[0], axis[1], axis[2]);
|
|
2023
|
+
if (n < 1e-12) return [[1, 0, 0], [0, 1, 0]];
|
|
2024
|
+
const a = [axis[0] / n, axis[1] / n, axis[2] / n];
|
|
2025
|
+
const seed = Math.abs(a[2]) < 0.9 ? [0, 0, 1] : [1, 0, 0];
|
|
2026
|
+
let u = [
|
|
2027
|
+
seed[1] * a[2] - seed[2] * a[1],
|
|
2028
|
+
seed[2] * a[0] - seed[0] * a[2],
|
|
2029
|
+
seed[0] * a[1] - seed[1] * a[0]
|
|
2030
|
+
];
|
|
2031
|
+
const un = Math.hypot(u[0], u[1], u[2]) || 1;
|
|
2032
|
+
u = [u[0] / un, u[1] / un, u[2] / un];
|
|
2033
|
+
const v = [
|
|
2034
|
+
a[1] * u[2] - a[2] * u[1],
|
|
2035
|
+
a[2] * u[0] - a[0] * u[2],
|
|
2036
|
+
a[0] * u[1] - a[1] * u[0]
|
|
2037
|
+
];
|
|
2038
|
+
return [u, v];
|
|
2039
|
+
}
|
|
2040
|
+
var init_ringBasis = __esm({
|
|
2041
|
+
"src/core/scene/kinds/_ringBasis.ts"() {
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
2044
|
+
|
|
1538
2045
|
// src/core/scene/kinds/cylinder3d.ts
|
|
1539
2046
|
var CURVED_SEGMENTS;
|
|
1540
2047
|
var init_cylinder3d = __esm({
|
|
1541
2048
|
"src/core/scene/kinds/cylinder3d.ts"() {
|
|
1542
2049
|
init_registry();
|
|
2050
|
+
init_ringBasis();
|
|
1543
2051
|
CURVED_SEGMENTS = 16;
|
|
1544
2052
|
registerKind({
|
|
1545
2053
|
type: "cylinder3d",
|
|
@@ -1558,14 +2066,17 @@ var init_cylinder3d = __esm({
|
|
|
1558
2066
|
const r = obj.attrs.radius;
|
|
1559
2067
|
const ax = a.X?.() ?? 0, ay = a.Y?.() ?? 0, az = a.Z?.() ?? 0;
|
|
1560
2068
|
const bx = b.X?.() ?? 0, by = b.Y?.() ?? 0, bz = b.Z?.() ?? 0;
|
|
2069
|
+
const [u, v] = perpBasis([bx - ax, by - ay, bz - az]);
|
|
1561
2070
|
const baseRing = [];
|
|
1562
2071
|
const topRing = [];
|
|
1563
2072
|
for (let i = 0; i < CURVED_SEGMENTS; i++) {
|
|
1564
2073
|
const theta = i / CURVED_SEGMENTS * Math.PI * 2;
|
|
1565
|
-
const
|
|
1566
|
-
const
|
|
1567
|
-
|
|
1568
|
-
|
|
2074
|
+
const c = Math.cos(theta), s = Math.sin(theta);
|
|
2075
|
+
const ox = r * (c * u[0] + s * v[0]);
|
|
2076
|
+
const oy = r * (c * u[1] + s * v[1]);
|
|
2077
|
+
const oz = r * (c * u[2] + s * v[2]);
|
|
2078
|
+
baseRing.push([ax + ox, ay + oy, az + oz]);
|
|
2079
|
+
topRing.push([bx + ox, by + oy, bz + oz]);
|
|
1569
2080
|
}
|
|
1570
2081
|
const vertices = [...baseRing, ...topRing];
|
|
1571
2082
|
const faces = [];
|
|
@@ -1576,7 +2087,7 @@ var init_cylinder3d = __esm({
|
|
|
1576
2087
|
faces.push([i, next, CURVED_SEGMENTS + next, CURVED_SEGMENTS + i]);
|
|
1577
2088
|
}
|
|
1578
2089
|
const vertJxgs = vertices.map(
|
|
1579
|
-
(
|
|
2090
|
+
(v2, i) => view.create("point3d", v2, {
|
|
1580
2091
|
id: `${obj.id}.v${i}`,
|
|
1581
2092
|
visible: false,
|
|
1582
2093
|
fixed: true,
|
|
@@ -1604,6 +2115,7 @@ var CURVED_SEGMENTS2;
|
|
|
1604
2115
|
var init_cone3d = __esm({
|
|
1605
2116
|
"src/core/scene/kinds/cone3d.ts"() {
|
|
1606
2117
|
init_registry();
|
|
2118
|
+
init_ringBasis();
|
|
1607
2119
|
CURVED_SEGMENTS2 = 16;
|
|
1608
2120
|
registerKind({
|
|
1609
2121
|
type: "cone3d",
|
|
@@ -1626,10 +2138,16 @@ var init_cone3d = __esm({
|
|
|
1626
2138
|
apexPt.Y?.() ?? 0,
|
|
1627
2139
|
apexPt.Z?.() ?? 0
|
|
1628
2140
|
];
|
|
2141
|
+
const [u, v] = perpBasis([apexCoords[0] - bx, apexCoords[1] - by, apexCoords[2] - bz]);
|
|
1629
2142
|
const baseRing = [];
|
|
1630
2143
|
for (let i = 0; i < CURVED_SEGMENTS2; i++) {
|
|
1631
2144
|
const theta = i / CURVED_SEGMENTS2 * Math.PI * 2;
|
|
1632
|
-
|
|
2145
|
+
const c = Math.cos(theta), s = Math.sin(theta);
|
|
2146
|
+
baseRing.push([
|
|
2147
|
+
bx + r * (c * u[0] + s * v[0]),
|
|
2148
|
+
by + r * (c * u[1] + s * v[1]),
|
|
2149
|
+
bz + r * (c * u[2] + s * v[2])
|
|
2150
|
+
]);
|
|
1633
2151
|
}
|
|
1634
2152
|
const apexIdx = baseRing.length;
|
|
1635
2153
|
const vertices = [...baseRing, apexCoords];
|
|
@@ -1638,7 +2156,7 @@ var init_cone3d = __esm({
|
|
|
1638
2156
|
faces.push([i, (i + 1) % CURVED_SEGMENTS2, apexIdx]);
|
|
1639
2157
|
}
|
|
1640
2158
|
const vertJxgs = vertices.map(
|
|
1641
|
-
(
|
|
2159
|
+
(v2, i) => view.create("point3d", v2, {
|
|
1642
2160
|
id: `${obj.id}.v${i}`,
|
|
1643
2161
|
visible: false,
|
|
1644
2162
|
fixed: true,
|
|
@@ -1727,8 +2245,16 @@ function constraintRefs2D(c) {
|
|
|
1727
2245
|
}
|
|
1728
2246
|
case "excenter":
|
|
1729
2247
|
return [c.vertices[0], c.vertices[1], c.vertices[2]];
|
|
1730
|
-
|
|
2248
|
+
case "commonTangentPoint":
|
|
2249
|
+
return [c.circles[0], c.circles[1]];
|
|
2250
|
+
// Các kind KHÔNG có ref scene-object (toạ độ literal): liệt kê TƯỜNG MINH để
|
|
2251
|
+
// exhaustive never-guard bên dưới buộc khai báo khi thêm constraint kind mới.
|
|
2252
|
+
case "free":
|
|
2253
|
+
case "onAxis":
|
|
1731
2254
|
return [];
|
|
2255
|
+
default: {
|
|
2256
|
+
return [];
|
|
2257
|
+
}
|
|
1732
2258
|
}
|
|
1733
2259
|
}
|
|
1734
2260
|
var init_d_constraint2 = __esm({
|
|
@@ -2250,19 +2776,19 @@ function buildJxgTransforms(board, ctx, t) {
|
|
|
2250
2776
|
}
|
|
2251
2777
|
}
|
|
2252
2778
|
function makeDistanceFn(ctx, d) {
|
|
2253
|
-
const
|
|
2779
|
+
const scale2 = d.scale ?? 1;
|
|
2254
2780
|
const offset = d.offset ?? 0;
|
|
2255
2781
|
if (d.kind === "literal") {
|
|
2256
2782
|
const v = d.value;
|
|
2257
|
-
return () =>
|
|
2783
|
+
return () => scale2 * v + offset;
|
|
2258
2784
|
}
|
|
2259
2785
|
if (d.kind === "segmentLength") {
|
|
2260
2786
|
const p = ctx.resolveRef(d.p1);
|
|
2261
2787
|
const q = ctx.resolveRef(d.p2);
|
|
2262
|
-
return () =>
|
|
2788
|
+
return () => scale2 * Math.hypot(p.X() - q.X(), p.Y() - q.Y()) + offset;
|
|
2263
2789
|
}
|
|
2264
2790
|
const circle = ctx.resolveRef(d.circle);
|
|
2265
|
-
return () =>
|
|
2791
|
+
return () => scale2 * circle.Radius() + offset;
|
|
2266
2792
|
}
|
|
2267
2793
|
function buildPointOpts(obj) {
|
|
2268
2794
|
return {
|
|
@@ -2311,6 +2837,73 @@ var init_pointAtDistance = __esm({
|
|
|
2311
2837
|
}
|
|
2312
2838
|
});
|
|
2313
2839
|
|
|
2840
|
+
// src/stamps/geometry-2d/geometry/commonTangent.ts
|
|
2841
|
+
function computeCommonTangentPoint(O1, r1, O2, r2, on, variant, side) {
|
|
2842
|
+
const dx = O2[0] - O1[0];
|
|
2843
|
+
const dy = O2[1] - O1[1];
|
|
2844
|
+
const d = Math.hypot(dx, dy);
|
|
2845
|
+
if (d < EPS) return null;
|
|
2846
|
+
const beta = Math.atan2(dy, dx);
|
|
2847
|
+
const ratio = variant === "external" ? (r1 - r2) / d : (r1 + r2) / d;
|
|
2848
|
+
if (Math.abs(ratio) > 1) return null;
|
|
2849
|
+
const gamma = Math.acos(ratio);
|
|
2850
|
+
const s = side === 0 ? 1 : -1;
|
|
2851
|
+
const angle = beta + s * gamma;
|
|
2852
|
+
const nx = Math.cos(angle);
|
|
2853
|
+
const ny = Math.sin(angle);
|
|
2854
|
+
if (on === 0) {
|
|
2855
|
+
return [O1[0] + r1 * nx, O1[1] + r1 * ny];
|
|
2856
|
+
}
|
|
2857
|
+
if (variant === "external") {
|
|
2858
|
+
return [O2[0] + r2 * nx, O2[1] + r2 * ny];
|
|
2859
|
+
}
|
|
2860
|
+
return [O2[0] - r2 * nx, O2[1] - r2 * ny];
|
|
2861
|
+
}
|
|
2862
|
+
var EPS;
|
|
2863
|
+
var init_commonTangent = __esm({
|
|
2864
|
+
"src/stamps/geometry-2d/geometry/commonTangent.ts"() {
|
|
2865
|
+
EPS = 1e-9;
|
|
2866
|
+
}
|
|
2867
|
+
});
|
|
2868
|
+
|
|
2869
|
+
// src/core/scene/kinds/point-constraints/commonTangentPoint.ts
|
|
2870
|
+
var commonTangentPointConstraint;
|
|
2871
|
+
var init_commonTangentPoint = __esm({
|
|
2872
|
+
"src/core/scene/kinds/point-constraints/commonTangentPoint.ts"() {
|
|
2873
|
+
init_commonTangent();
|
|
2874
|
+
init_types3();
|
|
2875
|
+
commonTangentPointConstraint = definePointConstraint({
|
|
2876
|
+
kind: "commonTangentPoint",
|
|
2877
|
+
describe: (obj, state, c) => {
|
|
2878
|
+
const c1 = state?.objects[c.circles[0]]?.label ?? c.circles[0];
|
|
2879
|
+
const c2 = state?.objects[c.circles[1]]?.label ?? c.circles[1];
|
|
2880
|
+
const v = c.variant === "internal" ? "trong" : "ngo\xE0i";
|
|
2881
|
+
return `${obj.label} = ti\u1EBFp \u0111i\u1EC3m ti\u1EBFp tuy\u1EBFn chung ${v} ${c1},${c2} (tr\xEAn ${c.on === 0 ? c1 : c2})`;
|
|
2882
|
+
},
|
|
2883
|
+
render: (obj, ctx, c, opts) => {
|
|
2884
|
+
const board = ctx.jxg;
|
|
2885
|
+
const k1 = ctx.resolveRef(c.circles[0]);
|
|
2886
|
+
const k2 = ctx.resolveRef(c.circles[1]);
|
|
2887
|
+
const O1 = k1?.center ?? k1?.midpoint ?? k1;
|
|
2888
|
+
const O2 = k2?.center ?? k2?.midpoint ?? k2;
|
|
2889
|
+
const compute = () => {
|
|
2890
|
+
const t = computeCommonTangentPoint(
|
|
2891
|
+
[O1.X(), O1.Y()],
|
|
2892
|
+
k1.Radius(),
|
|
2893
|
+
[O2.X(), O2.Y()],
|
|
2894
|
+
k2.Radius(),
|
|
2895
|
+
c.on,
|
|
2896
|
+
c.variant,
|
|
2897
|
+
c.side
|
|
2898
|
+
);
|
|
2899
|
+
return t ?? [0, 0];
|
|
2900
|
+
};
|
|
2901
|
+
return board.create("point", [() => compute()[0], () => compute()[1]], opts);
|
|
2902
|
+
}
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
});
|
|
2906
|
+
|
|
2314
2907
|
// src/core/scene/kinds/point-constraints/circleIntersection.ts
|
|
2315
2908
|
var circleIntersectionConstraint;
|
|
2316
2909
|
var init_circleIntersection = __esm({
|
|
@@ -2590,6 +3183,7 @@ var init_registry2 = __esm({
|
|
|
2590
3183
|
init_excenter();
|
|
2591
3184
|
init_mixtilinearPoint();
|
|
2592
3185
|
init_pointAtDistance();
|
|
3186
|
+
init_commonTangentPoint();
|
|
2593
3187
|
init_circleIntersection();
|
|
2594
3188
|
init_circleSecondIntersection();
|
|
2595
3189
|
init_secondIntersection();
|
|
@@ -2616,6 +3210,7 @@ var init_registry2 = __esm({
|
|
|
2616
3210
|
excenterConstraint,
|
|
2617
3211
|
mixtilinearPointConstraint,
|
|
2618
3212
|
pointAtDistanceConstraint,
|
|
3213
|
+
commonTangentPointConstraint,
|
|
2619
3214
|
circleIntersectionConstraint,
|
|
2620
3215
|
circleSecondIntersectionConstraint,
|
|
2621
3216
|
secondIntersectionConstraint,
|
|
@@ -2632,7 +3227,7 @@ var init_registry2 = __esm({
|
|
|
2632
3227
|
});
|
|
2633
3228
|
|
|
2634
3229
|
// src/core/scene/kinds/point.ts
|
|
2635
|
-
var
|
|
3230
|
+
var def5;
|
|
2636
3231
|
var init_point = __esm({
|
|
2637
3232
|
"src/core/scene/kinds/point.ts"() {
|
|
2638
3233
|
init_registry();
|
|
@@ -2640,7 +3235,7 @@ var init_point = __esm({
|
|
|
2640
3235
|
init_registry2();
|
|
2641
3236
|
init_shared();
|
|
2642
3237
|
init_label();
|
|
2643
|
-
|
|
3238
|
+
def5 = {
|
|
2644
3239
|
type: "point",
|
|
2645
3240
|
schemaVersion: 1,
|
|
2646
3241
|
migrate: {},
|
|
@@ -2718,18 +3313,18 @@ var init_point = __esm({
|
|
|
2718
3313
|
throw new Error("point: constraint kind changed \u2014 recreate");
|
|
2719
3314
|
}
|
|
2720
3315
|
};
|
|
2721
|
-
registerKind(
|
|
3316
|
+
registerKind(def5);
|
|
2722
3317
|
}
|
|
2723
3318
|
});
|
|
2724
3319
|
|
|
2725
3320
|
// src/core/scene/kinds/segment.ts
|
|
2726
|
-
var
|
|
3321
|
+
var def6;
|
|
2727
3322
|
var init_segment = __esm({
|
|
2728
3323
|
"src/core/scene/kinds/segment.ts"() {
|
|
2729
3324
|
init_registry();
|
|
2730
3325
|
init_labelOf();
|
|
2731
3326
|
init_label();
|
|
2732
|
-
|
|
3327
|
+
def6 = {
|
|
2733
3328
|
type: "segment",
|
|
2734
3329
|
schemaVersion: 1,
|
|
2735
3330
|
migrate: {},
|
|
@@ -2765,7 +3360,7 @@ var init_segment = __esm({
|
|
|
2765
3360
|
});
|
|
2766
3361
|
}
|
|
2767
3362
|
};
|
|
2768
|
-
registerKind(
|
|
3363
|
+
registerKind(def6);
|
|
2769
3364
|
}
|
|
2770
3365
|
});
|
|
2771
3366
|
|
|
@@ -2793,14 +3388,14 @@ function constructionRefs(c) {
|
|
|
2793
3388
|
return [c.throughPoint, c.toCircle];
|
|
2794
3389
|
}
|
|
2795
3390
|
}
|
|
2796
|
-
var
|
|
3391
|
+
var def7;
|
|
2797
3392
|
var init_line = __esm({
|
|
2798
3393
|
"src/core/scene/kinds/line.ts"() {
|
|
2799
3394
|
init_registry();
|
|
2800
3395
|
init_labelOf();
|
|
2801
3396
|
init_label();
|
|
2802
3397
|
init_pointConstructions();
|
|
2803
|
-
|
|
3398
|
+
def7 = {
|
|
2804
3399
|
type: "line",
|
|
2805
3400
|
schemaVersion: 1,
|
|
2806
3401
|
migrate: {},
|
|
@@ -2996,17 +3591,17 @@ var init_line = __esm({
|
|
|
2996
3591
|
}
|
|
2997
3592
|
}
|
|
2998
3593
|
};
|
|
2999
|
-
registerKind(
|
|
3594
|
+
registerKind(def7);
|
|
3000
3595
|
}
|
|
3001
3596
|
});
|
|
3002
3597
|
|
|
3003
3598
|
// src/core/scene/kinds/ray.ts
|
|
3004
|
-
var
|
|
3599
|
+
var def8;
|
|
3005
3600
|
var init_ray = __esm({
|
|
3006
3601
|
"src/core/scene/kinds/ray.ts"() {
|
|
3007
3602
|
init_registry();
|
|
3008
3603
|
init_labelOf();
|
|
3009
|
-
|
|
3604
|
+
def8 = {
|
|
3010
3605
|
type: "ray",
|
|
3011
3606
|
schemaVersion: 1,
|
|
3012
3607
|
migrate: {},
|
|
@@ -3031,17 +3626,17 @@ var init_ray = __esm({
|
|
|
3031
3626
|
});
|
|
3032
3627
|
}
|
|
3033
3628
|
};
|
|
3034
|
-
registerKind(
|
|
3629
|
+
registerKind(def8);
|
|
3035
3630
|
}
|
|
3036
3631
|
});
|
|
3037
3632
|
|
|
3038
3633
|
// src/core/scene/kinds/vector.ts
|
|
3039
|
-
var
|
|
3634
|
+
var def9;
|
|
3040
3635
|
var init_vector = __esm({
|
|
3041
3636
|
"src/core/scene/kinds/vector.ts"() {
|
|
3042
3637
|
init_registry();
|
|
3043
3638
|
init_labelOf();
|
|
3044
|
-
|
|
3639
|
+
def9 = {
|
|
3045
3640
|
type: "vector",
|
|
3046
3641
|
schemaVersion: 1,
|
|
3047
3642
|
migrate: {},
|
|
@@ -3063,7 +3658,7 @@ var init_vector = __esm({
|
|
|
3063
3658
|
});
|
|
3064
3659
|
}
|
|
3065
3660
|
};
|
|
3066
|
-
registerKind(
|
|
3661
|
+
registerKind(def9);
|
|
3067
3662
|
}
|
|
3068
3663
|
});
|
|
3069
3664
|
|
|
@@ -3093,14 +3688,14 @@ function constructionRefs2(c) {
|
|
|
3093
3688
|
return [c.p1, c.p2];
|
|
3094
3689
|
}
|
|
3095
3690
|
}
|
|
3096
|
-
var
|
|
3691
|
+
var def10;
|
|
3097
3692
|
var init_circle = __esm({
|
|
3098
3693
|
"src/core/scene/kinds/circle.ts"() {
|
|
3099
3694
|
init_registry();
|
|
3100
3695
|
init_labelOf();
|
|
3101
3696
|
init_label();
|
|
3102
3697
|
init_pointConstructions();
|
|
3103
|
-
|
|
3698
|
+
def10 = {
|
|
3104
3699
|
type: "circle",
|
|
3105
3700
|
schemaVersion: 1,
|
|
3106
3701
|
migrate: {},
|
|
@@ -3252,7 +3847,7 @@ var init_circle = __esm({
|
|
|
3252
3847
|
return board.create("circle", [center, surface], baseOpts);
|
|
3253
3848
|
}
|
|
3254
3849
|
};
|
|
3255
|
-
registerKind(
|
|
3850
|
+
registerKind(def10);
|
|
3256
3851
|
}
|
|
3257
3852
|
});
|
|
3258
3853
|
|
|
@@ -3267,12 +3862,12 @@ function constructionRefs3(c) {
|
|
|
3267
3862
|
return [c.p1, c.p2, c.p3];
|
|
3268
3863
|
}
|
|
3269
3864
|
}
|
|
3270
|
-
var
|
|
3865
|
+
var def11;
|
|
3271
3866
|
var init_arc = __esm({
|
|
3272
3867
|
"src/core/scene/kinds/arc.ts"() {
|
|
3273
3868
|
init_registry();
|
|
3274
3869
|
init_labelOf();
|
|
3275
|
-
|
|
3870
|
+
def11 = {
|
|
3276
3871
|
type: "arc",
|
|
3277
3872
|
schemaVersion: 1,
|
|
3278
3873
|
migrate: {},
|
|
@@ -3330,17 +3925,17 @@ var init_arc = __esm({
|
|
|
3330
3925
|
return board.create("circumcirclearc", [A, B, C], baseOpts);
|
|
3331
3926
|
}
|
|
3332
3927
|
};
|
|
3333
|
-
registerKind(
|
|
3928
|
+
registerKind(def11);
|
|
3334
3929
|
}
|
|
3335
3930
|
});
|
|
3336
3931
|
|
|
3337
3932
|
// src/core/scene/kinds/sector.ts
|
|
3338
|
-
var
|
|
3933
|
+
var def12;
|
|
3339
3934
|
var init_sector = __esm({
|
|
3340
3935
|
"src/core/scene/kinds/sector.ts"() {
|
|
3341
3936
|
init_registry();
|
|
3342
3937
|
init_labelOf();
|
|
3343
|
-
|
|
3938
|
+
def12 = {
|
|
3344
3939
|
type: "sector",
|
|
3345
3940
|
schemaVersion: 1,
|
|
3346
3941
|
migrate: {},
|
|
@@ -3380,7 +3975,7 @@ var init_sector = __esm({
|
|
|
3380
3975
|
});
|
|
3381
3976
|
}
|
|
3382
3977
|
};
|
|
3383
|
-
registerKind(
|
|
3978
|
+
registerKind(def12);
|
|
3384
3979
|
}
|
|
3385
3980
|
});
|
|
3386
3981
|
|
|
@@ -3426,12 +4021,12 @@ function specialShapeName(kind) {
|
|
|
3426
4021
|
return "";
|
|
3427
4022
|
}
|
|
3428
4023
|
}
|
|
3429
|
-
var
|
|
4024
|
+
var def13;
|
|
3430
4025
|
var init_polygon = __esm({
|
|
3431
4026
|
"src/core/scene/kinds/polygon.ts"() {
|
|
3432
4027
|
init_registry();
|
|
3433
4028
|
init_labelOf();
|
|
3434
|
-
|
|
4029
|
+
def13 = {
|
|
3435
4030
|
type: "polygon",
|
|
3436
4031
|
schemaVersion: 1,
|
|
3437
4032
|
migrate: {},
|
|
@@ -3618,16 +4213,16 @@ var init_polygon = __esm({
|
|
|
3618
4213
|
return poly;
|
|
3619
4214
|
}
|
|
3620
4215
|
};
|
|
3621
|
-
registerKind(
|
|
4216
|
+
registerKind(def13);
|
|
3622
4217
|
}
|
|
3623
4218
|
});
|
|
3624
4219
|
|
|
3625
4220
|
// src/core/scene/kinds/intersection.ts
|
|
3626
|
-
var
|
|
4221
|
+
var def14;
|
|
3627
4222
|
var init_intersection = __esm({
|
|
3628
4223
|
"src/core/scene/kinds/intersection.ts"() {
|
|
3629
4224
|
init_registry();
|
|
3630
|
-
|
|
4225
|
+
def14 = {
|
|
3631
4226
|
type: "intersection",
|
|
3632
4227
|
schemaVersion: 1,
|
|
3633
4228
|
migrate: {},
|
|
@@ -3702,17 +4297,17 @@ var init_intersection = __esm({
|
|
|
3702
4297
|
}
|
|
3703
4298
|
}
|
|
3704
4299
|
};
|
|
3705
|
-
registerKind(
|
|
4300
|
+
registerKind(def14);
|
|
3706
4301
|
}
|
|
3707
4302
|
});
|
|
3708
4303
|
|
|
3709
4304
|
// src/core/scene/kinds/angle.ts
|
|
3710
|
-
var
|
|
4305
|
+
var def15;
|
|
3711
4306
|
var init_angle = __esm({
|
|
3712
4307
|
"src/core/scene/kinds/angle.ts"() {
|
|
3713
4308
|
init_registry();
|
|
3714
4309
|
init_labelOf();
|
|
3715
|
-
|
|
4310
|
+
def15 = {
|
|
3716
4311
|
type: "angle",
|
|
3717
4312
|
schemaVersion: 1,
|
|
3718
4313
|
migrate: {},
|
|
@@ -3748,17 +4343,17 @@ var init_angle = __esm({
|
|
|
3748
4343
|
});
|
|
3749
4344
|
}
|
|
3750
4345
|
};
|
|
3751
|
-
registerKind(
|
|
4346
|
+
registerKind(def15);
|
|
3752
4347
|
}
|
|
3753
4348
|
});
|
|
3754
4349
|
|
|
3755
4350
|
// src/core/scene/kinds/distance.ts
|
|
3756
|
-
var
|
|
4351
|
+
var def16;
|
|
3757
4352
|
var init_distance = __esm({
|
|
3758
4353
|
"src/core/scene/kinds/distance.ts"() {
|
|
3759
4354
|
init_registry();
|
|
3760
4355
|
init_labelOf();
|
|
3761
|
-
|
|
4356
|
+
def16 = {
|
|
3762
4357
|
type: "distance",
|
|
3763
4358
|
schemaVersion: 1,
|
|
3764
4359
|
migrate: {},
|
|
@@ -3787,17 +4382,17 @@ var init_distance = __esm({
|
|
|
3787
4382
|
});
|
|
3788
4383
|
}
|
|
3789
4384
|
};
|
|
3790
|
-
registerKind(
|
|
4385
|
+
registerKind(def16);
|
|
3791
4386
|
}
|
|
3792
4387
|
});
|
|
3793
4388
|
|
|
3794
4389
|
// src/core/scene/kinds/function2d.ts
|
|
3795
|
-
var
|
|
4390
|
+
var def17;
|
|
3796
4391
|
var init_function2d = __esm({
|
|
3797
4392
|
"src/core/scene/kinds/function2d.ts"() {
|
|
3798
4393
|
init_registry();
|
|
3799
4394
|
init_parser();
|
|
3800
|
-
|
|
4395
|
+
def17 = {
|
|
3801
4396
|
type: "function2d",
|
|
3802
4397
|
schemaVersion: 1,
|
|
3803
4398
|
migrate: {},
|
|
@@ -3836,16 +4431,16 @@ var init_function2d = __esm({
|
|
|
3836
4431
|
});
|
|
3837
4432
|
}
|
|
3838
4433
|
};
|
|
3839
|
-
registerKind(
|
|
4434
|
+
registerKind(def17);
|
|
3840
4435
|
}
|
|
3841
4436
|
});
|
|
3842
4437
|
|
|
3843
4438
|
// src/core/scene/kinds/parameter.ts
|
|
3844
|
-
var
|
|
4439
|
+
var def18;
|
|
3845
4440
|
var init_parameter = __esm({
|
|
3846
4441
|
"src/core/scene/kinds/parameter.ts"() {
|
|
3847
4442
|
init_registry();
|
|
3848
|
-
|
|
4443
|
+
def18 = {
|
|
3849
4444
|
type: "parameter",
|
|
3850
4445
|
schemaVersion: 1,
|
|
3851
4446
|
migrate: {},
|
|
@@ -3863,16 +4458,16 @@ var init_parameter = __esm({
|
|
|
3863
4458
|
render: () => null
|
|
3864
4459
|
// Không render lên board
|
|
3865
4460
|
};
|
|
3866
|
-
registerKind(
|
|
4461
|
+
registerKind(def18);
|
|
3867
4462
|
}
|
|
3868
4463
|
});
|
|
3869
4464
|
|
|
3870
4465
|
// src/core/scene/kinds/pointOnCurve.ts
|
|
3871
|
-
var
|
|
4466
|
+
var def19;
|
|
3872
4467
|
var init_pointOnCurve = __esm({
|
|
3873
4468
|
"src/core/scene/kinds/pointOnCurve.ts"() {
|
|
3874
4469
|
init_registry();
|
|
3875
|
-
|
|
4470
|
+
def19 = {
|
|
3876
4471
|
type: "pointOnCurve",
|
|
3877
4472
|
schemaVersion: 1,
|
|
3878
4473
|
migrate: {},
|
|
@@ -3899,16 +4494,16 @@ var init_pointOnCurve = __esm({
|
|
|
3899
4494
|
});
|
|
3900
4495
|
}
|
|
3901
4496
|
};
|
|
3902
|
-
registerKind(
|
|
4497
|
+
registerKind(def19);
|
|
3903
4498
|
}
|
|
3904
4499
|
});
|
|
3905
4500
|
|
|
3906
4501
|
// src/core/scene/kinds/tangent2d.ts
|
|
3907
|
-
var
|
|
4502
|
+
var def20;
|
|
3908
4503
|
var init_tangent2d = __esm({
|
|
3909
4504
|
"src/core/scene/kinds/tangent2d.ts"() {
|
|
3910
4505
|
init_registry();
|
|
3911
|
-
|
|
4506
|
+
def20 = {
|
|
3912
4507
|
type: "tangent2d",
|
|
3913
4508
|
schemaVersion: 1,
|
|
3914
4509
|
migrate: {},
|
|
@@ -3931,7 +4526,7 @@ var init_tangent2d = __esm({
|
|
|
3931
4526
|
});
|
|
3932
4527
|
}
|
|
3933
4528
|
};
|
|
3934
|
-
registerKind(
|
|
4529
|
+
registerKind(def20);
|
|
3935
4530
|
}
|
|
3936
4531
|
});
|
|
3937
4532
|
|
|
@@ -4007,13 +4602,13 @@ var init_evaluator = __esm({
|
|
|
4007
4602
|
});
|
|
4008
4603
|
|
|
4009
4604
|
// src/core/scene/kinds/extremum2d.ts
|
|
4010
|
-
var
|
|
4605
|
+
var def21;
|
|
4011
4606
|
var init_extremum2d = __esm({
|
|
4012
4607
|
"src/core/scene/kinds/extremum2d.ts"() {
|
|
4013
4608
|
init_registry();
|
|
4014
4609
|
init_evaluator();
|
|
4015
4610
|
init_parser();
|
|
4016
|
-
|
|
4611
|
+
def21 = {
|
|
4017
4612
|
type: "extremum2d",
|
|
4018
4613
|
schemaVersion: 1,
|
|
4019
4614
|
migrate: {},
|
|
@@ -4046,18 +4641,18 @@ var init_extremum2d = __esm({
|
|
|
4046
4641
|
}));
|
|
4047
4642
|
}
|
|
4048
4643
|
};
|
|
4049
|
-
registerKind(
|
|
4644
|
+
registerKind(def21);
|
|
4050
4645
|
}
|
|
4051
4646
|
});
|
|
4052
4647
|
|
|
4053
4648
|
// src/core/scene/kinds/root2d.ts
|
|
4054
|
-
var
|
|
4649
|
+
var def22;
|
|
4055
4650
|
var init_root2d = __esm({
|
|
4056
4651
|
"src/core/scene/kinds/root2d.ts"() {
|
|
4057
4652
|
init_registry();
|
|
4058
4653
|
init_evaluator();
|
|
4059
4654
|
init_parser();
|
|
4060
|
-
|
|
4655
|
+
def22 = {
|
|
4061
4656
|
type: "root2d",
|
|
4062
4657
|
schemaVersion: 1,
|
|
4063
4658
|
migrate: {},
|
|
@@ -4087,16 +4682,16 @@ var init_root2d = __esm({
|
|
|
4087
4682
|
}));
|
|
4088
4683
|
}
|
|
4089
4684
|
};
|
|
4090
|
-
registerKind(
|
|
4685
|
+
registerKind(def22);
|
|
4091
4686
|
}
|
|
4092
4687
|
});
|
|
4093
4688
|
|
|
4094
4689
|
// src/core/scene/kinds/slope2d.ts
|
|
4095
|
-
var
|
|
4690
|
+
var def23;
|
|
4096
4691
|
var init_slope2d = __esm({
|
|
4097
4692
|
"src/core/scene/kinds/slope2d.ts"() {
|
|
4098
4693
|
init_registry();
|
|
4099
|
-
|
|
4694
|
+
def23 = {
|
|
4100
4695
|
type: "slope2d",
|
|
4101
4696
|
schemaVersion: 1,
|
|
4102
4697
|
migrate: {},
|
|
@@ -4120,7 +4715,7 @@ var init_slope2d = __esm({
|
|
|
4120
4715
|
});
|
|
4121
4716
|
}
|
|
4122
4717
|
};
|
|
4123
|
-
registerKind(
|
|
4718
|
+
registerKind(def23);
|
|
4124
4719
|
}
|
|
4125
4720
|
});
|
|
4126
4721
|
|
|
@@ -5819,7 +6414,7 @@ var init_useToolHoverTooltip = __esm({
|
|
|
5819
6414
|
init_types4();
|
|
5820
6415
|
}
|
|
5821
6416
|
});
|
|
5822
|
-
function
|
|
6417
|
+
function normalize2(s) {
|
|
5823
6418
|
return s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/đ/g, "d").replace(/Đ/g, "d");
|
|
5824
6419
|
}
|
|
5825
6420
|
function SearchIcon() {
|
|
@@ -5866,12 +6461,12 @@ function ToolGrid(props) {
|
|
|
5866
6461
|
const { tools, groupOrder, groupLabels, activeTool, onToolChange, chord } = props;
|
|
5867
6462
|
const { hover, portalReady, showHover, hideHover } = useToolHoverTooltip();
|
|
5868
6463
|
const [query, setQuery] = React5.useState("");
|
|
5869
|
-
const normalizedQuery = React5.useMemo(() =>
|
|
6464
|
+
const normalizedQuery = React5.useMemo(() => normalize2(query.trim()), [query]);
|
|
5870
6465
|
const filteredTools = React5.useMemo(() => {
|
|
5871
6466
|
if (!normalizedQuery) return tools;
|
|
5872
6467
|
return tools.filter((t) => {
|
|
5873
|
-
if (
|
|
5874
|
-
if (t.hint &&
|
|
6468
|
+
if (normalize2(t.label).includes(normalizedQuery)) return true;
|
|
6469
|
+
if (t.hint && normalize2(t.hint).includes(normalizedQuery)) return true;
|
|
5875
6470
|
return false;
|
|
5876
6471
|
});
|
|
5877
6472
|
}, [tools, normalizedQuery]);
|
|
@@ -6461,9 +7056,9 @@ async function insertStampImage(api, opts) {
|
|
|
6461
7056
|
const old = elements.find((e) => e.id === editingId) ;
|
|
6462
7057
|
const oldLongest = old ? Math.max(old.width ?? 0, old.height ?? 0) : 0;
|
|
6463
7058
|
const newLongest = Math.max(width, height);
|
|
6464
|
-
const
|
|
6465
|
-
const w = width *
|
|
6466
|
-
const h = height *
|
|
7059
|
+
const scale2 = oldLongest > 0 && newLongest > 0 ? oldLongest / newLongest : 1;
|
|
7060
|
+
const w = width * scale2;
|
|
7061
|
+
const h = height * scale2;
|
|
6467
7062
|
const updated = elements.map(
|
|
6468
7063
|
(e) => e.id === editingId ? { ...e, fileId, customData, width: w, height: h } : e
|
|
6469
7064
|
);
|
|
@@ -6533,11 +7128,10 @@ var init_useIsMobile = __esm({
|
|
|
6533
7128
|
NO_HOVER_QUERY = "(hover: none)";
|
|
6534
7129
|
}
|
|
6535
7130
|
});
|
|
6536
|
-
function useStampStore(domain,
|
|
7131
|
+
function useStampStore(domain, makeInitialState) {
|
|
6537
7132
|
const ref = React5.useRef(null);
|
|
6538
7133
|
if (!ref.current) {
|
|
6539
|
-
|
|
6540
|
-
ref.current = createStore(initial);
|
|
7134
|
+
ref.current = createStore(makeInitialState?.() ?? createEmptyState(domain));
|
|
6541
7135
|
}
|
|
6542
7136
|
return ref.current;
|
|
6543
7137
|
}
|
|
@@ -6861,7 +7455,10 @@ var init_host = __esm({
|
|
|
6861
7455
|
const panelRef = React5.useRef(null);
|
|
6862
7456
|
const { isMobile } = useIsMobile();
|
|
6863
7457
|
const [drawerOpen, setDrawerOpen] = React5.useState(false);
|
|
6864
|
-
const sceneStore = useStampStore(
|
|
7458
|
+
const sceneStore = useStampStore(
|
|
7459
|
+
"graph2d",
|
|
7460
|
+
() => editingElement?.customData ? parseInitialState(editingElement.customData) : null
|
|
7461
|
+
);
|
|
6865
7462
|
const [selectedObjectId, setSelectedObjectId] = React5.useState(void 0);
|
|
6866
7463
|
const initialMeta = sceneStore.getState().meta;
|
|
6867
7464
|
const initialView = initialMeta.domain === "graph2d" ? initialMeta.view : null;
|