@pixerate/editor 0.132.0 → 0.133.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/animation-editor/index.cjs +55 -55
- package/dist/animation-editor/index.d.cts +4 -4
- package/dist/animation-editor/index.d.ts +4 -4
- package/dist/animation-editor/index.js +2 -2
- package/dist/{bezier-0IHDCvv_.d.ts → bezier-BAGdL89w.d.ts} +1 -1
- package/dist/{bezier-oCBfrGDG.d.cts → bezier-DL2wPsFf.d.cts} +1 -1
- package/dist/canvas/index.d.cts +7 -7
- package/dist/canvas/index.d.ts +7 -7
- package/dist/{chunk-MZXQTKUM.cjs → chunk-24ATT2PE.cjs} +10 -6
- package/dist/chunk-24ATT2PE.cjs.map +1 -0
- package/dist/{chunk-AHUYMDYW.js → chunk-2HC4DRF4.js} +10 -6
- package/dist/chunk-2HC4DRF4.js.map +1 -0
- package/dist/{chunk-OYPJGGF3.cjs → chunk-2QKUD3E2.cjs} +36 -36
- package/dist/{chunk-OYPJGGF3.cjs.map → chunk-2QKUD3E2.cjs.map} +1 -1
- package/dist/{chunk-55UEZIU4.cjs → chunk-65GNHOD4.cjs} +231 -191
- package/dist/chunk-65GNHOD4.cjs.map +1 -0
- package/dist/{chunk-YRZ6NVE3.js → chunk-6CTZAGZ2.js} +235 -4
- package/dist/chunk-6CTZAGZ2.js.map +1 -0
- package/dist/{chunk-G5FX56KX.js → chunk-AOCFL7L7.js} +51 -11
- package/dist/chunk-AOCFL7L7.js.map +1 -0
- package/dist/{chunk-YYJKIESX.cjs → chunk-F7GGEAO2.cjs} +4 -2
- package/dist/chunk-F7GGEAO2.cjs.map +1 -0
- package/dist/{chunk-IEYXYMRQ.js → chunk-FOBB6AIO.js} +3 -1
- package/dist/chunk-FOBB6AIO.js.map +1 -0
- package/dist/{chunk-W6M7C7R3.cjs → chunk-NVTHUPJ6.cjs} +236 -5
- package/dist/chunk-NVTHUPJ6.cjs.map +1 -0
- package/dist/{chunk-ECVI5QRE.js → chunk-VGZSIXX3.js} +2 -2
- package/dist/effects/index.d.cts +4 -4
- package/dist/effects/index.d.ts +4 -4
- package/dist/{export-D-gkjBkB.d.cts → export-BICOEM9d.d.cts} +10 -10
- package/dist/{export-CfAogLEr.d.cts → export-CeFplzAW.d.cts} +1 -1
- package/dist/{export-ByJvAvR7.d.ts → export-XnuX8FZ2.d.ts} +10 -10
- package/dist/{export-Crl82sbE.d.ts → export-zB4HITwP.d.ts} +1 -1
- package/dist/{helpers-CoIeXQnW.d.cts → helpers-BuKdqUlM.d.cts} +23 -1
- package/dist/{helpers-BCd2-PAR.d.ts → helpers-cssRNUzH.d.ts} +23 -1
- package/dist/image-editor/index.cjs +983 -874
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +32 -13
- package/dist/image-editor/index.d.ts +32 -13
- package/dist/image-editor/index.js +124 -15
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{opentype-BDahNRTe.d.cts → opentype-C3iyIFRx.d.cts} +1 -1
- package/dist/{opentype-BQFEvy-t.d.ts → opentype-DG5Lkwul.d.ts} +1 -1
- package/dist/paint/index.cjs +8 -2
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +14 -3
- package/dist/paint/index.d.ts +14 -3
- package/dist/paint/index.js +7 -1
- package/dist/paint-editor/index.cjs +78 -78
- package/dist/paint-editor/index.d.cts +7 -7
- package/dist/paint-editor/index.d.ts +7 -7
- package/dist/paint-editor/index.js +3 -3
- package/dist/{pathfinder-01ZgAwqV.d.cts → pathfinder-8vXik95z.d.cts} +1 -1
- package/dist/{pathfinder-DaVdT8jq.d.ts → pathfinder-DKLt4UDG.d.ts} +1 -1
- package/dist/{pool-D2A3WTt9.d.ts → pool-C69pkWRz.d.ts} +1 -1
- package/dist/{pool-D6a45MoE.d.cts → pool-VAWcYUbs.d.cts} +1 -1
- package/dist/{rand-pQQ2sJTk.d.ts → rand-BaqEOs1Y.d.ts} +17 -4
- package/dist/{rand-DTXAssW1.d.cts → rand-DdpFzCo6.d.cts} +17 -4
- package/dist/raster/index.cjs +2 -2
- package/dist/raster/index.d.cts +4 -4
- package/dist/raster/index.d.ts +4 -4
- package/dist/raster/index.js +1 -1
- package/dist/{svg-CcDz7Zq2.d.cts → svg-BThlZmja.d.cts} +2 -2
- package/dist/{svg-DELNVerw.d.ts → svg-CEYpvsgH.d.ts} +2 -2
- package/dist/{tools-BFvkFnRj.d.cts → tools-CRnZJXXr.d.cts} +1 -1
- package/dist/{tools-D7ws-OKL.d.ts → tools-CVGqEpO8.d.ts} +1 -1
- package/dist/vector/index.cjs +1383 -1044
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +102 -12
- package/dist/vector/index.d.ts +102 -12
- package/dist/vector/index.js +342 -3
- package/dist/vector/index.js.map +1 -1
- package/dist/video-editor/index.d.cts +4 -4
- package/dist/video-editor/index.d.ts +4 -4
- package/dist/{warp-DErXW5rz.d.cts → warp-ChcFDdlT.d.cts} +1 -1
- package/dist/{warp-2N9wkOkL.d.ts → warp-mKylbLiF.d.ts} +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +1 -1
- package/skills/pixerate-image-editor/references/retouching.md +3 -2
- package/dist/chunk-55UEZIU4.cjs.map +0 -1
- package/dist/chunk-AHUYMDYW.js.map +0 -1
- package/dist/chunk-G5FX56KX.js.map +0 -1
- package/dist/chunk-IEYXYMRQ.js.map +0 -1
- package/dist/chunk-MZXQTKUM.cjs.map +0 -1
- package/dist/chunk-W6M7C7R3.cjs.map +0 -1
- package/dist/chunk-YRZ6NVE3.js.map +0 -1
- package/dist/chunk-YYJKIESX.cjs.map +0 -1
- /package/dist/{chunk-ECVI5QRE.js.map → chunk-VGZSIXX3.js.map} +0 -0
package/dist/vector/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
applyHomography,
|
|
13
13
|
homographyFromPoints,
|
|
14
14
|
homographyKeepsQuad,
|
|
15
|
+
invertHomography,
|
|
15
16
|
orderQuad,
|
|
16
17
|
solve8
|
|
17
18
|
} from "../chunk-GX332W2C.js";
|
|
@@ -42,7 +43,7 @@ import {
|
|
|
42
43
|
reverseMorphContour,
|
|
43
44
|
subpathToMorphContour,
|
|
44
45
|
turnMorphContour
|
|
45
|
-
} from "../chunk-
|
|
46
|
+
} from "../chunk-VGZSIXX3.js";
|
|
46
47
|
import {
|
|
47
48
|
DEFAULT_VECTOR_FONT,
|
|
48
49
|
IDENTITY_MATRIX,
|
|
@@ -83,6 +84,7 @@ import {
|
|
|
83
84
|
VECTOR_PARAGRAPH_STYLE_KEYS,
|
|
84
85
|
VECTOR_PATHFINDER_OPERATIONS,
|
|
85
86
|
VECTOR_PATH_TEXT_BASELINES,
|
|
87
|
+
VECTOR_PERSPECTIVE_PLANES,
|
|
86
88
|
VECTOR_PRESSURE_NOMINAL,
|
|
87
89
|
VECTOR_SPATIAL_MIN,
|
|
88
90
|
VECTOR_STROKE_GRADIENT_MODES,
|
|
@@ -493,7 +495,7 @@ import {
|
|
|
493
495
|
withVectorStrokes,
|
|
494
496
|
withVectorTargetPaint,
|
|
495
497
|
zigzagPaths
|
|
496
|
-
} from "../chunk-
|
|
498
|
+
} from "../chunk-FOBB6AIO.js";
|
|
497
499
|
import {
|
|
498
500
|
bezierPathBounds,
|
|
499
501
|
bezierPathToSvg,
|
|
@@ -834,6 +836,131 @@ function releaseVectorBlend(group, newId) {
|
|
|
834
836
|
return [...keys, group.transform ? transformVectorNode(path, m) : path];
|
|
835
837
|
}
|
|
836
838
|
|
|
839
|
+
// src/vector/perspective.ts
|
|
840
|
+
function vectorPerspectivePlanes(p) {
|
|
841
|
+
return p.vanishingPoints.length <= 1 ? ["floor", "side", "front"] : ["floor", "left", "right"];
|
|
842
|
+
}
|
|
843
|
+
function sanitizeVectorPerspective(value) {
|
|
844
|
+
if (!value || typeof value !== "object") return null;
|
|
845
|
+
const r = value;
|
|
846
|
+
const isPt = (v) => !!v && typeof v === "object" && Number.isFinite(v.x) && Number.isFinite(v.y);
|
|
847
|
+
if (!Array.isArray(r.vanishingPoints) || r.vanishingPoints.length < 1 || r.vanishingPoints.length > 3 || !r.vanishingPoints.every(isPt) || !isPt(r.origin)) return null;
|
|
848
|
+
const origin = { x: r.origin.x, y: r.origin.y };
|
|
849
|
+
const vps = r.vanishingPoints.map((v) => ({ x: v.x, y: v.y }));
|
|
850
|
+
if (vps.some((v) => Math.hypot(v.x - origin.x, v.y - origin.y) < 1e-6)) return null;
|
|
851
|
+
const out = { vanishingPoints: vps, origin };
|
|
852
|
+
if (typeof r.gridSize === "number" && r.gridSize > 0 && Number.isFinite(r.gridSize)) out.gridSize = Math.min(1e3, r.gridSize);
|
|
853
|
+
if (typeof r.extent === "number" && Number.isFinite(r.extent)) out.extent = Math.min(100, Math.max(1, Math.round(r.extent)));
|
|
854
|
+
if (r.visible === false) out.visible = false;
|
|
855
|
+
return out;
|
|
856
|
+
}
|
|
857
|
+
function towards(o, vp, want) {
|
|
858
|
+
const d = Math.hypot(vp.x - o.x, vp.y - o.y);
|
|
859
|
+
let a = 1 / d;
|
|
860
|
+
if (want === "right" ? vp.x - o.x < 0 : vp.y - o.y > 0) a = -a;
|
|
861
|
+
return [a * vp.x, a * vp.y, a];
|
|
862
|
+
}
|
|
863
|
+
function vectorPerspectivePlaneMap(p, plane) {
|
|
864
|
+
if (!vectorPerspectivePlanes(p).includes(plane)) return null;
|
|
865
|
+
const o = p.origin;
|
|
866
|
+
const [v1, v2, v3] = p.vanishingPoints;
|
|
867
|
+
const right = [1, 0, 0];
|
|
868
|
+
const up = v3 ? towards(o, v3, "up") : [0, -1, 0];
|
|
869
|
+
let x;
|
|
870
|
+
let y;
|
|
871
|
+
if (p.vanishingPoints.length <= 1) {
|
|
872
|
+
if (plane === "floor") [x, y] = [right, towards(o, v1, "up")];
|
|
873
|
+
else if (plane === "side") [x, y] = [towards(o, v1, "right"), up];
|
|
874
|
+
else [x, y] = [right, up];
|
|
875
|
+
} else if (plane === "floor") [x, y] = [towards(o, v2, "right"), towards(o, v1, "up")];
|
|
876
|
+
else if (plane === "left") [x, y] = [towards(o, v1, "right"), up];
|
|
877
|
+
else [x, y] = [towards(o, v2, "right"), up];
|
|
878
|
+
return [x[0], y[0], o.x, x[1], y[1], o.y, x[2], y[2], 1];
|
|
879
|
+
}
|
|
880
|
+
function vectorPerspectiveFlatToPlane(p, plane) {
|
|
881
|
+
const h = vectorPerspectivePlaneMap(p, plane);
|
|
882
|
+
if (!h) return null;
|
|
883
|
+
const o = p.origin;
|
|
884
|
+
return (q) => {
|
|
885
|
+
const u = q.x - o.x;
|
|
886
|
+
const v = o.y - q.y;
|
|
887
|
+
const w = h[6] * u + h[7] * v + h[8];
|
|
888
|
+
if (!(w > 1e-6)) return null;
|
|
889
|
+
return applyHomography(h, { x: u, y: v });
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
function vectorPerspectivePlaneToFlat(p, plane) {
|
|
893
|
+
const h = vectorPerspectivePlaneMap(p, plane);
|
|
894
|
+
const inv = h ? invertHomography(h) : null;
|
|
895
|
+
if (!inv) return null;
|
|
896
|
+
const o = p.origin;
|
|
897
|
+
return (q) => {
|
|
898
|
+
const f = applyHomography(inv, q);
|
|
899
|
+
if (!f) return null;
|
|
900
|
+
const w = h[6] * f.x + h[7] * f.y + h[8];
|
|
901
|
+
if (!(w > 1e-6)) return null;
|
|
902
|
+
return { x: o.x + f.x, y: o.y - f.y };
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
function vectorPerspectiveMapPath(p, plane, path) {
|
|
906
|
+
const f = vectorPerspectiveFlatToPlane(p, plane);
|
|
907
|
+
if (!f) return null;
|
|
908
|
+
let behind = false;
|
|
909
|
+
const out = mapBezierPath(
|
|
910
|
+
path,
|
|
911
|
+
(q) => {
|
|
912
|
+
const r = f(q);
|
|
913
|
+
if (!r) {
|
|
914
|
+
behind = true;
|
|
915
|
+
return q;
|
|
916
|
+
}
|
|
917
|
+
return r;
|
|
918
|
+
},
|
|
919
|
+
0.1
|
|
920
|
+
);
|
|
921
|
+
return behind ? null : out;
|
|
922
|
+
}
|
|
923
|
+
function vectorPerspectiveGridLines(p, plane) {
|
|
924
|
+
const h = vectorPerspectivePlaneMap(p, plane);
|
|
925
|
+
if (!h) return [];
|
|
926
|
+
const g = p.gridSize ?? 20;
|
|
927
|
+
const n2 = p.extent ?? 12;
|
|
928
|
+
const max = n2 * g;
|
|
929
|
+
const lo = (axis) => axis === "y" && plane !== "floor" ? 0 : -max;
|
|
930
|
+
const w = (u, v) => h[6] * u + h[7] * v + h[8];
|
|
931
|
+
const at = (u, v) => applyHomography(h, { x: u, y: v });
|
|
932
|
+
const segment = (u0, v0, u1, v1) => {
|
|
933
|
+
const wa = w(u0, v0);
|
|
934
|
+
const wb = w(u1, v1);
|
|
935
|
+
const min = 0.05;
|
|
936
|
+
if (wa < min && wb < min) return null;
|
|
937
|
+
let t0 = 0;
|
|
938
|
+
let t1 = 1;
|
|
939
|
+
if (wa < min) t0 = (min - wa) / (wb - wa);
|
|
940
|
+
if (wb < min) t1 = (min - wa) / (wb - wa);
|
|
941
|
+
const a = at(u0 + (u1 - u0) * t0, v0 + (v1 - v0) * t0);
|
|
942
|
+
const b = at(u0 + (u1 - u0) * t1, v0 + (v1 - v0) * t1);
|
|
943
|
+
return a && b ? { a, b } : null;
|
|
944
|
+
};
|
|
945
|
+
const out = [];
|
|
946
|
+
for (let k = lo("x") / g; k <= n2; k++) {
|
|
947
|
+
const s = segment(k * g, lo("y"), k * g, max);
|
|
948
|
+
if (s) out.push(s);
|
|
949
|
+
}
|
|
950
|
+
for (let k = lo("y") / g; k <= n2; k++) {
|
|
951
|
+
const s = segment(lo("x"), k * g, max, k * g);
|
|
952
|
+
if (s) out.push(s);
|
|
953
|
+
}
|
|
954
|
+
return out;
|
|
955
|
+
}
|
|
956
|
+
function vectorPerspectivePreset(points, width, height) {
|
|
957
|
+
const horizon = height * 0.35;
|
|
958
|
+
const origin = { x: width / 2, y: height * 0.8 };
|
|
959
|
+
const vps = points === 1 ? [{ x: width / 2, y: horizon }] : [{ x: -width * 0.3, y: horizon }, { x: width * 1.3, y: horizon }];
|
|
960
|
+
if (points === 3) vps.push({ x: width / 2, y: height * 3 });
|
|
961
|
+
return { vanishingPoints: vps, origin, gridSize: Math.max(4, Math.round(Math.min(width, height) / 20)), extent: 12 };
|
|
962
|
+
}
|
|
963
|
+
|
|
837
964
|
// src/vector/constraints/lm.ts
|
|
838
965
|
var MAX_ROWS = 800;
|
|
839
966
|
var maxAbs = (v) => v.reduce((m, a) => Number.isFinite(a) ? Math.max(m, Math.abs(a)) : Infinity, 0);
|
|
@@ -2414,6 +2541,21 @@ function shadingOverlay(state) {
|
|
|
2414
2541
|
}
|
|
2415
2542
|
return out;
|
|
2416
2543
|
}
|
|
2544
|
+
function perspectiveOverlay(state) {
|
|
2545
|
+
const grid = state.document.perspective;
|
|
2546
|
+
if (!grid || grid.visible === false) return null;
|
|
2547
|
+
const r = (n2) => Math.round(n2 * 10) / 10;
|
|
2548
|
+
const planes = vectorPerspectivePlanes(grid).map((plane) => ({
|
|
2549
|
+
plane,
|
|
2550
|
+
active: state.perspectivePlane === plane,
|
|
2551
|
+
d: vectorPerspectiveGridLines(grid, plane).map(({ a, b }) => {
|
|
2552
|
+
const p = toScreen(state, a);
|
|
2553
|
+
const q = toScreen(state, b);
|
|
2554
|
+
return `M${r(p.x)} ${r(p.y)}L${r(q.x)} ${r(q.y)}`;
|
|
2555
|
+
}).join("")
|
|
2556
|
+
}));
|
|
2557
|
+
return { planes, vanishingPoints: grid.vanishingPoints.map((v) => toScreen(state, v)), origin: toScreen(state, grid.origin) };
|
|
2558
|
+
}
|
|
2417
2559
|
function symmetryOverlay(state) {
|
|
2418
2560
|
const ids = /* @__PURE__ */ new Set([...state.selection, ...state.symmetryTarget ? [state.symmetryTarget] : []]);
|
|
2419
2561
|
const out = [];
|
|
@@ -2727,6 +2869,7 @@ function getVectorOverlayRenderData(state) {
|
|
|
2727
2869
|
connectorSites: connectorSiteOverlay(state),
|
|
2728
2870
|
shading: shadingOverlay(state),
|
|
2729
2871
|
symmetry: symmetryOverlay(state),
|
|
2872
|
+
perspective: perspectiveOverlay(state),
|
|
2730
2873
|
trackingPoints: (state.trackingPoints ?? []).map((p) => toScreen(state, p)),
|
|
2731
2874
|
typedEntry: state.typedEntry ? { text: state.typedEntry, ...state.pointer ? toScreen(state, state.pointer) : { x: 0, y: 0 } } : null
|
|
2732
2875
|
};
|
|
@@ -6987,6 +7130,7 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
6987
7130
|
typedEntry: this.typed,
|
|
6988
7131
|
shadingPoint: this.getShadingSelection(),
|
|
6989
7132
|
symmetryTarget: this.symmetryTarget && this.doc.nodes.some((n2) => n2.id === this.symmetryTarget) ? this.symmetryTarget : null,
|
|
7133
|
+
perspectivePlane: this.perspectivePlane && this.doc.perspective && vectorPerspectivePlanes(this.doc.perspective).includes(this.perspectivePlane) ? this.perspectivePlane : null,
|
|
6990
7134
|
canUndo: h.canUndo,
|
|
6991
7135
|
canRedo: h.canRedo,
|
|
6992
7136
|
undoLabel: h.undoName,
|
|
@@ -9514,6 +9658,109 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
9514
9658
|
this.notify();
|
|
9515
9659
|
}
|
|
9516
9660
|
// -----------------------------------------------------------------------------------------
|
|
9661
|
+
// Perspective drawing
|
|
9662
|
+
perspectivePlane = null;
|
|
9663
|
+
/** The document's perspective grid, or null. */
|
|
9664
|
+
getPerspective() {
|
|
9665
|
+
return this.doc.perspective ?? null;
|
|
9666
|
+
}
|
|
9667
|
+
/**
|
|
9668
|
+
* Sets the document's perspective grid (CorelDRAW's Perspective Drawing): 1 to 3 vanishing
|
|
9669
|
+
* points, the origin where its planes meet, the cell size and extent, and whether it shows;
|
|
9670
|
+
* `null` removes it. One undo step.
|
|
9671
|
+
*/
|
|
9672
|
+
setPerspective(grid) {
|
|
9673
|
+
let next = null;
|
|
9674
|
+
if (grid) {
|
|
9675
|
+
next = sanitizeVectorPerspective(grid);
|
|
9676
|
+
if (!next) return { ok: false, message: "A perspective grid needs 1 to 3 vanishing points { x, y } away from an origin { x, y }." };
|
|
9677
|
+
}
|
|
9678
|
+
this.change(next ? "Perspective Grid" : "Remove Perspective Grid", () => {
|
|
9679
|
+
const { perspective: _p, ...rest } = this.doc;
|
|
9680
|
+
this.doc = next ? { ...rest, perspective: next } : rest;
|
|
9681
|
+
});
|
|
9682
|
+
if (!next) this.perspectivePlane = null;
|
|
9683
|
+
return { ok: true, perspective: next };
|
|
9684
|
+
}
|
|
9685
|
+
/**
|
|
9686
|
+
* Draws new rectangles, ellipses, polygons and stars on a plane of the perspective grid (their
|
|
9687
|
+
* drag box is taken on the plane, so they recede with it), or flat again with `null`.
|
|
9688
|
+
*/
|
|
9689
|
+
setPerspectivePlane(plane) {
|
|
9690
|
+
if (plane !== null) {
|
|
9691
|
+
const grid = this.doc.perspective;
|
|
9692
|
+
if (!grid) return { ok: false, message: "There is no perspective grid: set one with vector.setPerspective first." };
|
|
9693
|
+
const planes = vectorPerspectivePlanes(grid);
|
|
9694
|
+
if (!planes.includes(plane)) return { ok: false, message: `This grid's planes are ${planes.join(", ")}.` };
|
|
9695
|
+
}
|
|
9696
|
+
this.perspectivePlane = plane;
|
|
9697
|
+
this.notify();
|
|
9698
|
+
return { ok: true };
|
|
9699
|
+
}
|
|
9700
|
+
/**
|
|
9701
|
+
* Lays objects onto a plane of the perspective grid: each is read flat, relative to the grid's
|
|
9702
|
+
* origin (right and up), and projected onto the plane, so art near the origin keeps its size and
|
|
9703
|
+
* art further along recedes. Paths and groups are mapped in document space (their transforms
|
|
9704
|
+
* baked in); text and instances must be converted to outlines first. One undo step. Returns
|
|
9705
|
+
* the ids changed.
|
|
9706
|
+
*/
|
|
9707
|
+
attachToPerspective(plane, options = {}) {
|
|
9708
|
+
const grid = this.doc.perspective;
|
|
9709
|
+
if (!grid) return { ok: false, message: "There is no perspective grid: set one with vector.setPerspective first." };
|
|
9710
|
+
const planes = vectorPerspectivePlanes(grid);
|
|
9711
|
+
if (!planes.includes(plane)) return { ok: false, message: `This grid's planes are ${planes.join(", ")}.` };
|
|
9712
|
+
const ids = [...new Set(options.ids ?? this.selectedRoots())];
|
|
9713
|
+
if (!ids.length) return { ok: false, message: "Select objects to put on the plane first." };
|
|
9714
|
+
const next = /* @__PURE__ */ new Map();
|
|
9715
|
+
const project = (n2, m) => {
|
|
9716
|
+
const own = n2.transform ? multiplyMatrices(m, n2.transform) : m;
|
|
9717
|
+
if (n2.type === "text" || n2.type === "instance") return `"${n2.id}" is ${n2.type === "text" ? "text" : "a symbol instance"}: convert it to outlines first (vector.createOutlines${n2.type === "instance" ? " after vector.detachInstance" : ""}).`;
|
|
9718
|
+
if (n2.type === "group") {
|
|
9719
|
+
const children = [];
|
|
9720
|
+
for (const c of n2.children) {
|
|
9721
|
+
const r = project(c, own);
|
|
9722
|
+
if (typeof r === "string") return r;
|
|
9723
|
+
children.push(r);
|
|
9724
|
+
}
|
|
9725
|
+
const { transform: _t2, ...rest2 } = n2;
|
|
9726
|
+
return { ...rest2, children };
|
|
9727
|
+
}
|
|
9728
|
+
const flat = transformBezierPath(subpathsToBezier(n2.subpaths), own);
|
|
9729
|
+
const mapped = vectorPerspectiveMapPath(grid, plane, flat);
|
|
9730
|
+
if (!mapped) return `"${n2.id}" reaches beyond the plane's horizon: move it nearer the origin, or the vanishing points further out.`;
|
|
9731
|
+
const { transform: _t, ...rest } = n2;
|
|
9732
|
+
return { ...rest, subpaths: bezierToSubpaths(mapped) };
|
|
9733
|
+
};
|
|
9734
|
+
for (const id of ids) {
|
|
9735
|
+
const loc = locateVectorNode(this.doc.nodes, id);
|
|
9736
|
+
if (!loc) return { ok: false, message: `There is no node "${id}".` };
|
|
9737
|
+
const node = loc.list[loc.index];
|
|
9738
|
+
if (node.locked) return { ok: false, message: `"${id}" is locked; unlock it first.` };
|
|
9739
|
+
const parentM = this.parentMatrixOf(id);
|
|
9740
|
+
const r = project(node, parentM);
|
|
9741
|
+
if (typeof r === "string") return { ok: false, message: r };
|
|
9742
|
+
const inv = invertMatrix(parentM);
|
|
9743
|
+
next.set(id, isIdentityMatrix(inv) ? r : transformVectorNode(r, inv));
|
|
9744
|
+
}
|
|
9745
|
+
this.change(`Attach to ${plane[0].toUpperCase()}${plane.slice(1)} Plane`, () => {
|
|
9746
|
+
this.setDoc(mapTree(this.doc.nodes, (n2) => next.get(n2.id) ?? n2));
|
|
9747
|
+
});
|
|
9748
|
+
return { ok: true, ids };
|
|
9749
|
+
}
|
|
9750
|
+
/** A shape's subpaths drawn on the active perspective plane from its flat drag box, or null to keep it flat. */
|
|
9751
|
+
perspectiveShape(kind, start, end) {
|
|
9752
|
+
const grid = this.doc.perspective;
|
|
9753
|
+
const plane = this.perspectivePlane;
|
|
9754
|
+
if (!grid || !plane || kind === "line" || !vectorPerspectivePlanes(grid).includes(plane)) return null;
|
|
9755
|
+
const toFlat = vectorPerspectivePlaneToFlat(grid, plane);
|
|
9756
|
+
const a = toFlat?.(start);
|
|
9757
|
+
const b = toFlat?.(end);
|
|
9758
|
+
if (!a || !b) return null;
|
|
9759
|
+
const flat = this.createShapeNode({ kind, ...boundsFromPoints(a, b) });
|
|
9760
|
+
const mapped = vectorPerspectiveMapPath(grid, plane, subpathsToBezier(flat.subpaths));
|
|
9761
|
+
return mapped ? bezierToSubpaths(mapped) : null;
|
|
9762
|
+
}
|
|
9763
|
+
// -----------------------------------------------------------------------------------------
|
|
9517
9764
|
// PDF
|
|
9518
9765
|
/**
|
|
9519
9766
|
* The document as a vector PDF (see `vectorDocumentToPdf`): one page of the artboard, or a page
|
|
@@ -12305,7 +12552,9 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
12305
12552
|
const y2 = drag.start.y + h;
|
|
12306
12553
|
bounds = boundsFromPoints(start, { x: x2, y: y2 });
|
|
12307
12554
|
}
|
|
12308
|
-
const
|
|
12555
|
+
const kind = drag.tool === "frame" ? "rect" : drag.tool;
|
|
12556
|
+
const onPlane = drag.tool !== "frame" ? this.perspectiveShape(kind, start, { x: bounds.x === start.x ? bounds.x + bounds.width : bounds.x, y: bounds.y === start.y ? bounds.y + bounds.height : bounds.y }) : null;
|
|
12557
|
+
const shaped = onPlane ? { subpaths: onPlane } : this.createShapeNode({ kind, ...bounds });
|
|
12309
12558
|
this.replaceNode(drag.nodeId, { ...node, subpaths: shaped.subpaths });
|
|
12310
12559
|
this.interaction = { type: "draw", tool: drag.tool, nodeId: drag.nodeId, bounds };
|
|
12311
12560
|
this.notify(true);
|
|
@@ -15166,6 +15415,86 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15166
15415
|
}
|
|
15167
15416
|
}
|
|
15168
15417
|
];
|
|
15418
|
+
const PLANE = { type: "string", enum: [...VECTOR_PERSPECTIVE_PLANES], description: "A plane of the grid: floor, left and right (2 or 3 vanishing points), or floor, side and front (1 point)." };
|
|
15419
|
+
const perspectiveResult = () => {
|
|
15420
|
+
const grid = controller.getPerspective();
|
|
15421
|
+
return { perspective: grid, planes: grid ? vectorPerspectivePlanes(grid) : [], drawingOn: controller.getState().perspectivePlane };
|
|
15422
|
+
};
|
|
15423
|
+
const perspectiveCommands = () => [
|
|
15424
|
+
{
|
|
15425
|
+
...base,
|
|
15426
|
+
id: `${prefix}getPerspective`,
|
|
15427
|
+
label: "Perspective Grid",
|
|
15428
|
+
keywords: ["perspective", "grid", "vanishing point", "horizon"],
|
|
15429
|
+
description: "Reads the document's perspective grid: { perspective: { vanishingPoints, origin, gridSize, extent, visible } or null, planes (the planes it has), drawingOn (the plane new shapes are drawn on, or null) }.",
|
|
15430
|
+
params: { type: "object", properties: {}, additionalProperties: false },
|
|
15431
|
+
run: () => perspectiveResult()
|
|
15432
|
+
},
|
|
15433
|
+
{
|
|
15434
|
+
...base,
|
|
15435
|
+
id: `${prefix}setPerspective`,
|
|
15436
|
+
label: "Perspective Grid\u2026",
|
|
15437
|
+
keywords: ["perspective", "grid", "vanishing point", "one point", "two point", "three point", "horizon", "drawing in perspective"],
|
|
15438
|
+
description: "Sets the document's perspective grid (CorelDRAW's Perspective Drawing): 1 vanishing point (planes floor, side, front), 2 (floor, left, right; walls recede to the first and second) or 3 (the third is where the walls' verticals meet). Put the vanishing points on the horizon line and the origin below it, where the planes meet. One undo step. Returns the grid as vector.getPerspective does.",
|
|
15439
|
+
params: {
|
|
15440
|
+
type: "object",
|
|
15441
|
+
properties: {
|
|
15442
|
+
vanishingPoints: { type: "array", minItems: 1, maxItems: 3, items: { ...POINT, description: "A vanishing point (document units)." }, description: "1 to 3 vanishing points, document units." },
|
|
15443
|
+
origin: { ...POINT, description: "Where the planes meet (document units), not on a vanishing point." },
|
|
15444
|
+
gridSize: { type: "number", exclusiveMinimum: 0, description: "Grid cell size at the origin, document units (default 20)." },
|
|
15445
|
+
extent: { type: "integer", minimum: 1, maximum: 100, description: "Cells drawn out from the origin along each axis (default 12)." },
|
|
15446
|
+
visible: { type: "boolean", description: "Show the grid on the canvas (default true)." }
|
|
15447
|
+
},
|
|
15448
|
+
required: ["vanishingPoints", "origin"],
|
|
15449
|
+
additionalProperties: false
|
|
15450
|
+
},
|
|
15451
|
+
undoable: true,
|
|
15452
|
+
run: (_ctx, params) => {
|
|
15453
|
+
check(controller.setPerspective(params));
|
|
15454
|
+
return perspectiveResult();
|
|
15455
|
+
}
|
|
15456
|
+
},
|
|
15457
|
+
{
|
|
15458
|
+
...base,
|
|
15459
|
+
id: `${prefix}removePerspective`,
|
|
15460
|
+
label: "Remove Perspective Grid",
|
|
15461
|
+
keywords: ["perspective", "grid", "remove"],
|
|
15462
|
+
description: "Removes the perspective grid (art already on its planes stays as drawn). One undo step. Returns { perspective: null }.",
|
|
15463
|
+
params: { type: "object", properties: {}, additionalProperties: false },
|
|
15464
|
+
undoable: true,
|
|
15465
|
+
run: () => {
|
|
15466
|
+
check(controller.setPerspective(null));
|
|
15467
|
+
return { perspective: null };
|
|
15468
|
+
}
|
|
15469
|
+
},
|
|
15470
|
+
{
|
|
15471
|
+
...base,
|
|
15472
|
+
id: `${prefix}setPerspectivePlane`,
|
|
15473
|
+
label: "Draw on Perspective Plane",
|
|
15474
|
+
keywords: ["perspective", "plane", "draw", "floor", "wall"],
|
|
15475
|
+
description: "Makes the Rectangle, Ellipse, Polygon and Star tools draw on a plane of the grid (their drag box is taken on the plane, so shapes recede with it), or flat again with plane null. Not an undo step. Returns the grid as vector.getPerspective does.",
|
|
15476
|
+
params: { type: "object", properties: { plane: { ...PLANE, type: ["string", "null"], enum: [...VECTOR_PERSPECTIVE_PLANES, null], description: `${PLANE.description} null draws flat.` } }, required: ["plane"], additionalProperties: false },
|
|
15477
|
+
run: (_ctx, params) => {
|
|
15478
|
+
check(controller.setPerspectivePlane(params.plane));
|
|
15479
|
+
return perspectiveResult();
|
|
15480
|
+
}
|
|
15481
|
+
},
|
|
15482
|
+
{
|
|
15483
|
+
...base,
|
|
15484
|
+
id: `${prefix}attachToPerspective`,
|
|
15485
|
+
label: "Attach to Perspective",
|
|
15486
|
+
keywords: ["perspective", "attach", "plane", "project", "wall", "floor", "sign"],
|
|
15487
|
+
description: "Lays objects (`ids`, default the selection) onto a plane of the grid: each is read flat relative to the grid origin (right and up) and projected, so art near the origin keeps its size and further art recedes. Draw or place the flat art beside the origin first. Text and instances must be outlines (vector.createOutlines). One undo step. Returns { ids }.",
|
|
15488
|
+
params: { type: "object", properties: { ids: { ...IDS, description: "Objects to project (default: the selection)." }, plane: PLANE }, required: ["plane"], additionalProperties: false },
|
|
15489
|
+
undoable: true,
|
|
15490
|
+
enabled: enabledFor,
|
|
15491
|
+
run: (_ctx, params) => {
|
|
15492
|
+
const r = controller.attachToPerspective(params.plane, params.ids ? { ids: params.ids } : {});
|
|
15493
|
+
check(r);
|
|
15494
|
+
return { ids: r.ids ?? [] };
|
|
15495
|
+
}
|
|
15496
|
+
}
|
|
15497
|
+
];
|
|
15169
15498
|
const pdfCommands = () => [
|
|
15170
15499
|
{
|
|
15171
15500
|
...base,
|
|
@@ -16002,6 +16331,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
16002
16331
|
...lottieCommands(),
|
|
16003
16332
|
...pdfCommands(),
|
|
16004
16333
|
...symmetryCommands(),
|
|
16334
|
+
...perspectiveCommands(),
|
|
16005
16335
|
...lensCommands(),
|
|
16006
16336
|
{
|
|
16007
16337
|
...base,
|
|
@@ -17052,6 +17382,7 @@ export {
|
|
|
17052
17382
|
VECTOR_PATH_ACTIONS,
|
|
17053
17383
|
VECTOR_PATH_TEXT_BASELINES,
|
|
17054
17384
|
VECTOR_PENCIL_STRING_PX,
|
|
17385
|
+
VECTOR_PERSPECTIVE_PLANES,
|
|
17055
17386
|
VECTOR_PRESSURE_NOMINAL,
|
|
17056
17387
|
VECTOR_ROTATE_HANDLE_OFFSET,
|
|
17057
17388
|
VECTOR_SPATIAL_MIN,
|
|
@@ -17358,6 +17689,7 @@ export {
|
|
|
17358
17689
|
sanitizeVectorGradient,
|
|
17359
17690
|
sanitizeVectorLens,
|
|
17360
17691
|
sanitizeVectorMask,
|
|
17692
|
+
sanitizeVectorPerspective,
|
|
17361
17693
|
sanitizeVectorResizing,
|
|
17362
17694
|
sanitizeVectorShadedPaint,
|
|
17363
17695
|
sanitizeVectorStrokeSettings,
|
|
@@ -17554,6 +17886,13 @@ export {
|
|
|
17554
17886
|
vectorPathTextPositions,
|
|
17555
17887
|
vectorPathWorldBezier,
|
|
17556
17888
|
vectorPathfinderShape,
|
|
17889
|
+
vectorPerspectiveFlatToPlane,
|
|
17890
|
+
vectorPerspectiveGridLines,
|
|
17891
|
+
vectorPerspectiveMapPath,
|
|
17892
|
+
vectorPerspectivePlaneMap,
|
|
17893
|
+
vectorPerspectivePlaneToFlat,
|
|
17894
|
+
vectorPerspectivePlanes,
|
|
17895
|
+
vectorPerspectivePreset,
|
|
17557
17896
|
vectorPolarAngles,
|
|
17558
17897
|
vectorPolarIncrementOf,
|
|
17559
17898
|
vectorRepeaterCopies,
|