@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/geometry-2d.js
CHANGED
|
@@ -73,16 +73,16 @@ var init_types = __esm({
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
// src/core/scene/registry.ts
|
|
76
|
-
function registerKind(
|
|
77
|
-
if (registry.has(
|
|
78
|
-
console.warn(`[scene] kind "${
|
|
76
|
+
function registerKind(def24) {
|
|
77
|
+
if (registry.has(def24.type)) {
|
|
78
|
+
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`);
|
|
79
79
|
}
|
|
80
|
-
registry.set(
|
|
80
|
+
registry.set(def24.type, def24);
|
|
81
81
|
}
|
|
82
82
|
function getKind(type) {
|
|
83
|
-
const
|
|
84
|
-
if (!
|
|
85
|
-
return
|
|
83
|
+
const def24 = registry.get(type);
|
|
84
|
+
if (!def24) throw new Error(`[scene] unknown kind: ${type}`);
|
|
85
|
+
return def24;
|
|
86
86
|
}
|
|
87
87
|
var registry;
|
|
88
88
|
var init_registry = __esm({
|
|
@@ -168,8 +168,8 @@ function reduce(draft, action) {
|
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
170
|
case "TRANSACTION": {
|
|
171
|
-
for (const
|
|
172
|
-
reduce(draft,
|
|
171
|
+
for (const sub2 of action.payload.actions) {
|
|
172
|
+
reduce(draft, sub2);
|
|
173
173
|
}
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
@@ -382,8 +382,36 @@ function constraintRefs(c) {
|
|
|
382
382
|
return [c.polygonId];
|
|
383
383
|
case "onSphere":
|
|
384
384
|
return [c.sphereId];
|
|
385
|
-
|
|
385
|
+
case "midpoint":
|
|
386
|
+
return [c.p1, c.p2];
|
|
387
|
+
case "centroid":
|
|
388
|
+
return [...c.vertices];
|
|
389
|
+
case "intersectionLines":
|
|
390
|
+
return [c.a1, c.b1, c.a2, c.b2];
|
|
391
|
+
case "intersectionLinePlane":
|
|
392
|
+
return [c.a, c.b, c.plane];
|
|
393
|
+
case "perpFootLine":
|
|
394
|
+
return [c.from, c.a, c.b];
|
|
395
|
+
case "perpFootPlane":
|
|
396
|
+
return [c.from, c.plane];
|
|
397
|
+
case "circumsphereCenter":
|
|
398
|
+
return [...c.vertices];
|
|
399
|
+
case "pyramidInsphereCenter":
|
|
400
|
+
return [c.apex, ...c.vertices];
|
|
401
|
+
case "faceCircumcenter":
|
|
402
|
+
return [...c.vertices];
|
|
403
|
+
case "pointAboveFace":
|
|
404
|
+
return [c.base, c.apex, ...c.vertices];
|
|
405
|
+
// Kind KHÔNG có ref scene-object (toạ độ literal): liệt kê TƯỜNG MINH để
|
|
406
|
+
// exhaustive never-guard bên dưới buộc khai báo khi thêm constraint kind mới
|
|
407
|
+
// (mô phỏng constraintRefs2D — quên case = cascade-delete/deps sai âm thầm).
|
|
408
|
+
case "free":
|
|
409
|
+
case "onGround":
|
|
410
|
+
case "onAxis":
|
|
411
|
+
return [];
|
|
412
|
+
default: {
|
|
386
413
|
return [];
|
|
414
|
+
}
|
|
387
415
|
}
|
|
388
416
|
}
|
|
389
417
|
var init_d_constraint = __esm({
|
|
@@ -391,12 +419,359 @@ var init_d_constraint = __esm({
|
|
|
391
419
|
}
|
|
392
420
|
});
|
|
393
421
|
|
|
422
|
+
// src/core/scene/kinds/constraint3d-math.ts
|
|
423
|
+
function sub(a, b) {
|
|
424
|
+
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
425
|
+
}
|
|
426
|
+
function add(a, b) {
|
|
427
|
+
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
428
|
+
}
|
|
429
|
+
function scale(a, k) {
|
|
430
|
+
return [a[0] * k, a[1] * k, a[2] * k];
|
|
431
|
+
}
|
|
432
|
+
function dot(a, b) {
|
|
433
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
434
|
+
}
|
|
435
|
+
function cross(a, b) {
|
|
436
|
+
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]];
|
|
437
|
+
}
|
|
438
|
+
function norm(a) {
|
|
439
|
+
return Math.sqrt(dot(a, a));
|
|
440
|
+
}
|
|
441
|
+
function normalize(a) {
|
|
442
|
+
const n = norm(a);
|
|
443
|
+
return n === 0 ? a : scale(a, 1 / n);
|
|
444
|
+
}
|
|
445
|
+
function getPointWorld(id, state) {
|
|
446
|
+
const obj = state.objects[id];
|
|
447
|
+
if (!obj || obj.kind !== "point3d") {
|
|
448
|
+
throw new Error(`constraintMath: point ${id} not found`);
|
|
449
|
+
}
|
|
450
|
+
const attrs = obj.attrs;
|
|
451
|
+
return constraintToWorld(attrs.constraint, state);
|
|
452
|
+
}
|
|
453
|
+
function getPlaneBasis(planeObj, state) {
|
|
454
|
+
const a = planeObj.attrs;
|
|
455
|
+
let p1, p2, p3;
|
|
456
|
+
if (a.construction) {
|
|
457
|
+
const r = planeConstructionWorld(a.construction, state);
|
|
458
|
+
p1 = r.p1;
|
|
459
|
+
p2 = r.p2;
|
|
460
|
+
p3 = r.p3;
|
|
461
|
+
} else {
|
|
462
|
+
p1 = getPointWorld(a.p1, state);
|
|
463
|
+
p2 = getPointWorld(a.p2, state);
|
|
464
|
+
p3 = getPointWorld(a.p3, state);
|
|
465
|
+
}
|
|
466
|
+
const basis1 = sub(p2, p1);
|
|
467
|
+
const tmp = sub(p3, p1);
|
|
468
|
+
const normal = normalize(cross(basis1, tmp));
|
|
469
|
+
const basis2 = cross(normal, basis1);
|
|
470
|
+
return { origin: p1, basis1, basis2, normal };
|
|
471
|
+
}
|
|
472
|
+
function orthoBasisFromNormal(n) {
|
|
473
|
+
const seed = Math.abs(n[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
474
|
+
const basis1 = normalize(cross(n, seed));
|
|
475
|
+
const basis2 = cross(n, basis1);
|
|
476
|
+
return { basis1, basis2 };
|
|
477
|
+
}
|
|
478
|
+
function planeConstructionWorld(c, state) {
|
|
479
|
+
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?");
|
|
480
|
+
_recDepth++;
|
|
481
|
+
try {
|
|
482
|
+
return planeConstructionWorldInner(c, state);
|
|
483
|
+
} finally {
|
|
484
|
+
_recDepth--;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function planeConstructionWorldInner(c, state) {
|
|
488
|
+
switch (c.kind) {
|
|
489
|
+
case "planeParallelThrough": {
|
|
490
|
+
const P = getPointWorld(c.point, state);
|
|
491
|
+
const ref = state.objects[c.refPlane];
|
|
492
|
+
if (!ref || ref.kind !== "plane3d") throw new Error("planeParallelThrough: m\u1EB7t tham chi\u1EBFu thi\u1EBFu");
|
|
493
|
+
const { basis1, basis2 } = getPlaneBasis(ref, state);
|
|
494
|
+
if (norm(basis1) < 1e-12 || norm(basis2) < 1e-12) {
|
|
495
|
+
return { p1: P, p2: add(P, [1, 0, 0]), p3: add(P, [0, 1, 0]) };
|
|
496
|
+
}
|
|
497
|
+
return { p1: P, p2: add(P, basis1), p3: add(P, basis2) };
|
|
498
|
+
}
|
|
499
|
+
case "planePerpToLine": {
|
|
500
|
+
const P = getPointWorld(c.point, state);
|
|
501
|
+
const dir = sub(getPointWorld(c.lineB, state), getPointWorld(c.lineA, state));
|
|
502
|
+
const dn = norm(dir);
|
|
503
|
+
if (dn < 1e-12) return { p1: P, p2: add(P, [1, 0, 0]), p3: add(P, [0, 1, 0]) };
|
|
504
|
+
const { basis1, basis2 } = orthoBasisFromNormal(scale(dir, 1 / dn));
|
|
505
|
+
return { p1: P, p2: add(P, basis1), p3: add(P, basis2) };
|
|
506
|
+
}
|
|
507
|
+
default: {
|
|
508
|
+
throw new Error("planeConstructionWorld: kind kh\xF4ng h\u1ED7 tr\u1EE3");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function lineDefiningPointIds(line) {
|
|
513
|
+
if (line.kind === "line3d" || line.kind === "segment3d") {
|
|
514
|
+
const a = line.attrs;
|
|
515
|
+
return a.p1 && a.p2 ? [a.p1, a.p2] : null;
|
|
516
|
+
}
|
|
517
|
+
if (line.kind === "ray3d") {
|
|
518
|
+
const a = line.attrs;
|
|
519
|
+
return [a.origin, a.through];
|
|
520
|
+
}
|
|
521
|
+
if (line.kind === "vector3d") {
|
|
522
|
+
const a = line.attrs;
|
|
523
|
+
return [a.from, a.to];
|
|
524
|
+
}
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
function lineEndpointsWorld(lineId, state, ctx) {
|
|
528
|
+
const line = state.objects[lineId];
|
|
529
|
+
if (!line) throw new Error(`${ctx}: \u0111\u01B0\u1EDDng ${lineId} kh\xF4ng t\u1ED3n t\u1EA1i`);
|
|
530
|
+
const ids = lineDefiningPointIds(line);
|
|
531
|
+
if (!ids) throw new Error(`${ctx}: kind ${line.kind} kh\xF4ng ph\u1EA3i \u0111\u01B0\u1EDDng`);
|
|
532
|
+
return { a: getPointWorld(ids[0], state), b: getPointWorld(ids[1], state) };
|
|
533
|
+
}
|
|
534
|
+
function lineLineClosestMidpoint(A, B, C, D) {
|
|
535
|
+
const u = sub(B, A), v = sub(D, C), w0 = sub(A, C);
|
|
536
|
+
const a = dot(u, u), b = dot(u, v), cc = dot(v, v), d = dot(u, w0), e = dot(v, w0);
|
|
537
|
+
const denom = a * cc - b * b;
|
|
538
|
+
if (Math.abs(denom) < 1e-12) return scale(add(A, C), 0.5);
|
|
539
|
+
const sc = (b * e - cc * d) / denom;
|
|
540
|
+
const tc = (a * e - b * d) / denom;
|
|
541
|
+
return scale(add(add(A, scale(u, sc)), add(C, scale(v, tc))), 0.5);
|
|
542
|
+
}
|
|
543
|
+
function planeOriginNormal(planeId, state, ctx) {
|
|
544
|
+
const plane = state.objects[planeId];
|
|
545
|
+
if (!plane || plane.kind !== "plane3d") throw new Error(`${ctx}: m\u1EB7t ph\u1EB3ng ${planeId} thi\u1EBFu`);
|
|
546
|
+
const { origin, normal } = getPlaneBasis(plane, state);
|
|
547
|
+
return { origin, normal };
|
|
548
|
+
}
|
|
549
|
+
function lineConstructionWorld(c, state) {
|
|
550
|
+
switch (c.kind) {
|
|
551
|
+
case "planePlaneIntersection": {
|
|
552
|
+
const P1 = planeOriginNormal(c.plane1, state, "planePlaneIntersection");
|
|
553
|
+
const P2 = planeOriginNormal(c.plane2, state, "planePlaneIntersection");
|
|
554
|
+
const d = cross(P1.normal, P2.normal);
|
|
555
|
+
const dd = dot(d, d);
|
|
556
|
+
if (dd < 1e-12) {
|
|
557
|
+
return { a: P1.origin, b: add(P1.origin, P2.normal) };
|
|
558
|
+
}
|
|
559
|
+
const c1 = dot(P1.normal, P1.origin);
|
|
560
|
+
const c2 = dot(P2.normal, P2.origin);
|
|
561
|
+
const p0 = scale(add(scale(cross(P2.normal, d), c1), scale(cross(d, P1.normal), c2)), 1 / dd);
|
|
562
|
+
return { a: p0, b: add(p0, d) };
|
|
563
|
+
}
|
|
564
|
+
case "lineParallelThrough": {
|
|
565
|
+
const P = getPointWorld(c.point, state);
|
|
566
|
+
const dir = sub(getPointWorld(c.dirB, state), getPointWorld(c.dirA, state));
|
|
567
|
+
if (norm(dir) < 1e-12) return { a: P, b: add(P, [1, 0, 0]) };
|
|
568
|
+
return { a: P, b: add(P, dir) };
|
|
569
|
+
}
|
|
570
|
+
case "linePerpToPlane": {
|
|
571
|
+
const P = getPointWorld(c.point, state);
|
|
572
|
+
const { normal } = planeOriginNormal(c.plane, state, "linePerpToPlane");
|
|
573
|
+
return { a: P, b: add(P, normal) };
|
|
574
|
+
}
|
|
575
|
+
default: {
|
|
576
|
+
throw new Error("lineConstructionWorld: kind kh\xF4ng h\u1ED7 tr\u1EE3");
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
function solve3(M, b) {
|
|
581
|
+
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]);
|
|
582
|
+
const det = det3(M);
|
|
583
|
+
if (Math.abs(det) < 1e-9) return null;
|
|
584
|
+
const colDet = (j) => {
|
|
585
|
+
const A = M.map((r) => r.slice());
|
|
586
|
+
for (let i = 0; i < 3; i++) A[i][j] = b[i];
|
|
587
|
+
return det3(A);
|
|
588
|
+
};
|
|
589
|
+
return [colDet(0) / det, colDet(1) / det, colDet(2) / det];
|
|
590
|
+
}
|
|
591
|
+
function constraintToWorld(c, state) {
|
|
592
|
+
if (_recDepth >= MAX_REC_DEPTH) throw new Error("constraintToWorld: \u0111\u1EC7 quy qu\xE1 s\xE2u \u2014 chu tr\xECnh tham chi\u1EBFu?");
|
|
593
|
+
_recDepth++;
|
|
594
|
+
try {
|
|
595
|
+
return constraintToWorldInner(c, state);
|
|
596
|
+
} finally {
|
|
597
|
+
_recDepth--;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function constraintToWorldInner(c, state) {
|
|
601
|
+
switch (c.kind) {
|
|
602
|
+
case "free":
|
|
603
|
+
return [c.x, c.y, c.z];
|
|
604
|
+
case "onGround":
|
|
605
|
+
return [c.x, c.y, 0];
|
|
606
|
+
case "onAxis": {
|
|
607
|
+
if (c.axis === "x") return [c.t, 0, 0];
|
|
608
|
+
if (c.axis === "y") return [0, c.t, 0];
|
|
609
|
+
return [0, 0, c.t];
|
|
610
|
+
}
|
|
611
|
+
case "onPlane": {
|
|
612
|
+
const plane = state.objects[c.planeId];
|
|
613
|
+
if (!plane || plane.kind !== "plane3d") throw new Error("onPlane: plane missing");
|
|
614
|
+
const { origin, basis1, basis2 } = getPlaneBasis(plane, state);
|
|
615
|
+
return add(add(origin, scale(basis1, c.u)), scale(basis2, c.v));
|
|
616
|
+
}
|
|
617
|
+
case "onLine": {
|
|
618
|
+
const { a, b } = lineEndpointsWorld(c.lineId, state, "onLine");
|
|
619
|
+
return add(a, scale(sub(b, a), c.t));
|
|
620
|
+
}
|
|
621
|
+
case "onPolygon": {
|
|
622
|
+
const pg = state.objects[c.polygonId];
|
|
623
|
+
if (!pg || pg.kind !== "polygon3d") throw new Error("onPolygon: parent missing");
|
|
624
|
+
const v = pg.attrs.vertices;
|
|
625
|
+
if (v.length < 3) throw new Error("onPolygon: < 3 vertices");
|
|
626
|
+
const p1 = getPointWorld(v[0], state);
|
|
627
|
+
const p2 = getPointWorld(v[1], state);
|
|
628
|
+
const p3 = getPointWorld(v[2], state);
|
|
629
|
+
const basis1 = sub(p2, p1);
|
|
630
|
+
const tmp = sub(p3, p1);
|
|
631
|
+
const normal = normalize(cross(basis1, tmp));
|
|
632
|
+
const basis2 = cross(normal, basis1);
|
|
633
|
+
return add(add(p1, scale(basis1, c.u)), scale(basis2, c.v));
|
|
634
|
+
}
|
|
635
|
+
case "onSphere": {
|
|
636
|
+
const sph = state.objects[c.sphereId];
|
|
637
|
+
if (!sph || sph.kind !== "sphere3d") throw new Error("onSphere: parent missing");
|
|
638
|
+
const a = sph.attrs;
|
|
639
|
+
const center = getPointWorld(a.center, state);
|
|
640
|
+
const surface = getPointWorld(a.surfacePoint, state);
|
|
641
|
+
const radius = norm(sub(surface, center));
|
|
642
|
+
const x = center[0] + radius * Math.sin(c.phi) * Math.cos(c.theta);
|
|
643
|
+
const y = center[1] + radius * Math.sin(c.phi) * Math.sin(c.theta);
|
|
644
|
+
const z = center[2] + radius * Math.cos(c.phi);
|
|
645
|
+
return [x, y, z];
|
|
646
|
+
}
|
|
647
|
+
// ───── Điểm phái sinh (v1) ─────
|
|
648
|
+
case "midpoint": {
|
|
649
|
+
const p1 = getPointWorld(c.p1, state);
|
|
650
|
+
const p2 = getPointWorld(c.p2, state);
|
|
651
|
+
return scale(add(p1, p2), 0.5);
|
|
652
|
+
}
|
|
653
|
+
case "centroid": {
|
|
654
|
+
const n = c.vertices.length;
|
|
655
|
+
if (n === 0) return [0, 0, 0];
|
|
656
|
+
let acc = [0, 0, 0];
|
|
657
|
+
for (const id of c.vertices) acc = add(acc, getPointWorld(id, state));
|
|
658
|
+
return scale(acc, 1 / n);
|
|
659
|
+
}
|
|
660
|
+
case "circumsphereCenter": {
|
|
661
|
+
const P = c.vertices.map((id) => getPointWorld(id, state));
|
|
662
|
+
if (P.length < 4) return P.length ? P[0] : [0, 0, 0];
|
|
663
|
+
const p0 = P[0];
|
|
664
|
+
const M = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
|
|
665
|
+
const rhs = [0, 0, 0];
|
|
666
|
+
for (let i = 1; i < P.length; i++) {
|
|
667
|
+
const r = [2 * (P[i][0] - p0[0]), 2 * (P[i][1] - p0[1]), 2 * (P[i][2] - p0[2])];
|
|
668
|
+
const bi = dot(P[i], P[i]) - dot(p0, p0);
|
|
669
|
+
for (let a = 0; a < 3; a++) {
|
|
670
|
+
for (let bcol = 0; bcol < 3; bcol++) M[a][bcol] += r[a] * r[bcol];
|
|
671
|
+
rhs[a] += r[a] * bi;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
const sol = solve3(M, rhs);
|
|
675
|
+
if (sol) return sol;
|
|
676
|
+
let acc = [0, 0, 0];
|
|
677
|
+
for (const p of P) acc = add(acc, p);
|
|
678
|
+
return scale(acc, 1 / P.length);
|
|
679
|
+
}
|
|
680
|
+
case "pyramidInsphereCenter": {
|
|
681
|
+
const S = getPointWorld(c.apex, state);
|
|
682
|
+
const base = c.vertices.map((id) => getPointWorld(id, state));
|
|
683
|
+
const n = base.length;
|
|
684
|
+
if (n < 3) return S;
|
|
685
|
+
let G = [0, 0, 0];
|
|
686
|
+
for (const p of base) G = add(G, p);
|
|
687
|
+
G = scale(G, 1 / n);
|
|
688
|
+
let nb = normalize(cross(sub(base[1], base[0]), sub(base[2], base[0])));
|
|
689
|
+
if (dot(nb, sub(S, G)) < 0) nb = scale(nb, -1);
|
|
690
|
+
let m = normalize(cross(sub(base[0], S), sub(base[1], S)));
|
|
691
|
+
if (dot(m, sub(G, base[0])) < 0) m = scale(m, -1);
|
|
692
|
+
const denom = 1 - dot(m, nb);
|
|
693
|
+
const s = Math.abs(denom) < 1e-9 ? NaN : dot(m, sub(G, base[0])) / denom;
|
|
694
|
+
if (!Number.isFinite(s) || s <= 0) {
|
|
695
|
+
return scale(add(S, scale(G, n)), 1 / (n + 1));
|
|
696
|
+
}
|
|
697
|
+
return add(G, scale(nb, s));
|
|
698
|
+
}
|
|
699
|
+
case "faceCircumcenter": {
|
|
700
|
+
const P = c.vertices.map((id) => getPointWorld(id, state));
|
|
701
|
+
if (P.length < 3) return P.length ? P[0] : [0, 0, 0];
|
|
702
|
+
const [p0, p1, p2] = P;
|
|
703
|
+
const e1 = sub(p1, p0), e2 = sub(p2, p0);
|
|
704
|
+
const nrm = cross(e1, e2);
|
|
705
|
+
const M = [
|
|
706
|
+
[2 * e1[0], 2 * e1[1], 2 * e1[2]],
|
|
707
|
+
[2 * e2[0], 2 * e2[1], 2 * e2[2]],
|
|
708
|
+
[nrm[0], nrm[1], nrm[2]]
|
|
709
|
+
];
|
|
710
|
+
const rhs = [dot(p1, p1) - dot(p0, p0), dot(p2, p2) - dot(p0, p0), dot(nrm, p0)];
|
|
711
|
+
const sol = solve3(M, rhs);
|
|
712
|
+
if (sol) return sol;
|
|
713
|
+
return scale(add(add(p0, p1), p2), 1 / 3);
|
|
714
|
+
}
|
|
715
|
+
case "pointAboveFace": {
|
|
716
|
+
const G = getPointWorld(c.base, state);
|
|
717
|
+
const P = c.vertices.map((id) => getPointWorld(id, state));
|
|
718
|
+
if (P.length < 3) return G;
|
|
719
|
+
let n = normalize(cross(sub(P[1], P[0]), sub(P[2], P[0])));
|
|
720
|
+
const S = getPointWorld(c.apex, state);
|
|
721
|
+
if (dot(n, sub(S, P[0])) < 0) n = scale(n, -1);
|
|
722
|
+
const h = dot(sub(S, P[0]), n);
|
|
723
|
+
if (!Number.isFinite(h) || h <= 1e-9) return G;
|
|
724
|
+
return add(G, scale(n, h));
|
|
725
|
+
}
|
|
726
|
+
case "intersectionLines": {
|
|
727
|
+
const A = getPointWorld(c.a1, state), B = getPointWorld(c.b1, state);
|
|
728
|
+
const C = getPointWorld(c.a2, state), D = getPointWorld(c.b2, state);
|
|
729
|
+
return lineLineClosestMidpoint(A, B, C, D);
|
|
730
|
+
}
|
|
731
|
+
case "intersectionLinePlane": {
|
|
732
|
+
const A = getPointWorld(c.a, state), B = getPointWorld(c.b, state);
|
|
733
|
+
const plane = state.objects[c.plane];
|
|
734
|
+
if (!plane || plane.kind !== "plane3d") throw new Error("intersectionLinePlane: m\u1EB7t ph\u1EB3ng thi\u1EBFu");
|
|
735
|
+
const { origin, normal } = getPlaneBasis(plane, state);
|
|
736
|
+
const dir = sub(B, A);
|
|
737
|
+
const dn = dot(dir, normal);
|
|
738
|
+
if (Math.abs(dn) < 1e-12) return A;
|
|
739
|
+
const t = dot(sub(origin, A), normal) / dn;
|
|
740
|
+
return add(A, scale(dir, t));
|
|
741
|
+
}
|
|
742
|
+
case "perpFootLine": {
|
|
743
|
+
const P = getPointWorld(c.from, state);
|
|
744
|
+
const A = getPointWorld(c.a, state), B = getPointWorld(c.b, state);
|
|
745
|
+
const u = sub(B, A);
|
|
746
|
+
const uu = dot(u, u);
|
|
747
|
+
const t = uu === 0 ? 0 : dot(sub(P, A), u) / uu;
|
|
748
|
+
return add(A, scale(u, t));
|
|
749
|
+
}
|
|
750
|
+
case "perpFootPlane": {
|
|
751
|
+
const P = getPointWorld(c.from, state);
|
|
752
|
+
const plane = state.objects[c.plane];
|
|
753
|
+
if (!plane || plane.kind !== "plane3d") throw new Error("perpFootPlane: m\u1EB7t ph\u1EB3ng thi\u1EBFu");
|
|
754
|
+
const { origin, normal } = getPlaneBasis(plane, state);
|
|
755
|
+
const dist2 = dot(sub(P, origin), normal);
|
|
756
|
+
return sub(P, scale(normal, dist2));
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
var MAX_REC_DEPTH, _recDepth;
|
|
761
|
+
var init_constraint3d_math = __esm({
|
|
762
|
+
"src/core/scene/kinds/constraint3d-math.ts"() {
|
|
763
|
+
MAX_REC_DEPTH = 512;
|
|
764
|
+
_recDepth = 0;
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
|
|
394
768
|
// src/core/scene/kinds/point3d.ts
|
|
395
769
|
var def;
|
|
396
770
|
var init_point3d = __esm({
|
|
397
771
|
"src/core/scene/kinds/point3d.ts"() {
|
|
398
772
|
init_registry();
|
|
399
773
|
init_d_constraint();
|
|
774
|
+
init_constraint3d_math();
|
|
400
775
|
def = {
|
|
401
776
|
type: "point3d",
|
|
402
777
|
schemaVersion: 1,
|
|
@@ -434,6 +809,15 @@ var init_point3d = __esm({
|
|
|
434
809
|
if (c.kind === "onLine") return `${obj.label} tr\xEAn \u0111\u01B0\u1EDDng ${c.lineId}`;
|
|
435
810
|
if (c.kind === "onPolygon") return `${obj.label} tr\xEAn \u0111a gi\xE1c ${c.polygonId}`;
|
|
436
811
|
if (c.kind === "onSphere") return `${obj.label} tr\xEAn m\u1EB7t c\u1EA7u ${c.sphereId}`;
|
|
812
|
+
if (c.kind === "midpoint") return `${obj.label} = trung \u0111i\u1EC3m ${c.p1}${c.p2}`;
|
|
813
|
+
if (c.kind === "centroid") return `${obj.label} = tr\u1ECDng t\xE2m ${c.vertices.join("")}`;
|
|
814
|
+
if (c.kind === "intersectionLines") return `${obj.label} = giao 2 \u0111\u01B0\u1EDDng (${c.a1}${c.b1}, ${c.a2}${c.b2})`;
|
|
815
|
+
if (c.kind === "intersectionLinePlane") return `${obj.label} = giao ${c.a}${c.b} \u2229 ${c.plane}`;
|
|
816
|
+
if (c.kind === "perpFootLine") return `${obj.label} = ch\xE2n \u22A5 t\u1EEB ${c.from} xu\u1ED1ng ${c.a}${c.b}`;
|
|
817
|
+
if (c.kind === "perpFootPlane") return `${obj.label} = ch\xE2n \u22A5 t\u1EEB ${c.from} xu\u1ED1ng ${c.plane}`;
|
|
818
|
+
if (c.kind === "pyramidInsphereCenter") return `${obj.label} = t\xE2m c\u1EA7u n\u1ED9i ti\u1EBFp ch\xF3p ${c.apex}.${c.vertices.join("")}`;
|
|
819
|
+
if (c.kind === "faceCircumcenter") return `${obj.label} = t\xE2m ngo\u1EA1i ti\u1EBFp ${c.vertices.join("")}`;
|
|
820
|
+
if (c.kind === "pointAboveFace") return `${obj.label} = \u0111\u1EC9nh tr\u1EE5c tr\u1EE5 \u22A5 m\u1EB7t ${c.vertices.join("")}`;
|
|
437
821
|
return obj.label;
|
|
438
822
|
},
|
|
439
823
|
render: (obj, ctx) => {
|
|
@@ -483,6 +867,15 @@ var init_point3d = __esm({
|
|
|
483
867
|
() => sph.F(c.theta, c.phi)[2]
|
|
484
868
|
], opts);
|
|
485
869
|
}
|
|
870
|
+
const getState = ctx.getState;
|
|
871
|
+
if (getState) {
|
|
872
|
+
const cw = () => constraintToWorld(c, getState());
|
|
873
|
+
return view.create("point3d", [
|
|
874
|
+
() => cw()[0],
|
|
875
|
+
() => cw()[1],
|
|
876
|
+
() => cw()[2]
|
|
877
|
+
], { ...opts, needsRegularUpdate: true });
|
|
878
|
+
}
|
|
486
879
|
return view.create("point3d", [0, 0, 0], opts);
|
|
487
880
|
}
|
|
488
881
|
};
|
|
@@ -544,32 +937,77 @@ var init_segment3d = __esm({
|
|
|
544
937
|
});
|
|
545
938
|
|
|
546
939
|
// src/core/scene/kinds/line3d.ts
|
|
940
|
+
function line3dConstructionRefs(c) {
|
|
941
|
+
switch (c.kind) {
|
|
942
|
+
case "planePlaneIntersection":
|
|
943
|
+
return [c.plane1, c.plane2];
|
|
944
|
+
case "lineParallelThrough":
|
|
945
|
+
return [c.point, c.dirA, c.dirB];
|
|
946
|
+
case "linePerpToPlane":
|
|
947
|
+
return [c.point, c.plane];
|
|
948
|
+
default: {
|
|
949
|
+
return [];
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
var def3;
|
|
547
954
|
var init_line3d = __esm({
|
|
548
955
|
"src/core/scene/kinds/line3d.ts"() {
|
|
549
956
|
init_registry();
|
|
550
957
|
init_labelOf();
|
|
551
|
-
|
|
958
|
+
init_constraint3d_math();
|
|
959
|
+
def3 = {
|
|
552
960
|
type: "line3d",
|
|
553
961
|
schemaVersion: 1,
|
|
554
962
|
migrate: {},
|
|
555
963
|
validate: (a) => {
|
|
556
|
-
if (
|
|
964
|
+
if (a?.construction) return;
|
|
965
|
+
if (!a?.p1 || !a?.p2) throw new Error("line3d: p1/p2 required (ho\u1EB7c construction)");
|
|
966
|
+
},
|
|
967
|
+
dependsOn: (a) => a.construction ? line3dConstructionRefs(a.construction) : [a.p1, a.p2],
|
|
968
|
+
describe: (obj, state) => {
|
|
969
|
+
const c = obj.attrs.construction;
|
|
970
|
+
if (!c) return `\u0110\u01B0\u1EDDng ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}`;
|
|
971
|
+
switch (c.kind) {
|
|
972
|
+
case "planePlaneIntersection":
|
|
973
|
+
return `Giao tuy\u1EBFn ${obj.label} = ${labelOf(c.plane1, state)} \u2229 ${labelOf(c.plane2, state)}`;
|
|
974
|
+
case "lineParallelThrough":
|
|
975
|
+
return `${obj.label} \u2225 ${labelOf(c.dirA, state)}${labelOf(c.dirB, state)} qua ${labelOf(c.point, state)}`;
|
|
976
|
+
case "linePerpToPlane":
|
|
977
|
+
return `${obj.label} \u22A5 ${labelOf(c.plane, state)} qua ${labelOf(c.point, state)}`;
|
|
978
|
+
default:
|
|
979
|
+
return obj.label;
|
|
980
|
+
}
|
|
557
981
|
},
|
|
558
|
-
dependsOn: (a) => [a.p1, a.p2],
|
|
559
|
-
describe: (obj, state) => `\u0110\u01B0\u1EDDng ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}`,
|
|
560
982
|
render: (obj, ctx) => {
|
|
561
983
|
const view = ctx.jxg;
|
|
984
|
+
const baseOpts = {
|
|
985
|
+
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
986
|
+
strokeWidth: 2,
|
|
987
|
+
visible: obj.visible
|
|
988
|
+
};
|
|
989
|
+
const c = obj.attrs.construction;
|
|
990
|
+
if (c) {
|
|
991
|
+
const getState = ctx.getState;
|
|
992
|
+
if (!getState) throw new Error("line3d construction: c\u1EA7n ctx.getState");
|
|
993
|
+
const lc = () => lineConstructionWorld(c, getState());
|
|
994
|
+
return view.create("line3d", [() => lc().a, () => lc().b], {
|
|
995
|
+
...baseOpts,
|
|
996
|
+
straightFirst: true,
|
|
997
|
+
straightLast: true,
|
|
998
|
+
needsRegularUpdate: true
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
562
1001
|
const pA = ctx.resolveRef(obj.attrs.p1);
|
|
563
1002
|
const pB = ctx.resolveRef(obj.attrs.p2);
|
|
564
1003
|
return view.create("line3d", [pA, pB], {
|
|
1004
|
+
...baseOpts,
|
|
565
1005
|
straightFirst: true,
|
|
566
|
-
straightLast: true
|
|
567
|
-
strokeColor: obj.attrs.color ?? "#0f172a",
|
|
568
|
-
strokeWidth: 2,
|
|
569
|
-
visible: obj.visible
|
|
1006
|
+
straightLast: true
|
|
570
1007
|
});
|
|
571
1008
|
}
|
|
572
|
-
}
|
|
1009
|
+
};
|
|
1010
|
+
registerKind(def3);
|
|
573
1011
|
}
|
|
574
1012
|
});
|
|
575
1013
|
|
|
@@ -635,33 +1073,77 @@ var init_vector3d = __esm({
|
|
|
635
1073
|
});
|
|
636
1074
|
|
|
637
1075
|
// src/core/scene/kinds/plane3d.ts
|
|
1076
|
+
function plane3dConstructionRefs(c) {
|
|
1077
|
+
switch (c.kind) {
|
|
1078
|
+
case "planeParallelThrough":
|
|
1079
|
+
return [c.point, c.refPlane];
|
|
1080
|
+
case "planePerpToLine":
|
|
1081
|
+
return [c.point, c.lineA, c.lineB];
|
|
1082
|
+
default: {
|
|
1083
|
+
return [];
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
var def4;
|
|
638
1088
|
var init_plane3d = __esm({
|
|
639
1089
|
"src/core/scene/kinds/plane3d.ts"() {
|
|
640
1090
|
init_registry();
|
|
641
1091
|
init_labelOf();
|
|
642
|
-
|
|
1092
|
+
init_constraint3d_math();
|
|
1093
|
+
def4 = {
|
|
643
1094
|
type: "plane3d",
|
|
644
1095
|
schemaVersion: 1,
|
|
645
1096
|
migrate: {},
|
|
646
1097
|
validate: (a) => {
|
|
647
|
-
if (
|
|
1098
|
+
if (a?.construction) return;
|
|
1099
|
+
if (!a?.p1 || !a?.p2 || !a?.p3) throw new Error("plane3d: c\u1EA7n 3 \u0111i\u1EC3m (ho\u1EB7c construction)");
|
|
1100
|
+
},
|
|
1101
|
+
dependsOn: (a) => a.construction ? plane3dConstructionRefs(a.construction) : [a.p1, a.p2, a.p3],
|
|
1102
|
+
describe: (obj, state) => {
|
|
1103
|
+
const c = obj.attrs.construction;
|
|
1104
|
+
if (!c) {
|
|
1105
|
+
return `M\u1EB7t ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}, ${labelOf(obj.attrs.p3, state)}`;
|
|
1106
|
+
}
|
|
1107
|
+
switch (c.kind) {
|
|
1108
|
+
case "planeParallelThrough":
|
|
1109
|
+
return `${obj.label} \u2225 ${labelOf(c.refPlane, state)} qua ${labelOf(c.point, state)}`;
|
|
1110
|
+
case "planePerpToLine":
|
|
1111
|
+
return `${obj.label} \u22A5 ${labelOf(c.lineA, state)}${labelOf(c.lineB, state)} qua ${labelOf(c.point, state)}`;
|
|
1112
|
+
default:
|
|
1113
|
+
return obj.label;
|
|
1114
|
+
}
|
|
648
1115
|
},
|
|
649
|
-
dependsOn: (a) => [a.p1, a.p2, a.p3],
|
|
650
|
-
describe: (obj, state) => `M\u1EB7t ${obj.label} qua ${labelOf(obj.attrs.p1, state)}, ${labelOf(obj.attrs.p2, state)}, ${labelOf(obj.attrs.p3, state)}`,
|
|
651
1116
|
render: (obj, ctx) => {
|
|
652
1117
|
const view = ctx.jxg;
|
|
653
|
-
|
|
654
|
-
ctx.resolveRef(obj.attrs.p1),
|
|
655
|
-
ctx.resolveRef(obj.attrs.p2),
|
|
656
|
-
ctx.resolveRef(obj.attrs.p3)
|
|
657
|
-
], {
|
|
1118
|
+
const opts = {
|
|
658
1119
|
fillOpacity: 0.15,
|
|
659
1120
|
fillColor: obj.attrs.color ?? "#60a5fa",
|
|
660
1121
|
strokeColor: obj.attrs.color ?? "#60a5fa",
|
|
661
1122
|
visible: obj.visible
|
|
662
|
-
}
|
|
1123
|
+
};
|
|
1124
|
+
const c = obj.attrs.construction;
|
|
1125
|
+
if (c) {
|
|
1126
|
+
const getState = ctx.getState;
|
|
1127
|
+
if (!getState) throw new Error("plane3d construction: c\u1EA7n ctx.getState");
|
|
1128
|
+
const pc = () => planeConstructionWorld(c, getState());
|
|
1129
|
+
const diff = (which) => {
|
|
1130
|
+
const r = pc();
|
|
1131
|
+
const q = r[which];
|
|
1132
|
+
return [q[0] - r.p1[0], q[1] - r.p1[1], q[2] - r.p1[2]];
|
|
1133
|
+
};
|
|
1134
|
+
return view.create("plane3d", [() => pc().p1, () => diff("p2"), () => diff("p3")], {
|
|
1135
|
+
...opts,
|
|
1136
|
+
needsRegularUpdate: true
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
return view.create("plane3d", [
|
|
1140
|
+
ctx.resolveRef(obj.attrs.p1),
|
|
1141
|
+
ctx.resolveRef(obj.attrs.p2),
|
|
1142
|
+
ctx.resolveRef(obj.attrs.p3)
|
|
1143
|
+
], opts);
|
|
663
1144
|
}
|
|
664
|
-
}
|
|
1145
|
+
};
|
|
1146
|
+
registerKind(def4);
|
|
665
1147
|
}
|
|
666
1148
|
});
|
|
667
1149
|
|
|
@@ -760,11 +1242,37 @@ var init_polyhedron3d = __esm({
|
|
|
760
1242
|
}
|
|
761
1243
|
});
|
|
762
1244
|
|
|
1245
|
+
// src/core/scene/kinds/_ringBasis.ts
|
|
1246
|
+
function perpBasis(axis) {
|
|
1247
|
+
const n = Math.hypot(axis[0], axis[1], axis[2]);
|
|
1248
|
+
if (n < 1e-12) return [[1, 0, 0], [0, 1, 0]];
|
|
1249
|
+
const a = [axis[0] / n, axis[1] / n, axis[2] / n];
|
|
1250
|
+
const seed = Math.abs(a[2]) < 0.9 ? [0, 0, 1] : [1, 0, 0];
|
|
1251
|
+
let u = [
|
|
1252
|
+
seed[1] * a[2] - seed[2] * a[1],
|
|
1253
|
+
seed[2] * a[0] - seed[0] * a[2],
|
|
1254
|
+
seed[0] * a[1] - seed[1] * a[0]
|
|
1255
|
+
];
|
|
1256
|
+
const un = Math.hypot(u[0], u[1], u[2]) || 1;
|
|
1257
|
+
u = [u[0] / un, u[1] / un, u[2] / un];
|
|
1258
|
+
const v = [
|
|
1259
|
+
a[1] * u[2] - a[2] * u[1],
|
|
1260
|
+
a[2] * u[0] - a[0] * u[2],
|
|
1261
|
+
a[0] * u[1] - a[1] * u[0]
|
|
1262
|
+
];
|
|
1263
|
+
return [u, v];
|
|
1264
|
+
}
|
|
1265
|
+
var init_ringBasis = __esm({
|
|
1266
|
+
"src/core/scene/kinds/_ringBasis.ts"() {
|
|
1267
|
+
}
|
|
1268
|
+
});
|
|
1269
|
+
|
|
763
1270
|
// src/core/scene/kinds/cylinder3d.ts
|
|
764
1271
|
var CURVED_SEGMENTS;
|
|
765
1272
|
var init_cylinder3d = __esm({
|
|
766
1273
|
"src/core/scene/kinds/cylinder3d.ts"() {
|
|
767
1274
|
init_registry();
|
|
1275
|
+
init_ringBasis();
|
|
768
1276
|
CURVED_SEGMENTS = 16;
|
|
769
1277
|
registerKind({
|
|
770
1278
|
type: "cylinder3d",
|
|
@@ -783,14 +1291,17 @@ var init_cylinder3d = __esm({
|
|
|
783
1291
|
const r = obj.attrs.radius;
|
|
784
1292
|
const ax = a.X?.() ?? 0, ay = a.Y?.() ?? 0, az = a.Z?.() ?? 0;
|
|
785
1293
|
const bx = b.X?.() ?? 0, by = b.Y?.() ?? 0, bz = b.Z?.() ?? 0;
|
|
1294
|
+
const [u, v] = perpBasis([bx - ax, by - ay, bz - az]);
|
|
786
1295
|
const baseRing = [];
|
|
787
1296
|
const topRing = [];
|
|
788
1297
|
for (let i = 0; i < CURVED_SEGMENTS; i++) {
|
|
789
1298
|
const theta = i / CURVED_SEGMENTS * Math.PI * 2;
|
|
790
|
-
const
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
1299
|
+
const c = Math.cos(theta), s = Math.sin(theta);
|
|
1300
|
+
const ox = r * (c * u[0] + s * v[0]);
|
|
1301
|
+
const oy = r * (c * u[1] + s * v[1]);
|
|
1302
|
+
const oz = r * (c * u[2] + s * v[2]);
|
|
1303
|
+
baseRing.push([ax + ox, ay + oy, az + oz]);
|
|
1304
|
+
topRing.push([bx + ox, by + oy, bz + oz]);
|
|
794
1305
|
}
|
|
795
1306
|
const vertices = [...baseRing, ...topRing];
|
|
796
1307
|
const faces = [];
|
|
@@ -801,7 +1312,7 @@ var init_cylinder3d = __esm({
|
|
|
801
1312
|
faces.push([i, next, CURVED_SEGMENTS + next, CURVED_SEGMENTS + i]);
|
|
802
1313
|
}
|
|
803
1314
|
const vertJxgs = vertices.map(
|
|
804
|
-
(
|
|
1315
|
+
(v2, i) => view.create("point3d", v2, {
|
|
805
1316
|
id: `${obj.id}.v${i}`,
|
|
806
1317
|
visible: false,
|
|
807
1318
|
fixed: true,
|
|
@@ -829,6 +1340,7 @@ var CURVED_SEGMENTS2;
|
|
|
829
1340
|
var init_cone3d = __esm({
|
|
830
1341
|
"src/core/scene/kinds/cone3d.ts"() {
|
|
831
1342
|
init_registry();
|
|
1343
|
+
init_ringBasis();
|
|
832
1344
|
CURVED_SEGMENTS2 = 16;
|
|
833
1345
|
registerKind({
|
|
834
1346
|
type: "cone3d",
|
|
@@ -851,10 +1363,16 @@ var init_cone3d = __esm({
|
|
|
851
1363
|
apexPt.Y?.() ?? 0,
|
|
852
1364
|
apexPt.Z?.() ?? 0
|
|
853
1365
|
];
|
|
1366
|
+
const [u, v] = perpBasis([apexCoords[0] - bx, apexCoords[1] - by, apexCoords[2] - bz]);
|
|
854
1367
|
const baseRing = [];
|
|
855
1368
|
for (let i = 0; i < CURVED_SEGMENTS2; i++) {
|
|
856
1369
|
const theta = i / CURVED_SEGMENTS2 * Math.PI * 2;
|
|
857
|
-
|
|
1370
|
+
const c = Math.cos(theta), s = Math.sin(theta);
|
|
1371
|
+
baseRing.push([
|
|
1372
|
+
bx + r * (c * u[0] + s * v[0]),
|
|
1373
|
+
by + r * (c * u[1] + s * v[1]),
|
|
1374
|
+
bz + r * (c * u[2] + s * v[2])
|
|
1375
|
+
]);
|
|
858
1376
|
}
|
|
859
1377
|
const apexIdx = baseRing.length;
|
|
860
1378
|
const vertices = [...baseRing, apexCoords];
|
|
@@ -863,7 +1381,7 @@ var init_cone3d = __esm({
|
|
|
863
1381
|
faces.push([i, (i + 1) % CURVED_SEGMENTS2, apexIdx]);
|
|
864
1382
|
}
|
|
865
1383
|
const vertJxgs = vertices.map(
|
|
866
|
-
(
|
|
1384
|
+
(v2, i) => view.create("point3d", v2, {
|
|
867
1385
|
id: `${obj.id}.v${i}`,
|
|
868
1386
|
visible: false,
|
|
869
1387
|
fixed: true,
|
|
@@ -952,8 +1470,16 @@ function constraintRefs2D(c) {
|
|
|
952
1470
|
}
|
|
953
1471
|
case "excenter":
|
|
954
1472
|
return [c.vertices[0], c.vertices[1], c.vertices[2]];
|
|
955
|
-
|
|
1473
|
+
case "commonTangentPoint":
|
|
1474
|
+
return [c.circles[0], c.circles[1]];
|
|
1475
|
+
// Các kind KHÔNG có ref scene-object (toạ độ literal): liệt kê TƯỜNG MINH để
|
|
1476
|
+
// exhaustive never-guard bên dưới buộc khai báo khi thêm constraint kind mới.
|
|
1477
|
+
case "free":
|
|
1478
|
+
case "onAxis":
|
|
956
1479
|
return [];
|
|
1480
|
+
default: {
|
|
1481
|
+
return [];
|
|
1482
|
+
}
|
|
957
1483
|
}
|
|
958
1484
|
}
|
|
959
1485
|
var init_d_constraint2 = __esm({
|
|
@@ -1491,19 +2017,19 @@ function buildJxgTransforms(board, ctx, t) {
|
|
|
1491
2017
|
}
|
|
1492
2018
|
}
|
|
1493
2019
|
function makeDistanceFn(ctx, d) {
|
|
1494
|
-
const
|
|
2020
|
+
const scale2 = d.scale ?? 1;
|
|
1495
2021
|
const offset = d.offset ?? 0;
|
|
1496
2022
|
if (d.kind === "literal") {
|
|
1497
2023
|
const v = d.value;
|
|
1498
|
-
return () =>
|
|
2024
|
+
return () => scale2 * v + offset;
|
|
1499
2025
|
}
|
|
1500
2026
|
if (d.kind === "segmentLength") {
|
|
1501
2027
|
const p = ctx.resolveRef(d.p1);
|
|
1502
2028
|
const q = ctx.resolveRef(d.p2);
|
|
1503
|
-
return () =>
|
|
2029
|
+
return () => scale2 * Math.hypot(p.X() - q.X(), p.Y() - q.Y()) + offset;
|
|
1504
2030
|
}
|
|
1505
2031
|
const circle = ctx.resolveRef(d.circle);
|
|
1506
|
-
return () =>
|
|
2032
|
+
return () => scale2 * circle.Radius() + offset;
|
|
1507
2033
|
}
|
|
1508
2034
|
function buildPointOpts(obj) {
|
|
1509
2035
|
return {
|
|
@@ -1552,6 +2078,73 @@ var init_pointAtDistance = __esm({
|
|
|
1552
2078
|
}
|
|
1553
2079
|
});
|
|
1554
2080
|
|
|
2081
|
+
// src/stamps/geometry-2d/geometry/commonTangent.ts
|
|
2082
|
+
function computeCommonTangentPoint(O1, r1, O2, r2, on, variant, side) {
|
|
2083
|
+
const dx = O2[0] - O1[0];
|
|
2084
|
+
const dy = O2[1] - O1[1];
|
|
2085
|
+
const d = Math.hypot(dx, dy);
|
|
2086
|
+
if (d < EPS) return null;
|
|
2087
|
+
const beta = Math.atan2(dy, dx);
|
|
2088
|
+
const ratio = variant === "external" ? (r1 - r2) / d : (r1 + r2) / d;
|
|
2089
|
+
if (Math.abs(ratio) > 1) return null;
|
|
2090
|
+
const gamma = Math.acos(ratio);
|
|
2091
|
+
const s = side === 0 ? 1 : -1;
|
|
2092
|
+
const angle = beta + s * gamma;
|
|
2093
|
+
const nx = Math.cos(angle);
|
|
2094
|
+
const ny = Math.sin(angle);
|
|
2095
|
+
if (on === 0) {
|
|
2096
|
+
return [O1[0] + r1 * nx, O1[1] + r1 * ny];
|
|
2097
|
+
}
|
|
2098
|
+
if (variant === "external") {
|
|
2099
|
+
return [O2[0] + r2 * nx, O2[1] + r2 * ny];
|
|
2100
|
+
}
|
|
2101
|
+
return [O2[0] - r2 * nx, O2[1] - r2 * ny];
|
|
2102
|
+
}
|
|
2103
|
+
var EPS;
|
|
2104
|
+
var init_commonTangent = __esm({
|
|
2105
|
+
"src/stamps/geometry-2d/geometry/commonTangent.ts"() {
|
|
2106
|
+
EPS = 1e-9;
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
|
|
2110
|
+
// src/core/scene/kinds/point-constraints/commonTangentPoint.ts
|
|
2111
|
+
var commonTangentPointConstraint;
|
|
2112
|
+
var init_commonTangentPoint = __esm({
|
|
2113
|
+
"src/core/scene/kinds/point-constraints/commonTangentPoint.ts"() {
|
|
2114
|
+
init_commonTangent();
|
|
2115
|
+
init_types2();
|
|
2116
|
+
commonTangentPointConstraint = definePointConstraint({
|
|
2117
|
+
kind: "commonTangentPoint",
|
|
2118
|
+
describe: (obj, state, c) => {
|
|
2119
|
+
const c1 = state?.objects[c.circles[0]]?.label ?? c.circles[0];
|
|
2120
|
+
const c2 = state?.objects[c.circles[1]]?.label ?? c.circles[1];
|
|
2121
|
+
const v = c.variant === "internal" ? "trong" : "ngo\xE0i";
|
|
2122
|
+
return `${obj.label} = ti\u1EBFp \u0111i\u1EC3m ti\u1EBFp tuy\u1EBFn chung ${v} ${c1},${c2} (tr\xEAn ${c.on === 0 ? c1 : c2})`;
|
|
2123
|
+
},
|
|
2124
|
+
render: (obj, ctx, c, opts) => {
|
|
2125
|
+
const board = ctx.jxg;
|
|
2126
|
+
const k1 = ctx.resolveRef(c.circles[0]);
|
|
2127
|
+
const k2 = ctx.resolveRef(c.circles[1]);
|
|
2128
|
+
const O1 = k1?.center ?? k1?.midpoint ?? k1;
|
|
2129
|
+
const O2 = k2?.center ?? k2?.midpoint ?? k2;
|
|
2130
|
+
const compute = () => {
|
|
2131
|
+
const t = computeCommonTangentPoint(
|
|
2132
|
+
[O1.X(), O1.Y()],
|
|
2133
|
+
k1.Radius(),
|
|
2134
|
+
[O2.X(), O2.Y()],
|
|
2135
|
+
k2.Radius(),
|
|
2136
|
+
c.on,
|
|
2137
|
+
c.variant,
|
|
2138
|
+
c.side
|
|
2139
|
+
);
|
|
2140
|
+
return t ?? [0, 0];
|
|
2141
|
+
};
|
|
2142
|
+
return board.create("point", [() => compute()[0], () => compute()[1]], opts);
|
|
2143
|
+
}
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
});
|
|
2147
|
+
|
|
1555
2148
|
// src/core/scene/kinds/point-constraints/circleIntersection.ts
|
|
1556
2149
|
var circleIntersectionConstraint;
|
|
1557
2150
|
var init_circleIntersection = __esm({
|
|
@@ -1831,6 +2424,7 @@ var init_registry2 = __esm({
|
|
|
1831
2424
|
init_excenter();
|
|
1832
2425
|
init_mixtilinearPoint();
|
|
1833
2426
|
init_pointAtDistance();
|
|
2427
|
+
init_commonTangentPoint();
|
|
1834
2428
|
init_circleIntersection();
|
|
1835
2429
|
init_circleSecondIntersection();
|
|
1836
2430
|
init_secondIntersection();
|
|
@@ -1857,6 +2451,7 @@ var init_registry2 = __esm({
|
|
|
1857
2451
|
excenterConstraint,
|
|
1858
2452
|
mixtilinearPointConstraint,
|
|
1859
2453
|
pointAtDistanceConstraint,
|
|
2454
|
+
commonTangentPointConstraint,
|
|
1860
2455
|
circleIntersectionConstraint,
|
|
1861
2456
|
circleSecondIntersectionConstraint,
|
|
1862
2457
|
secondIntersectionConstraint,
|
|
@@ -1873,7 +2468,7 @@ var init_registry2 = __esm({
|
|
|
1873
2468
|
});
|
|
1874
2469
|
|
|
1875
2470
|
// src/core/scene/kinds/point.ts
|
|
1876
|
-
var
|
|
2471
|
+
var def5;
|
|
1877
2472
|
var init_point = __esm({
|
|
1878
2473
|
"src/core/scene/kinds/point.ts"() {
|
|
1879
2474
|
init_registry();
|
|
@@ -1881,7 +2476,7 @@ var init_point = __esm({
|
|
|
1881
2476
|
init_registry2();
|
|
1882
2477
|
init_shared();
|
|
1883
2478
|
init_label();
|
|
1884
|
-
|
|
2479
|
+
def5 = {
|
|
1885
2480
|
type: "point",
|
|
1886
2481
|
schemaVersion: 1,
|
|
1887
2482
|
migrate: {},
|
|
@@ -1959,18 +2554,18 @@ var init_point = __esm({
|
|
|
1959
2554
|
throw new Error("point: constraint kind changed \u2014 recreate");
|
|
1960
2555
|
}
|
|
1961
2556
|
};
|
|
1962
|
-
registerKind(
|
|
2557
|
+
registerKind(def5);
|
|
1963
2558
|
}
|
|
1964
2559
|
});
|
|
1965
2560
|
|
|
1966
2561
|
// src/core/scene/kinds/segment.ts
|
|
1967
|
-
var
|
|
2562
|
+
var def6;
|
|
1968
2563
|
var init_segment = __esm({
|
|
1969
2564
|
"src/core/scene/kinds/segment.ts"() {
|
|
1970
2565
|
init_registry();
|
|
1971
2566
|
init_labelOf();
|
|
1972
2567
|
init_label();
|
|
1973
|
-
|
|
2568
|
+
def6 = {
|
|
1974
2569
|
type: "segment",
|
|
1975
2570
|
schemaVersion: 1,
|
|
1976
2571
|
migrate: {},
|
|
@@ -2006,7 +2601,7 @@ var init_segment = __esm({
|
|
|
2006
2601
|
});
|
|
2007
2602
|
}
|
|
2008
2603
|
};
|
|
2009
|
-
registerKind(
|
|
2604
|
+
registerKind(def6);
|
|
2010
2605
|
}
|
|
2011
2606
|
});
|
|
2012
2607
|
|
|
@@ -2034,14 +2629,14 @@ function constructionRefs(c) {
|
|
|
2034
2629
|
return [c.throughPoint, c.toCircle];
|
|
2035
2630
|
}
|
|
2036
2631
|
}
|
|
2037
|
-
var
|
|
2632
|
+
var def7;
|
|
2038
2633
|
var init_line = __esm({
|
|
2039
2634
|
"src/core/scene/kinds/line.ts"() {
|
|
2040
2635
|
init_registry();
|
|
2041
2636
|
init_labelOf();
|
|
2042
2637
|
init_label();
|
|
2043
2638
|
init_pointConstructions();
|
|
2044
|
-
|
|
2639
|
+
def7 = {
|
|
2045
2640
|
type: "line",
|
|
2046
2641
|
schemaVersion: 1,
|
|
2047
2642
|
migrate: {},
|
|
@@ -2237,17 +2832,17 @@ var init_line = __esm({
|
|
|
2237
2832
|
}
|
|
2238
2833
|
}
|
|
2239
2834
|
};
|
|
2240
|
-
registerKind(
|
|
2835
|
+
registerKind(def7);
|
|
2241
2836
|
}
|
|
2242
2837
|
});
|
|
2243
2838
|
|
|
2244
2839
|
// src/core/scene/kinds/ray.ts
|
|
2245
|
-
var
|
|
2840
|
+
var def8;
|
|
2246
2841
|
var init_ray = __esm({
|
|
2247
2842
|
"src/core/scene/kinds/ray.ts"() {
|
|
2248
2843
|
init_registry();
|
|
2249
2844
|
init_labelOf();
|
|
2250
|
-
|
|
2845
|
+
def8 = {
|
|
2251
2846
|
type: "ray",
|
|
2252
2847
|
schemaVersion: 1,
|
|
2253
2848
|
migrate: {},
|
|
@@ -2272,17 +2867,17 @@ var init_ray = __esm({
|
|
|
2272
2867
|
});
|
|
2273
2868
|
}
|
|
2274
2869
|
};
|
|
2275
|
-
registerKind(
|
|
2870
|
+
registerKind(def8);
|
|
2276
2871
|
}
|
|
2277
2872
|
});
|
|
2278
2873
|
|
|
2279
2874
|
// src/core/scene/kinds/vector.ts
|
|
2280
|
-
var
|
|
2875
|
+
var def9;
|
|
2281
2876
|
var init_vector = __esm({
|
|
2282
2877
|
"src/core/scene/kinds/vector.ts"() {
|
|
2283
2878
|
init_registry();
|
|
2284
2879
|
init_labelOf();
|
|
2285
|
-
|
|
2880
|
+
def9 = {
|
|
2286
2881
|
type: "vector",
|
|
2287
2882
|
schemaVersion: 1,
|
|
2288
2883
|
migrate: {},
|
|
@@ -2304,7 +2899,7 @@ var init_vector = __esm({
|
|
|
2304
2899
|
});
|
|
2305
2900
|
}
|
|
2306
2901
|
};
|
|
2307
|
-
registerKind(
|
|
2902
|
+
registerKind(def9);
|
|
2308
2903
|
}
|
|
2309
2904
|
});
|
|
2310
2905
|
|
|
@@ -2334,14 +2929,14 @@ function constructionRefs2(c) {
|
|
|
2334
2929
|
return [c.p1, c.p2];
|
|
2335
2930
|
}
|
|
2336
2931
|
}
|
|
2337
|
-
var
|
|
2932
|
+
var def10;
|
|
2338
2933
|
var init_circle = __esm({
|
|
2339
2934
|
"src/core/scene/kinds/circle.ts"() {
|
|
2340
2935
|
init_registry();
|
|
2341
2936
|
init_labelOf();
|
|
2342
2937
|
init_label();
|
|
2343
2938
|
init_pointConstructions();
|
|
2344
|
-
|
|
2939
|
+
def10 = {
|
|
2345
2940
|
type: "circle",
|
|
2346
2941
|
schemaVersion: 1,
|
|
2347
2942
|
migrate: {},
|
|
@@ -2493,7 +3088,7 @@ var init_circle = __esm({
|
|
|
2493
3088
|
return board.create("circle", [center, surface], baseOpts);
|
|
2494
3089
|
}
|
|
2495
3090
|
};
|
|
2496
|
-
registerKind(
|
|
3091
|
+
registerKind(def10);
|
|
2497
3092
|
}
|
|
2498
3093
|
});
|
|
2499
3094
|
|
|
@@ -2508,12 +3103,12 @@ function constructionRefs3(c) {
|
|
|
2508
3103
|
return [c.p1, c.p2, c.p3];
|
|
2509
3104
|
}
|
|
2510
3105
|
}
|
|
2511
|
-
var
|
|
3106
|
+
var def11;
|
|
2512
3107
|
var init_arc = __esm({
|
|
2513
3108
|
"src/core/scene/kinds/arc.ts"() {
|
|
2514
3109
|
init_registry();
|
|
2515
3110
|
init_labelOf();
|
|
2516
|
-
|
|
3111
|
+
def11 = {
|
|
2517
3112
|
type: "arc",
|
|
2518
3113
|
schemaVersion: 1,
|
|
2519
3114
|
migrate: {},
|
|
@@ -2571,17 +3166,17 @@ var init_arc = __esm({
|
|
|
2571
3166
|
return board.create("circumcirclearc", [A, B, C], baseOpts);
|
|
2572
3167
|
}
|
|
2573
3168
|
};
|
|
2574
|
-
registerKind(
|
|
3169
|
+
registerKind(def11);
|
|
2575
3170
|
}
|
|
2576
3171
|
});
|
|
2577
3172
|
|
|
2578
3173
|
// src/core/scene/kinds/sector.ts
|
|
2579
|
-
var
|
|
3174
|
+
var def12;
|
|
2580
3175
|
var init_sector = __esm({
|
|
2581
3176
|
"src/core/scene/kinds/sector.ts"() {
|
|
2582
3177
|
init_registry();
|
|
2583
3178
|
init_labelOf();
|
|
2584
|
-
|
|
3179
|
+
def12 = {
|
|
2585
3180
|
type: "sector",
|
|
2586
3181
|
schemaVersion: 1,
|
|
2587
3182
|
migrate: {},
|
|
@@ -2621,7 +3216,7 @@ var init_sector = __esm({
|
|
|
2621
3216
|
});
|
|
2622
3217
|
}
|
|
2623
3218
|
};
|
|
2624
|
-
registerKind(
|
|
3219
|
+
registerKind(def12);
|
|
2625
3220
|
}
|
|
2626
3221
|
});
|
|
2627
3222
|
|
|
@@ -2667,12 +3262,12 @@ function specialShapeName(kind) {
|
|
|
2667
3262
|
return "";
|
|
2668
3263
|
}
|
|
2669
3264
|
}
|
|
2670
|
-
var
|
|
3265
|
+
var def13;
|
|
2671
3266
|
var init_polygon = __esm({
|
|
2672
3267
|
"src/core/scene/kinds/polygon.ts"() {
|
|
2673
3268
|
init_registry();
|
|
2674
3269
|
init_labelOf();
|
|
2675
|
-
|
|
3270
|
+
def13 = {
|
|
2676
3271
|
type: "polygon",
|
|
2677
3272
|
schemaVersion: 1,
|
|
2678
3273
|
migrate: {},
|
|
@@ -2859,16 +3454,16 @@ var init_polygon = __esm({
|
|
|
2859
3454
|
return poly;
|
|
2860
3455
|
}
|
|
2861
3456
|
};
|
|
2862
|
-
registerKind(
|
|
3457
|
+
registerKind(def13);
|
|
2863
3458
|
}
|
|
2864
3459
|
});
|
|
2865
3460
|
|
|
2866
3461
|
// src/core/scene/kinds/intersection.ts
|
|
2867
|
-
var
|
|
3462
|
+
var def14;
|
|
2868
3463
|
var init_intersection = __esm({
|
|
2869
3464
|
"src/core/scene/kinds/intersection.ts"() {
|
|
2870
3465
|
init_registry();
|
|
2871
|
-
|
|
3466
|
+
def14 = {
|
|
2872
3467
|
type: "intersection",
|
|
2873
3468
|
schemaVersion: 1,
|
|
2874
3469
|
migrate: {},
|
|
@@ -2943,17 +3538,17 @@ var init_intersection = __esm({
|
|
|
2943
3538
|
}
|
|
2944
3539
|
}
|
|
2945
3540
|
};
|
|
2946
|
-
registerKind(
|
|
3541
|
+
registerKind(def14);
|
|
2947
3542
|
}
|
|
2948
3543
|
});
|
|
2949
3544
|
|
|
2950
3545
|
// src/core/scene/kinds/angle.ts
|
|
2951
|
-
var
|
|
3546
|
+
var def15;
|
|
2952
3547
|
var init_angle = __esm({
|
|
2953
3548
|
"src/core/scene/kinds/angle.ts"() {
|
|
2954
3549
|
init_registry();
|
|
2955
3550
|
init_labelOf();
|
|
2956
|
-
|
|
3551
|
+
def15 = {
|
|
2957
3552
|
type: "angle",
|
|
2958
3553
|
schemaVersion: 1,
|
|
2959
3554
|
migrate: {},
|
|
@@ -2989,17 +3584,17 @@ var init_angle = __esm({
|
|
|
2989
3584
|
});
|
|
2990
3585
|
}
|
|
2991
3586
|
};
|
|
2992
|
-
registerKind(
|
|
3587
|
+
registerKind(def15);
|
|
2993
3588
|
}
|
|
2994
3589
|
});
|
|
2995
3590
|
|
|
2996
3591
|
// src/core/scene/kinds/distance.ts
|
|
2997
|
-
var
|
|
3592
|
+
var def16;
|
|
2998
3593
|
var init_distance = __esm({
|
|
2999
3594
|
"src/core/scene/kinds/distance.ts"() {
|
|
3000
3595
|
init_registry();
|
|
3001
3596
|
init_labelOf();
|
|
3002
|
-
|
|
3597
|
+
def16 = {
|
|
3003
3598
|
type: "distance",
|
|
3004
3599
|
schemaVersion: 1,
|
|
3005
3600
|
migrate: {},
|
|
@@ -3028,7 +3623,7 @@ var init_distance = __esm({
|
|
|
3028
3623
|
});
|
|
3029
3624
|
}
|
|
3030
3625
|
};
|
|
3031
|
-
registerKind(
|
|
3626
|
+
registerKind(def16);
|
|
3032
3627
|
}
|
|
3033
3628
|
});
|
|
3034
3629
|
|
|
@@ -3157,12 +3752,12 @@ var init_parser = __esm({
|
|
|
3157
3752
|
});
|
|
3158
3753
|
|
|
3159
3754
|
// src/core/scene/kinds/function2d.ts
|
|
3160
|
-
var
|
|
3755
|
+
var def17;
|
|
3161
3756
|
var init_function2d = __esm({
|
|
3162
3757
|
"src/core/scene/kinds/function2d.ts"() {
|
|
3163
3758
|
init_registry();
|
|
3164
3759
|
init_parser();
|
|
3165
|
-
|
|
3760
|
+
def17 = {
|
|
3166
3761
|
type: "function2d",
|
|
3167
3762
|
schemaVersion: 1,
|
|
3168
3763
|
migrate: {},
|
|
@@ -3201,16 +3796,16 @@ var init_function2d = __esm({
|
|
|
3201
3796
|
});
|
|
3202
3797
|
}
|
|
3203
3798
|
};
|
|
3204
|
-
registerKind(
|
|
3799
|
+
registerKind(def17);
|
|
3205
3800
|
}
|
|
3206
3801
|
});
|
|
3207
3802
|
|
|
3208
3803
|
// src/core/scene/kinds/parameter.ts
|
|
3209
|
-
var
|
|
3804
|
+
var def18;
|
|
3210
3805
|
var init_parameter = __esm({
|
|
3211
3806
|
"src/core/scene/kinds/parameter.ts"() {
|
|
3212
3807
|
init_registry();
|
|
3213
|
-
|
|
3808
|
+
def18 = {
|
|
3214
3809
|
type: "parameter",
|
|
3215
3810
|
schemaVersion: 1,
|
|
3216
3811
|
migrate: {},
|
|
@@ -3228,16 +3823,16 @@ var init_parameter = __esm({
|
|
|
3228
3823
|
render: () => null
|
|
3229
3824
|
// Không render lên board
|
|
3230
3825
|
};
|
|
3231
|
-
registerKind(
|
|
3826
|
+
registerKind(def18);
|
|
3232
3827
|
}
|
|
3233
3828
|
});
|
|
3234
3829
|
|
|
3235
3830
|
// src/core/scene/kinds/pointOnCurve.ts
|
|
3236
|
-
var
|
|
3831
|
+
var def19;
|
|
3237
3832
|
var init_pointOnCurve = __esm({
|
|
3238
3833
|
"src/core/scene/kinds/pointOnCurve.ts"() {
|
|
3239
3834
|
init_registry();
|
|
3240
|
-
|
|
3835
|
+
def19 = {
|
|
3241
3836
|
type: "pointOnCurve",
|
|
3242
3837
|
schemaVersion: 1,
|
|
3243
3838
|
migrate: {},
|
|
@@ -3264,16 +3859,16 @@ var init_pointOnCurve = __esm({
|
|
|
3264
3859
|
});
|
|
3265
3860
|
}
|
|
3266
3861
|
};
|
|
3267
|
-
registerKind(
|
|
3862
|
+
registerKind(def19);
|
|
3268
3863
|
}
|
|
3269
3864
|
});
|
|
3270
3865
|
|
|
3271
3866
|
// src/core/scene/kinds/tangent2d.ts
|
|
3272
|
-
var
|
|
3867
|
+
var def20;
|
|
3273
3868
|
var init_tangent2d = __esm({
|
|
3274
3869
|
"src/core/scene/kinds/tangent2d.ts"() {
|
|
3275
3870
|
init_registry();
|
|
3276
|
-
|
|
3871
|
+
def20 = {
|
|
3277
3872
|
type: "tangent2d",
|
|
3278
3873
|
schemaVersion: 1,
|
|
3279
3874
|
migrate: {},
|
|
@@ -3296,7 +3891,7 @@ var init_tangent2d = __esm({
|
|
|
3296
3891
|
});
|
|
3297
3892
|
}
|
|
3298
3893
|
};
|
|
3299
|
-
registerKind(
|
|
3894
|
+
registerKind(def20);
|
|
3300
3895
|
}
|
|
3301
3896
|
});
|
|
3302
3897
|
|
|
@@ -3372,13 +3967,13 @@ var init_evaluator = __esm({
|
|
|
3372
3967
|
});
|
|
3373
3968
|
|
|
3374
3969
|
// src/core/scene/kinds/extremum2d.ts
|
|
3375
|
-
var
|
|
3970
|
+
var def21;
|
|
3376
3971
|
var init_extremum2d = __esm({
|
|
3377
3972
|
"src/core/scene/kinds/extremum2d.ts"() {
|
|
3378
3973
|
init_registry();
|
|
3379
3974
|
init_evaluator();
|
|
3380
3975
|
init_parser();
|
|
3381
|
-
|
|
3976
|
+
def21 = {
|
|
3382
3977
|
type: "extremum2d",
|
|
3383
3978
|
schemaVersion: 1,
|
|
3384
3979
|
migrate: {},
|
|
@@ -3411,18 +4006,18 @@ var init_extremum2d = __esm({
|
|
|
3411
4006
|
}));
|
|
3412
4007
|
}
|
|
3413
4008
|
};
|
|
3414
|
-
registerKind(
|
|
4009
|
+
registerKind(def21);
|
|
3415
4010
|
}
|
|
3416
4011
|
});
|
|
3417
4012
|
|
|
3418
4013
|
// src/core/scene/kinds/root2d.ts
|
|
3419
|
-
var
|
|
4014
|
+
var def22;
|
|
3420
4015
|
var init_root2d = __esm({
|
|
3421
4016
|
"src/core/scene/kinds/root2d.ts"() {
|
|
3422
4017
|
init_registry();
|
|
3423
4018
|
init_evaluator();
|
|
3424
4019
|
init_parser();
|
|
3425
|
-
|
|
4020
|
+
def22 = {
|
|
3426
4021
|
type: "root2d",
|
|
3427
4022
|
schemaVersion: 1,
|
|
3428
4023
|
migrate: {},
|
|
@@ -3452,16 +4047,16 @@ var init_root2d = __esm({
|
|
|
3452
4047
|
}));
|
|
3453
4048
|
}
|
|
3454
4049
|
};
|
|
3455
|
-
registerKind(
|
|
4050
|
+
registerKind(def22);
|
|
3456
4051
|
}
|
|
3457
4052
|
});
|
|
3458
4053
|
|
|
3459
4054
|
// src/core/scene/kinds/slope2d.ts
|
|
3460
|
-
var
|
|
4055
|
+
var def23;
|
|
3461
4056
|
var init_slope2d = __esm({
|
|
3462
4057
|
"src/core/scene/kinds/slope2d.ts"() {
|
|
3463
4058
|
init_registry();
|
|
3464
|
-
|
|
4059
|
+
def23 = {
|
|
3465
4060
|
type: "slope2d",
|
|
3466
4061
|
schemaVersion: 1,
|
|
3467
4062
|
migrate: {},
|
|
@@ -3485,7 +4080,7 @@ var init_slope2d = __esm({
|
|
|
3485
4080
|
});
|
|
3486
4081
|
}
|
|
3487
4082
|
};
|
|
3488
|
-
registerKind(
|
|
4083
|
+
registerKind(def23);
|
|
3489
4084
|
}
|
|
3490
4085
|
});
|
|
3491
4086
|
|
|
@@ -3691,8 +4286,8 @@ var init_JxgRenderer = __esm({
|
|
|
3691
4286
|
}
|
|
3692
4287
|
create(obj) {
|
|
3693
4288
|
try {
|
|
3694
|
-
const
|
|
3695
|
-
const el =
|
|
4289
|
+
const def24 = getKind(obj.kind);
|
|
4290
|
+
const el = def24.render(obj, this.ctx());
|
|
3696
4291
|
this.elements.set(obj.id, el);
|
|
3697
4292
|
this.attachFreePointDragSync(obj, el);
|
|
3698
4293
|
this.attachGliderDragSync(obj, el);
|
|
@@ -3896,11 +4491,11 @@ var init_JxgRenderer = __esm({
|
|
|
3896
4491
|
continue;
|
|
3897
4492
|
}
|
|
3898
4493
|
if (Object.is(old, cur)) continue;
|
|
3899
|
-
const
|
|
4494
|
+
const def24 = getKind(cur.kind);
|
|
3900
4495
|
const existing = this.elements.get(id);
|
|
3901
|
-
if (
|
|
4496
|
+
if (def24.update && existing) {
|
|
3902
4497
|
try {
|
|
3903
|
-
|
|
4498
|
+
def24.update(cur, old, this.ctx(), existing);
|
|
3904
4499
|
continue;
|
|
3905
4500
|
} catch (err) {
|
|
3906
4501
|
console.warn(`[scene/render/2d] update fail, recreate:`, err);
|
|
@@ -4177,15 +4772,18 @@ function computeAutoFitBbox(points, circles, aspect, padPct = 0.12) {
|
|
|
4177
4772
|
const xs = points.map((p) => p[0]).filter(Number.isFinite);
|
|
4178
4773
|
const ys = points.map((p) => p[1]).filter(Number.isFinite);
|
|
4179
4774
|
let xmin = Infinity, xmax = -Infinity, ymin = Infinity, ymax = -Infinity;
|
|
4180
|
-
let
|
|
4775
|
+
let fullDiag = 0;
|
|
4181
4776
|
if (xs.length >= 2 && ys.length >= 2) {
|
|
4182
4777
|
[xmin, xmax] = robustRange(xs);
|
|
4183
4778
|
[ymin, ymax] = robustRange(ys);
|
|
4184
|
-
|
|
4779
|
+
fullDiag = Math.hypot(
|
|
4780
|
+
Math.max(...xs) - Math.min(...xs),
|
|
4781
|
+
Math.max(...ys) - Math.min(...ys)
|
|
4782
|
+
);
|
|
4185
4783
|
}
|
|
4186
4784
|
for (const c of circles) {
|
|
4187
4785
|
if (!Number.isFinite(c.cx) || !Number.isFinite(c.cy) || !Number.isFinite(c.r)) continue;
|
|
4188
|
-
if (
|
|
4786
|
+
if (fullDiag > 0 && c.r > CIRCLE_MAX_FACTOR * fullDiag) continue;
|
|
4189
4787
|
xmin = Math.min(xmin, c.cx - c.r);
|
|
4190
4788
|
xmax = Math.max(xmax, c.cx + c.r);
|
|
4191
4789
|
ymin = Math.min(ymin, c.cy - c.r);
|
|
@@ -5048,7 +5646,7 @@ var init_useToolHoverTooltip = __esm({
|
|
|
5048
5646
|
init_types4();
|
|
5049
5647
|
}
|
|
5050
5648
|
});
|
|
5051
|
-
function
|
|
5649
|
+
function normalize2(s) {
|
|
5052
5650
|
return s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/đ/g, "d").replace(/Đ/g, "d");
|
|
5053
5651
|
}
|
|
5054
5652
|
function SearchIcon() {
|
|
@@ -5095,12 +5693,12 @@ function ToolGrid(props) {
|
|
|
5095
5693
|
const { tools, groupOrder, groupLabels, activeTool, onToolChange, chord } = props;
|
|
5096
5694
|
const { hover, portalReady, showHover, hideHover } = useToolHoverTooltip();
|
|
5097
5695
|
const [query, setQuery] = React2.useState("");
|
|
5098
|
-
const normalizedQuery = React2.useMemo(() =>
|
|
5696
|
+
const normalizedQuery = React2.useMemo(() => normalize2(query.trim()), [query]);
|
|
5099
5697
|
const filteredTools = React2.useMemo(() => {
|
|
5100
5698
|
if (!normalizedQuery) return tools;
|
|
5101
5699
|
return tools.filter((t) => {
|
|
5102
|
-
if (
|
|
5103
|
-
if (t.hint &&
|
|
5700
|
+
if (normalize2(t.label).includes(normalizedQuery)) return true;
|
|
5701
|
+
if (t.hint && normalize2(t.hint).includes(normalizedQuery)) return true;
|
|
5104
5702
|
return false;
|
|
5105
5703
|
});
|
|
5106
5704
|
}, [tools, normalizedQuery]);
|
|
@@ -6808,8 +7406,8 @@ var init_circles = __esm({
|
|
|
6808
7406
|
const ax = picks[0].X(), ay = picks[0].Y();
|
|
6809
7407
|
const bx = picks[1].X(), by = picks[1].Y();
|
|
6810
7408
|
const cx = picks[2].X(), cy = picks[2].Y();
|
|
6811
|
-
const
|
|
6812
|
-
if (Math.abs(
|
|
7409
|
+
const cross2 = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
|
|
7410
|
+
if (Math.abs(cross2) < 1e-6) {
|
|
6813
7411
|
ctx.toast?.("Kh\xF4ng v\u1EBD \u0111\u01B0\u1EE3c cung qua 3 \u0111i\u1EC3m th\u1EB3ng h\xE0ng", {
|
|
6814
7412
|
variant: "warning",
|
|
6815
7413
|
id: "arc3-collinear"
|
|
@@ -9588,6 +10186,141 @@ var init_tesseract = __esm({
|
|
|
9588
10186
|
}
|
|
9589
10187
|
});
|
|
9590
10188
|
|
|
10189
|
+
// src/stamps/geometry-2d/ai/vision/repairOcrSymbols.ts
|
|
10190
|
+
function repairOcrSymbols(text) {
|
|
10191
|
+
let t = text;
|
|
10192
|
+
t = t.replace(PERP_RE, "$1 \u22A5 $3");
|
|
10193
|
+
t = t.replace(TRI_STRICT_RE, "tam gi\xE1c $1 $2");
|
|
10194
|
+
t = t.replace(TRI_DOUBLE_RE, "tam gi\xE1c A$1");
|
|
10195
|
+
t = t.replace(CIRCLE_O_RE, "(O)");
|
|
10196
|
+
t = t.replace(ELEM_RE, "$1 \u2208 (O)");
|
|
10197
|
+
t = t.replace(INTERSECT_RE, "$1 \u2229 $2 = {");
|
|
10198
|
+
t = t.replace(SQUARE_RE, "$1\xB2");
|
|
10199
|
+
t = t.replace(HORN_O_C_RE, "C");
|
|
10200
|
+
t = t.replace(DUONG_DBAR_RE, "\u0110\u01B0\u1EDDng");
|
|
10201
|
+
t = t.replace(DUONG_LOWER_RE, "\u0111\u01B0\u1EDDng");
|
|
10202
|
+
t = t.replace(DUONG_TRON_RE, "$1tr\xF2n");
|
|
10203
|
+
t = t.replace(FLORIN_F_RE, "F");
|
|
10204
|
+
t = t.replace(TAI_TAI_RE, "t\u1EA1i$1");
|
|
10205
|
+
t = t.replace(TAM_TAM_RE, "t\xE2m$1");
|
|
10206
|
+
t = t.replace(EURO_ELEM_RE, "\u2208");
|
|
10207
|
+
t = t.replace(PARALLEL_RE, "\u2225");
|
|
10208
|
+
t = t.replace(CENT_C_RE, "c");
|
|
10209
|
+
t = t.replace(ETH_D_RE, "D");
|
|
10210
|
+
t = t.replace(SLASH_O_RE, "O");
|
|
10211
|
+
t = t.replace(GOI_RE, "G\u1ECDi");
|
|
10212
|
+
t = t.replace(LAY_RE, "L\u1EA5y");
|
|
10213
|
+
t = t.replace(DIQUA_RE, "\u0111i qua");
|
|
10214
|
+
t = t.replace(VA_VAND_RE, "v\xE0 ");
|
|
10215
|
+
t = t.replace(TREN_RE, "$1r\xEAn");
|
|
10216
|
+
t = t.replace(DAY_RE, "d\xE2y");
|
|
10217
|
+
t = t.replace(CHUNG_MINH_RE, "$1minh");
|
|
10218
|
+
t = t.replace(THANG_HANG_RE, "th\u1EB3ng h\xE0ng");
|
|
10219
|
+
t = t.replace(TINH_RE, "T\xEDnh");
|
|
10220
|
+
t = t.replace(DO_DAI_RE, "\u0111\u1ED9 d\xE0i");
|
|
10221
|
+
t = t.replace(NIM_RE, "n\u1EB1m");
|
|
10222
|
+
t = t.replace(NAM_GIUA_RE, "n\u1EB1m");
|
|
10223
|
+
t = t.replace(ANGLE_Z_RE, "\u2220$1");
|
|
10224
|
+
t = t.replace(DE_PAREN_RE, "(\u0110\u1EC1 ");
|
|
10225
|
+
t = t.replace(DE_VERB_RE, "$1xu\u1EA5t$2");
|
|
10226
|
+
t = t.replace(DE_THI_LOWER_RE, "\u0111\u1EC1");
|
|
10227
|
+
t = t.replace(DI_DONG_RE, "di \u0111\u1ED9ng");
|
|
10228
|
+
t = t.replace(POUND_E_RE, "E");
|
|
10229
|
+
t = t.replace(TRI_SPACE_2_1, "$1$2$3$4");
|
|
10230
|
+
t = t.replace(TRI_SPACE_1_2, "$1$2$3$4");
|
|
10231
|
+
t = t.replace(DIAERESIS_O_RE, "O");
|
|
10232
|
+
t = t.replace(INTERSECT_PAREN_RE, "$1 \u2229 $2$3");
|
|
10233
|
+
return t;
|
|
10234
|
+
}
|
|
10235
|
+
var PT, PERP_RE, TRI_STRICT_RE, TRI_DOUBLE_RE, CIRCLE_O_RE, ELEM_RE, INTERSECT_RE, SQUARE_RE, HORN_O_C_RE, DUONG_DBAR_RE, DUONG_TRON_RE, FLORIN_F_RE, TAI_TAI_RE, TAM_TAM_RE, EURO_ELEM_RE, PARALLEL_RE, CENT_C_RE, ETH_D_RE, SLASH_O_RE, GOI_RE, LAY_RE, DIQUA_RE, VA_VAND_RE, TREN_RE, DUONG_LOWER_RE, DAY_RE, CHUNG_MINH_RE, THANG_HANG_RE, TINH_RE, DO_DAI_RE, NIM_RE, NAM_GIUA_RE, ANGLE_Z_RE, DE_PAREN_RE, DE_VERB_RE, DE_THI_LOWER_RE, DI_DONG_RE, POUND_E_RE, TRI_SPACE_2_1, TRI_SPACE_1_2, DIAERESIS_O_RE, INTERSECT_PAREN_RE;
|
|
10236
|
+
var init_repairOcrSymbols = __esm({
|
|
10237
|
+
"src/stamps/geometry-2d/ai/vision/repairOcrSymbols.ts"() {
|
|
10238
|
+
PT = `[A-Z]{2,3}['\u2032]?`;
|
|
10239
|
+
PERP_RE = new RegExp(
|
|
10240
|
+
`(?<![\\p{L}\\d])(${PT})\\s+([1|L])\\s+(${PT})(?![\\p{L}\\d])`,
|
|
10241
|
+
"gu"
|
|
10242
|
+
);
|
|
10243
|
+
TRI_STRICT_RE = /(?<!giác )(?<!thang )(?<![\p{L}\d])A([A-Z]{3})\s+(đều|cân|nhọn|vuông)(?![\p{L}])/gu;
|
|
10244
|
+
TRI_DOUBLE_RE = /(?<![\p{L}\d])AA([A-Z]{2})(?![A-Z])/gu;
|
|
10245
|
+
CIRCLE_O_RE = /\(0\)/gu;
|
|
10246
|
+
ELEM_RE = /(?<![\p{L}\d])([A-Z](?:\s*,\s*[A-Z])+)\s*e\s*\((?:O|0)\)/gu;
|
|
10247
|
+
INTERSECT_RE = /([A-Z]{2,3})N\s+([A-Z]\S{0,2})\s*=\s*\{/gu;
|
|
10248
|
+
SQUARE_RE = /([A-Z])\?(?=\s*[-=+)])/gu;
|
|
10249
|
+
HORN_O_C_RE = /(?<!\p{Ll})Ơ(?!\p{Ll})/gu;
|
|
10250
|
+
DUONG_DBAR_RE = /D(?:ường|uong)(?= (?:tròn|tron|thẳng|kính|cao|chéo|trung|phân|vuông|nối|gấp|tâm))/gu;
|
|
10251
|
+
DUONG_TRON_RE = /([Đđ]ường\s+)tron(?![\p{L}])/gu;
|
|
10252
|
+
FLORIN_F_RE = /Ƒ/gu;
|
|
10253
|
+
TAI_TAI_RE = /(?<![\p{L}])tai(\s+)(?=[A-Z(]|điểm)/gu;
|
|
10254
|
+
TAM_TAM_RE = /(?<![\p{L}])tam(\s+)(?=đường|\(|đối xứng)/gu;
|
|
10255
|
+
EURO_ELEM_RE = /€/gu;
|
|
10256
|
+
PARALLEL_RE = /\|\|/gu;
|
|
10257
|
+
CENT_C_RE = /¢/gu;
|
|
10258
|
+
ETH_D_RE = /(?<!\p{Ll})Ð(?!\p{Ll})/gu;
|
|
10259
|
+
SLASH_O_RE = /(?<!\p{Ll})Ø(?!\p{Ll})/gu;
|
|
10260
|
+
GOI_RE = /(?<!\p{L})Goi(?!\p{L})/gu;
|
|
10261
|
+
LAY_RE = /(?<!\p{L})Lay(?!\p{L})/gu;
|
|
10262
|
+
DIQUA_RE = /(?<!\p{L})di qua(?!\p{L})/gu;
|
|
10263
|
+
VA_VAND_RE = /(?<!\p{L})va (?=[A-Z(]|dây|đường)/gu;
|
|
10264
|
+
TREN_RE = /([Tt])rén(?![\p{L}])/gu;
|
|
10265
|
+
DUONG_LOWER_RE = /(?<![\p{L}])dường(?= (?:tròn|tron|thẳng|kính|cao|chéo|trung|phân|vuông|nối|gấp|tâm))/gu;
|
|
10266
|
+
DAY_RE = /(?<![\p{L}])day(?=\s+(?:cung(?![\p{L}])|[A-Z]{2}))/gu;
|
|
10267
|
+
CHUNG_MINH_RE = /([Cc]hứng )mình(?![\p{L}])/gu;
|
|
10268
|
+
THANG_HANG_RE = /thẳng hang(?![\p{L}])/gu;
|
|
10269
|
+
TINH_RE = /(?<![\p{L}])Tinh(?= (?:[A-Z]|do(?![\p{L}])|độ|diện|bán|chu|số|giá))/gu;
|
|
10270
|
+
DO_DAI_RE = /(?<![\p{L}])do dai(?![\p{L}])/gu;
|
|
10271
|
+
NIM_RE = /(?<![\p{L}])nim(?= (?:giữa|trên|trong)(?![\p{L}]))/gu;
|
|
10272
|
+
NAM_GIUA_RE = /(?<![\p{L}])năm(?= (?:giữa|trên) [A-Z])/gu;
|
|
10273
|
+
ANGLE_Z_RE = /(?<![\p{L}\d])4?Z([A-Z]{2,3})(?![A-Z])/gu;
|
|
10274
|
+
DE_PAREN_RE = /\(Dé /gu;
|
|
10275
|
+
DE_VERB_RE = /(\(Đề )\S+( bởi)/gu;
|
|
10276
|
+
DE_THI_LOWER_RE = /(?<![\p{L}])dé(?= thi)/gu;
|
|
10277
|
+
DI_DONG_RE = /(?<![\p{L}])di dong(?![\p{L}])/gu;
|
|
10278
|
+
POUND_E_RE = /£/gu;
|
|
10279
|
+
TRI_SPACE_2_1 = /(tam\s*giác\s+)([A-Z])([A-Z])\s+([A-Z])(?![A-Z\p{Ll}])/gu;
|
|
10280
|
+
TRI_SPACE_1_2 = /(tam\s*giác\s+)([A-Z])\s+([A-Z])([A-Z])(?![A-Z\p{Ll}])/gu;
|
|
10281
|
+
DIAERESIS_O_RE = /(?<!\p{Ll})Ö(?!\p{Ll})/gu;
|
|
10282
|
+
INTERSECT_PAREN_RE = /(\([A-Z]{3}\))\s+N\s+([A-Z]{2})(\s*=\s*\{)/gu;
|
|
10283
|
+
}
|
|
10284
|
+
});
|
|
10285
|
+
|
|
10286
|
+
// src/stamps/geometry-2d/ai/vision/detectFormulaRisk.ts
|
|
10287
|
+
function hasManglingLtGt(text) {
|
|
10288
|
+
const re = /[<>]/gu;
|
|
10289
|
+
let m;
|
|
10290
|
+
while ((m = re.exec(text)) !== null) {
|
|
10291
|
+
const prev = text.slice(0, m.index).replace(/\s+$/u, "").slice(-1);
|
|
10292
|
+
const next = text.slice(m.index + 1).replace(/^\s+/u, "").slice(0, 1);
|
|
10293
|
+
const prevOperand = /[A-Za-z0-9]/.test(prev);
|
|
10294
|
+
const nextOperand = /[A-Za-z0-9]/.test(next);
|
|
10295
|
+
if (!(prevOperand && nextOperand)) return true;
|
|
10296
|
+
}
|
|
10297
|
+
return false;
|
|
10298
|
+
}
|
|
10299
|
+
function detectFormulaRisk(text) {
|
|
10300
|
+
const reasons = [];
|
|
10301
|
+
if (hasManglingLtGt(text)) {
|
|
10302
|
+
reasons.push('ph\xE2n s\u1ED1/bi\u1EC3u th\u1EE9c nghi b\u1ECB nu\u1ED1t (k\xFD hi\u1EC7u "<"/">")');
|
|
10303
|
+
}
|
|
10304
|
+
if (SUP_RESIDUE.test(text)) {
|
|
10305
|
+
reasons.push('s\u1ED1 m\u0169 ho\u1EB7c \u0111\u1ED9 nghi b\u1ECB m\u1EA5t (d\u1EA5u "?")');
|
|
10306
|
+
}
|
|
10307
|
+
for (const m of text.matchAll(ANGLE_DEG)) {
|
|
10308
|
+
const tok = m[1];
|
|
10309
|
+
if (/[A-Z]/.test(tok) && /[^\x00-\x7F]/u.test(tok)) {
|
|
10310
|
+
reasons.push("t\xEAn g\xF3c nghi b\u1ECB nh\u1EADn d\u1EA1ng sai (k\xFD t\u1EF1 c\xF3 d\u1EA5u)");
|
|
10311
|
+
break;
|
|
10312
|
+
}
|
|
10313
|
+
}
|
|
10314
|
+
return reasons;
|
|
10315
|
+
}
|
|
10316
|
+
var SUP_RESIDUE, ANGLE_DEG;
|
|
10317
|
+
var init_detectFormulaRisk = __esm({
|
|
10318
|
+
"src/stamps/geometry-2d/ai/vision/detectFormulaRisk.ts"() {
|
|
10319
|
+
SUP_RESIDUE = /[A-Z0-9]\?(?=\s*[-=+)(])/u;
|
|
10320
|
+
ANGLE_DEG = /([\p{L}]{1,6})\s*=\s*\d+\s*°/gu;
|
|
10321
|
+
}
|
|
10322
|
+
});
|
|
10323
|
+
|
|
9591
10324
|
// src/stamps/geometry-2d/ai/vision/extractProblem.ts
|
|
9592
10325
|
async function extractProblemFromImage(image, opts = {}) {
|
|
9593
10326
|
let raw;
|
|
@@ -9615,6 +10348,7 @@ async function extractProblemFromImage(image, opts = {}) {
|
|
|
9615
10348
|
ok: true,
|
|
9616
10349
|
text,
|
|
9617
10350
|
confidence,
|
|
10351
|
+
warnings: detectFormulaRisk(text),
|
|
9618
10352
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
9619
10353
|
};
|
|
9620
10354
|
}
|
|
@@ -9626,6 +10360,7 @@ function postProcess(raw) {
|
|
|
9626
10360
|
t = t.replace(/```[\s\S]*?```/g, "").replace(/`([^`]+)`/g, "$1");
|
|
9627
10361
|
t = t.replace(/\s+/g, " ").trim();
|
|
9628
10362
|
t = t.normalize("NFC");
|
|
10363
|
+
t = repairOcrSymbols(t);
|
|
9629
10364
|
if (t.length > MAX_TEXT_CHARS) t = t.slice(0, MAX_TEXT_CHARS);
|
|
9630
10365
|
return t;
|
|
9631
10366
|
}
|
|
@@ -9633,6 +10368,8 @@ var MIN_HIGH_CONFIDENCE_CHARS, MAX_TEXT_CHARS, TESSERACT_HIGH_CONFIDENCE_THRESHO
|
|
|
9633
10368
|
var init_extractProblem = __esm({
|
|
9634
10369
|
"src/stamps/geometry-2d/ai/vision/extractProblem.ts"() {
|
|
9635
10370
|
init_tesseract();
|
|
10371
|
+
init_repairOcrSymbols();
|
|
10372
|
+
init_detectFormulaRisk();
|
|
9636
10373
|
MIN_HIGH_CONFIDENCE_CHARS = 10;
|
|
9637
10374
|
MAX_TEXT_CHARS = 2e3;
|
|
9638
10375
|
TESSERACT_HIGH_CONFIDENCE_THRESHOLD = 70;
|
|
@@ -9644,6 +10381,14 @@ async function handleExtractProblem(image, opts = {}) {
|
|
|
9644
10381
|
try {
|
|
9645
10382
|
const r = await extractProblemFromImage(image, opts);
|
|
9646
10383
|
if (r.ok) {
|
|
10384
|
+
if (r.warnings.length > 0) {
|
|
10385
|
+
return {
|
|
10386
|
+
kind: "low-confidence",
|
|
10387
|
+
text: r.text,
|
|
10388
|
+
warning: `C\xF3 th\u1EC3 c\xF3 c\xF4ng th\u1EE9c/k\xFD hi\u1EC7u b\u1ECB nh\u1EADn d\u1EA1ng sai (${r.warnings.join("; ")}). Ki\u1EC3m tra k\u1EF9 tr\u01B0\u1EDBc khi v\u1EBD.`,
|
|
10389
|
+
usage: r.usage
|
|
10390
|
+
};
|
|
10391
|
+
}
|
|
9647
10392
|
if (r.confidence === "low") {
|
|
9648
10393
|
return {
|
|
9649
10394
|
kind: "low-confidence",
|
|
@@ -9708,9 +10453,9 @@ async function fileToImagePart(file) {
|
|
|
9708
10453
|
const bitmap = await createImageBitmap(file);
|
|
9709
10454
|
const { width, height } = bitmap;
|
|
9710
10455
|
const maxEdge = Math.max(width, height);
|
|
9711
|
-
const
|
|
9712
|
-
const targetW = Math.round(width *
|
|
9713
|
-
const targetH = Math.round(height *
|
|
10456
|
+
const scale2 = maxEdge > MAX_EDGE_PX ? MAX_EDGE_PX / maxEdge : 1;
|
|
10457
|
+
const targetW = Math.round(width * scale2);
|
|
10458
|
+
const targetH = Math.round(height * scale2);
|
|
9714
10459
|
const canvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(targetW, targetH) : Object.assign(document.createElement("canvas"), { width: targetW, height: targetH });
|
|
9715
10460
|
const ctx = canvas.getContext("2d");
|
|
9716
10461
|
if (!ctx) throw new Error("Kh\xF4ng t\u1EA1o \u0111\u01B0\u1EE3c canvas 2D context");
|
|
@@ -10599,92 +11344,10 @@ var init_useChordShortcut = __esm({
|
|
|
10599
11344
|
A_CODE2 = "a".charCodeAt(0);
|
|
10600
11345
|
}
|
|
10601
11346
|
});
|
|
10602
|
-
|
|
10603
|
-
// src/stamps/shared/insertImage.ts
|
|
10604
|
-
function buildStampImageElement(api, fileId, width, height, customData, x, y) {
|
|
10605
|
-
const appState = api?.getAppState() ?? { scrollX: 0, scrollY: 0, width: 800, height: 600, zoom: { value: 1 } };
|
|
10606
|
-
const cx = x ?? appState.scrollX + (appState.width ?? 800) / 2 / (appState.zoom?.value ?? 1) - width / 2;
|
|
10607
|
-
const cy = y ?? appState.scrollY + (appState.height ?? 600) / 2 / (appState.zoom?.value ?? 1) - height / 2;
|
|
10608
|
-
return {
|
|
10609
|
-
type: "image",
|
|
10610
|
-
id: "stamp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8),
|
|
10611
|
-
x: cx,
|
|
10612
|
-
y: cy,
|
|
10613
|
-
width,
|
|
10614
|
-
height,
|
|
10615
|
-
fileId,
|
|
10616
|
-
customData,
|
|
10617
|
-
angle: 0,
|
|
10618
|
-
strokeColor: "transparent",
|
|
10619
|
-
backgroundColor: "transparent",
|
|
10620
|
-
fillStyle: "solid",
|
|
10621
|
-
strokeWidth: 1,
|
|
10622
|
-
strokeStyle: "solid",
|
|
10623
|
-
roughness: 0,
|
|
10624
|
-
opacity: 100,
|
|
10625
|
-
groupIds: [],
|
|
10626
|
-
roundness: null,
|
|
10627
|
-
seed: Math.floor(Math.random() * 1e9),
|
|
10628
|
-
versionNonce: 0,
|
|
10629
|
-
version: 1,
|
|
10630
|
-
isDeleted: false,
|
|
10631
|
-
boundElements: null,
|
|
10632
|
-
updated: Date.now(),
|
|
10633
|
-
link: null,
|
|
10634
|
-
locked: false,
|
|
10635
|
-
status: "saved",
|
|
10636
|
-
scale: [1, 1]
|
|
10637
|
-
};
|
|
10638
|
-
}
|
|
10639
|
-
async function insertStampImage(api, opts) {
|
|
10640
|
-
const { dataURL, fileId, width, height, mimeType } = await createStampFile(opts.svgString);
|
|
10641
|
-
api.addFiles([{ id: fileId, dataURL, mimeType, created: Date.now() }]);
|
|
10642
|
-
const customData = opts.makeCustomData();
|
|
10643
|
-
const elements = api.getSceneElements();
|
|
10644
|
-
const editingId = opts.editingElementId ?? null;
|
|
10645
|
-
if (editingId) {
|
|
10646
|
-
const old = elements.find((e) => e.id === editingId) ;
|
|
10647
|
-
const oldLongest = old ? Math.max(old.width ?? 0, old.height ?? 0) : 0;
|
|
10648
|
-
const newLongest = Math.max(width, height);
|
|
10649
|
-
const scale = oldLongest > 0 && newLongest > 0 ? oldLongest / newLongest : 1;
|
|
10650
|
-
const w = width * scale;
|
|
10651
|
-
const h = height * scale;
|
|
10652
|
-
const updated = elements.map(
|
|
10653
|
-
(e) => e.id === editingId ? { ...e, fileId, customData, width: w, height: h } : e
|
|
10654
|
-
);
|
|
10655
|
-
api.updateScene({ elements: updated, appState: clearAppStateAfterInsert() });
|
|
10656
|
-
return { fileId, width: w, height: h, elementId: editingId };
|
|
10657
|
-
}
|
|
10658
|
-
const newElement = buildStampImageElement(
|
|
10659
|
-
api,
|
|
10660
|
-
fileId,
|
|
10661
|
-
width,
|
|
10662
|
-
height,
|
|
10663
|
-
customData,
|
|
10664
|
-
opts.position?.x,
|
|
10665
|
-
opts.position?.y
|
|
10666
|
-
);
|
|
10667
|
-
api.updateScene({
|
|
10668
|
-
elements: [...elements, newElement],
|
|
10669
|
-
appState: clearAppStateAfterInsert()
|
|
10670
|
-
});
|
|
10671
|
-
return { fileId, width, height, elementId: newElement.id };
|
|
10672
|
-
}
|
|
10673
|
-
var clearAppStateAfterInsert;
|
|
10674
|
-
var init_insertImage = __esm({
|
|
10675
|
-
"src/stamps/shared/insertImage.ts"() {
|
|
10676
|
-
init_svgToStampFile();
|
|
10677
|
-
clearAppStateAfterInsert = () => ({
|
|
10678
|
-
selectedElementIds: {},
|
|
10679
|
-
croppingElementId: null
|
|
10680
|
-
});
|
|
10681
|
-
}
|
|
10682
|
-
});
|
|
10683
|
-
function useStampStore(domain, editingElement, parseInitial) {
|
|
11347
|
+
function useStampStore(domain, makeInitialState) {
|
|
10684
11348
|
const ref = React2.useRef(null);
|
|
10685
11349
|
if (!ref.current) {
|
|
10686
|
-
|
|
10687
|
-
ref.current = createStore(initial);
|
|
11350
|
+
ref.current = createStore(makeInitialState?.() ?? createEmptyState(domain));
|
|
10688
11351
|
}
|
|
10689
11352
|
return ref.current;
|
|
10690
11353
|
}
|
|
@@ -10857,6 +11520,21 @@ function serializePoint(obj, state) {
|
|
|
10857
11520
|
entity: { name: obj.label, kind: "pointAtDistance", from: refs[0], through: refs[1], distance }
|
|
10858
11521
|
};
|
|
10859
11522
|
}
|
|
11523
|
+
case "commonTangentPoint": {
|
|
11524
|
+
const refs = resolveRefs([c.circles[0], c.circles[1]], state);
|
|
11525
|
+
if (!refs) return fail("unresolved-ref", `${c.circles[0]},${c.circles[1]}`);
|
|
11526
|
+
return {
|
|
11527
|
+
ok: true,
|
|
11528
|
+
entity: {
|
|
11529
|
+
name: obj.label,
|
|
11530
|
+
kind: "commonTangentPoint",
|
|
11531
|
+
circles: [refs[0], refs[1]],
|
|
11532
|
+
on: c.on,
|
|
11533
|
+
variant: c.variant,
|
|
11534
|
+
side: c.side
|
|
11535
|
+
}
|
|
11536
|
+
};
|
|
11537
|
+
}
|
|
10860
11538
|
// Out of DSL v1:
|
|
10861
11539
|
case "onAxis":
|
|
10862
11540
|
case "onPolygon":
|
|
@@ -11184,6 +11862,10 @@ function describeEntity(e) {
|
|
|
11184
11862
|
}
|
|
11185
11863
|
case "onPerpBisector":
|
|
11186
11864
|
return `${e.name} = \u0111i\u1EC3m tr\xEAn trung tr\u1EF1c ${e.p1}${e.p2}`;
|
|
11865
|
+
case "commonTangentPoint": {
|
|
11866
|
+
const v = e.variant === "internal" ? "trong" : "ngo\xE0i";
|
|
11867
|
+
return `${e.name} = ti\u1EBFp \u0111i\u1EC3m ti\u1EBFp tuy\u1EBFn chung ${v} ${e.circles[0]},${e.circles[1]} (tr\xEAn ${e.circles[e.on]})`;
|
|
11868
|
+
}
|
|
11187
11869
|
default: {
|
|
11188
11870
|
return "";
|
|
11189
11871
|
}
|
|
@@ -11242,38 +11924,29 @@ var init_dslRenderRow = __esm({
|
|
|
11242
11924
|
init_describeDsl();
|
|
11243
11925
|
}
|
|
11244
11926
|
});
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
__export(host_exports, {
|
|
11249
|
-
GeometryStampHost: () => GeometryStampHost
|
|
11250
|
-
});
|
|
11251
|
-
function parseInitialState(data) {
|
|
11252
|
-
if (!isGeometryCustomData(data)) return null;
|
|
11253
|
-
return deserializeBoard(data.jsonState);
|
|
11254
|
-
}
|
|
11255
|
-
var GeometryStampHost;
|
|
11256
|
-
var init_host = __esm({
|
|
11257
|
-
"src/stamps/geometry-2d/host.tsx"() {
|
|
11927
|
+
var GeometryStudio;
|
|
11928
|
+
var init_GeometryStudio = __esm({
|
|
11929
|
+
"src/stamps/geometry-2d/studio/GeometryStudio.tsx"() {
|
|
11258
11930
|
"use client";
|
|
11259
11931
|
init_StampLeftPanel();
|
|
11260
11932
|
init_icons();
|
|
11261
11933
|
init_EditorPanel();
|
|
11262
11934
|
init_tools();
|
|
11263
11935
|
init_useChordShortcut();
|
|
11264
|
-
init_insertImage();
|
|
11265
11936
|
init_serialize();
|
|
11266
|
-
init_types3();
|
|
11267
11937
|
init_scene();
|
|
11268
11938
|
init_useIsMobile();
|
|
11269
11939
|
init_useStampStore();
|
|
11270
11940
|
init_dslRenderRow();
|
|
11271
|
-
|
|
11272
|
-
function
|
|
11941
|
+
GeometryStudio = React2.forwardRef(
|
|
11942
|
+
function GeometryStudio2({ initialJsonState, onCommit, onClose, isDark, api, generateGeometryFigure, onGeometryDraft }, ref) {
|
|
11273
11943
|
const panelRef = React2.useRef(null);
|
|
11274
11944
|
const { isMobile } = useIsMobile();
|
|
11275
11945
|
const [drawerOpen, setDrawerOpen] = React2.useState(false);
|
|
11276
|
-
const sceneStore = useStampStore(
|
|
11946
|
+
const sceneStore = useStampStore(
|
|
11947
|
+
"2d",
|
|
11948
|
+
() => initialJsonState ? deserializeBoard(initialJsonState) : null
|
|
11949
|
+
);
|
|
11277
11950
|
const initialMeta = sceneStore.getState().meta;
|
|
11278
11951
|
const initialView = initialMeta.domain === "2d" ? initialMeta.view : DEFAULT_VIEW_2D;
|
|
11279
11952
|
const [selectedTool, setSelectedTool] = React2.useState("move");
|
|
@@ -11297,24 +11970,15 @@ var init_host = __esm({
|
|
|
11297
11970
|
const renderRow = React2.useMemo(() => makeDslRenderRow(sceneStore), [sceneStore]);
|
|
11298
11971
|
const handleInsert = React2.useCallback(
|
|
11299
11972
|
async (jsonState, svgString) => {
|
|
11300
|
-
if (!api) return;
|
|
11301
11973
|
try {
|
|
11302
|
-
await
|
|
11303
|
-
|
|
11304
|
-
makeCustomData: () => ({
|
|
11305
|
-
kind: "geometry",
|
|
11306
|
-
version: 1,
|
|
11307
|
-
jsonState
|
|
11308
|
-
}),
|
|
11309
|
-
editingElementId: editingElement?.id ?? null,
|
|
11310
|
-
preserveExistingSize: true
|
|
11311
|
-
});
|
|
11974
|
+
const committed = await onCommit(jsonState, svgString);
|
|
11975
|
+
if (committed === false) return;
|
|
11312
11976
|
} catch (err) {
|
|
11313
|
-
console.error("Geometry
|
|
11977
|
+
console.error("Geometry commit failed:", err);
|
|
11314
11978
|
}
|
|
11315
11979
|
onClose();
|
|
11316
11980
|
},
|
|
11317
|
-
[
|
|
11981
|
+
[onCommit, onClose]
|
|
11318
11982
|
);
|
|
11319
11983
|
React2.useImperativeHandle(
|
|
11320
11984
|
ref,
|
|
@@ -11396,6 +12060,137 @@ var init_host = __esm({
|
|
|
11396
12060
|
}
|
|
11397
12061
|
});
|
|
11398
12062
|
|
|
12063
|
+
// src/stamps/shared/insertImage.ts
|
|
12064
|
+
function buildStampImageElement(api, fileId, width, height, customData, x, y) {
|
|
12065
|
+
const appState = api?.getAppState() ?? { scrollX: 0, scrollY: 0, width: 800, height: 600, zoom: { value: 1 } };
|
|
12066
|
+
const cx = x ?? appState.scrollX + (appState.width ?? 800) / 2 / (appState.zoom?.value ?? 1) - width / 2;
|
|
12067
|
+
const cy = y ?? appState.scrollY + (appState.height ?? 600) / 2 / (appState.zoom?.value ?? 1) - height / 2;
|
|
12068
|
+
return {
|
|
12069
|
+
type: "image",
|
|
12070
|
+
id: "stamp_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8),
|
|
12071
|
+
x: cx,
|
|
12072
|
+
y: cy,
|
|
12073
|
+
width,
|
|
12074
|
+
height,
|
|
12075
|
+
fileId,
|
|
12076
|
+
customData,
|
|
12077
|
+
angle: 0,
|
|
12078
|
+
strokeColor: "transparent",
|
|
12079
|
+
backgroundColor: "transparent",
|
|
12080
|
+
fillStyle: "solid",
|
|
12081
|
+
strokeWidth: 1,
|
|
12082
|
+
strokeStyle: "solid",
|
|
12083
|
+
roughness: 0,
|
|
12084
|
+
opacity: 100,
|
|
12085
|
+
groupIds: [],
|
|
12086
|
+
roundness: null,
|
|
12087
|
+
seed: Math.floor(Math.random() * 1e9),
|
|
12088
|
+
versionNonce: 0,
|
|
12089
|
+
version: 1,
|
|
12090
|
+
isDeleted: false,
|
|
12091
|
+
boundElements: null,
|
|
12092
|
+
updated: Date.now(),
|
|
12093
|
+
link: null,
|
|
12094
|
+
locked: false,
|
|
12095
|
+
status: "saved",
|
|
12096
|
+
scale: [1, 1]
|
|
12097
|
+
};
|
|
12098
|
+
}
|
|
12099
|
+
async function insertStampImage(api, opts) {
|
|
12100
|
+
const { dataURL, fileId, width, height, mimeType } = await createStampFile(opts.svgString);
|
|
12101
|
+
api.addFiles([{ id: fileId, dataURL, mimeType, created: Date.now() }]);
|
|
12102
|
+
const customData = opts.makeCustomData();
|
|
12103
|
+
const elements = api.getSceneElements();
|
|
12104
|
+
const editingId = opts.editingElementId ?? null;
|
|
12105
|
+
if (editingId) {
|
|
12106
|
+
const old = elements.find((e) => e.id === editingId) ;
|
|
12107
|
+
const oldLongest = old ? Math.max(old.width ?? 0, old.height ?? 0) : 0;
|
|
12108
|
+
const newLongest = Math.max(width, height);
|
|
12109
|
+
const scale2 = oldLongest > 0 && newLongest > 0 ? oldLongest / newLongest : 1;
|
|
12110
|
+
const w = width * scale2;
|
|
12111
|
+
const h = height * scale2;
|
|
12112
|
+
const updated = elements.map(
|
|
12113
|
+
(e) => e.id === editingId ? { ...e, fileId, customData, width: w, height: h } : e
|
|
12114
|
+
);
|
|
12115
|
+
api.updateScene({ elements: updated, appState: clearAppStateAfterInsert() });
|
|
12116
|
+
return { fileId, width: w, height: h, elementId: editingId };
|
|
12117
|
+
}
|
|
12118
|
+
const newElement = buildStampImageElement(
|
|
12119
|
+
api,
|
|
12120
|
+
fileId,
|
|
12121
|
+
width,
|
|
12122
|
+
height,
|
|
12123
|
+
customData,
|
|
12124
|
+
opts.position?.x,
|
|
12125
|
+
opts.position?.y
|
|
12126
|
+
);
|
|
12127
|
+
api.updateScene({
|
|
12128
|
+
elements: [...elements, newElement],
|
|
12129
|
+
appState: clearAppStateAfterInsert()
|
|
12130
|
+
});
|
|
12131
|
+
return { fileId, width, height, elementId: newElement.id };
|
|
12132
|
+
}
|
|
12133
|
+
var clearAppStateAfterInsert;
|
|
12134
|
+
var init_insertImage = __esm({
|
|
12135
|
+
"src/stamps/shared/insertImage.ts"() {
|
|
12136
|
+
init_svgToStampFile();
|
|
12137
|
+
clearAppStateAfterInsert = () => ({
|
|
12138
|
+
selectedElementIds: {},
|
|
12139
|
+
croppingElementId: null
|
|
12140
|
+
});
|
|
12141
|
+
}
|
|
12142
|
+
});
|
|
12143
|
+
|
|
12144
|
+
// src/stamps/geometry-2d/host.tsx
|
|
12145
|
+
var host_exports = {};
|
|
12146
|
+
__export(host_exports, {
|
|
12147
|
+
GeometryStampHost: () => GeometryStampHost
|
|
12148
|
+
});
|
|
12149
|
+
var GeometryStampHost;
|
|
12150
|
+
var init_host = __esm({
|
|
12151
|
+
"src/stamps/geometry-2d/host.tsx"() {
|
|
12152
|
+
"use client";
|
|
12153
|
+
init_GeometryStudio();
|
|
12154
|
+
init_insertImage();
|
|
12155
|
+
init_types3();
|
|
12156
|
+
GeometryStampHost = React2.forwardRef(
|
|
12157
|
+
function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure, onGeometryDraft }, ref) {
|
|
12158
|
+
const initialJsonState = isGeometryCustomData(editingElement?.customData) ? editingElement.customData.jsonState : void 0;
|
|
12159
|
+
const handleCommit = React2.useCallback(
|
|
12160
|
+
async (jsonState, svgString) => {
|
|
12161
|
+
if (!api) return false;
|
|
12162
|
+
await insertStampImage(api, {
|
|
12163
|
+
svgString,
|
|
12164
|
+
makeCustomData: () => ({
|
|
12165
|
+
kind: "geometry",
|
|
12166
|
+
version: 1,
|
|
12167
|
+
jsonState
|
|
12168
|
+
}),
|
|
12169
|
+
editingElementId: editingElement?.id ?? null,
|
|
12170
|
+
preserveExistingSize: true
|
|
12171
|
+
});
|
|
12172
|
+
return true;
|
|
12173
|
+
},
|
|
12174
|
+
[api, editingElement?.id]
|
|
12175
|
+
);
|
|
12176
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12177
|
+
GeometryStudio,
|
|
12178
|
+
{
|
|
12179
|
+
ref,
|
|
12180
|
+
initialJsonState,
|
|
12181
|
+
onCommit: handleCommit,
|
|
12182
|
+
onClose,
|
|
12183
|
+
isDark,
|
|
12184
|
+
api,
|
|
12185
|
+
generateGeometryFigure,
|
|
12186
|
+
onGeometryDraft
|
|
12187
|
+
}
|
|
12188
|
+
);
|
|
12189
|
+
}
|
|
12190
|
+
);
|
|
12191
|
+
}
|
|
12192
|
+
});
|
|
12193
|
+
|
|
11399
12194
|
// src/stamps/geometry-2d/index.tsx
|
|
11400
12195
|
init_render();
|
|
11401
12196
|
init_svgToStampFile();
|