@pooder/kit 4.2.0 → 4.3.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/CHANGELOG.md +6 -0
- package/dist/index.d.mts +12 -5
- package/dist/index.d.ts +12 -5
- package/dist/index.js +236 -75
- package/dist/index.mjs +236 -75
- package/package.json +1 -1
- package/src/CanvasService.ts +96 -96
- package/src/ViewportSystem.ts +92 -92
- package/src/background.ts +230 -230
- package/src/constraints.ts +157 -42
- package/src/coordinate.ts +106 -106
- package/src/dieline.ts +955 -955
- package/src/feature.ts +88 -68
- package/src/featureComplete.ts +3 -2
- package/src/film.ts +194 -194
- package/src/geometry.ts +161 -30
- package/src/image.ts +512 -512
- package/src/index.ts +10 -10
- package/src/mirror.ts +128 -128
- package/src/ruler.ts +508 -508
- package/src/tracer.ts +570 -570
- package/src/units.ts +27 -27
- package/src/white-ink.ts +373 -373
- package/tsconfig.test.json +15 -15
- package/.test-dist/src/CanvasService.js +0 -83
- package/.test-dist/src/ViewportSystem.js +0 -75
- package/.test-dist/src/background.js +0 -203
- package/.test-dist/src/constraints.js +0 -153
- package/.test-dist/src/coordinate.js +0 -74
- package/.test-dist/src/dieline.js +0 -758
- package/.test-dist/src/feature.js +0 -687
- package/.test-dist/src/featureComplete.js +0 -31
- package/.test-dist/src/featureDraft.js +0 -31
- package/.test-dist/src/film.js +0 -167
- package/.test-dist/src/geometry.js +0 -292
- package/.test-dist/src/image.js +0 -421
- package/.test-dist/src/index.js +0 -31
- package/.test-dist/src/mirror.js +0 -104
- package/.test-dist/src/ruler.js +0 -383
- package/.test-dist/src/tracer.js +0 -448
- package/.test-dist/src/units.js +0 -30
- package/.test-dist/src/white-ink.js +0 -310
- package/.test-dist/tests/run.js +0 -60
- package/tests/run.ts +0 -81
package/CHANGELOG.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -53,13 +53,12 @@ interface DielineFeature {
|
|
|
53
53
|
height?: number;
|
|
54
54
|
radius?: number;
|
|
55
55
|
rotation?: number;
|
|
56
|
-
|
|
56
|
+
renderBehavior?: "edge" | "surface";
|
|
57
57
|
color?: string;
|
|
58
58
|
strokeDash?: number[];
|
|
59
59
|
skipCut?: boolean;
|
|
60
|
-
|
|
61
|
-
type:
|
|
62
|
-
params?: any;
|
|
60
|
+
bridge?: {
|
|
61
|
+
type: "vertical";
|
|
63
62
|
};
|
|
64
63
|
}
|
|
65
64
|
|
|
@@ -147,6 +146,14 @@ declare class FilmTool implements Extension {
|
|
|
147
146
|
private updateFilm;
|
|
148
147
|
}
|
|
149
148
|
|
|
149
|
+
interface ConstraintFeature extends DielineFeature {
|
|
150
|
+
constraints?: Array<{
|
|
151
|
+
type: string;
|
|
152
|
+
params?: any;
|
|
153
|
+
validateOnly?: boolean;
|
|
154
|
+
}>;
|
|
155
|
+
}
|
|
156
|
+
|
|
150
157
|
declare class FeatureTool implements Extension {
|
|
151
158
|
id: string;
|
|
152
159
|
metadata: {
|
|
@@ -162,7 +169,7 @@ declare class FeatureTool implements Extension {
|
|
|
162
169
|
private handleDielineChange;
|
|
163
170
|
private currentGeometry;
|
|
164
171
|
constructor(options?: Partial<{
|
|
165
|
-
features:
|
|
172
|
+
features: ConstraintFeature[];
|
|
166
173
|
}>);
|
|
167
174
|
activate(context: ExtensionContext): void;
|
|
168
175
|
deactivate(context: ExtensionContext): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -53,13 +53,12 @@ interface DielineFeature {
|
|
|
53
53
|
height?: number;
|
|
54
54
|
radius?: number;
|
|
55
55
|
rotation?: number;
|
|
56
|
-
|
|
56
|
+
renderBehavior?: "edge" | "surface";
|
|
57
57
|
color?: string;
|
|
58
58
|
strokeDash?: number[];
|
|
59
59
|
skipCut?: boolean;
|
|
60
|
-
|
|
61
|
-
type:
|
|
62
|
-
params?: any;
|
|
60
|
+
bridge?: {
|
|
61
|
+
type: "vertical";
|
|
63
62
|
};
|
|
64
63
|
}
|
|
65
64
|
|
|
@@ -147,6 +146,14 @@ declare class FilmTool implements Extension {
|
|
|
147
146
|
private updateFilm;
|
|
148
147
|
}
|
|
149
148
|
|
|
149
|
+
interface ConstraintFeature extends DielineFeature {
|
|
150
|
+
constraints?: Array<{
|
|
151
|
+
type: string;
|
|
152
|
+
params?: any;
|
|
153
|
+
validateOnly?: boolean;
|
|
154
|
+
}>;
|
|
155
|
+
}
|
|
156
|
+
|
|
150
157
|
declare class FeatureTool implements Extension {
|
|
151
158
|
id: string;
|
|
152
159
|
metadata: {
|
|
@@ -162,7 +169,7 @@ declare class FeatureTool implements Extension {
|
|
|
162
169
|
private handleDielineChange;
|
|
163
170
|
private currentGeometry;
|
|
164
171
|
constructor(options?: Partial<{
|
|
165
|
-
features:
|
|
172
|
+
features: ConstraintFeature[];
|
|
166
173
|
}>);
|
|
167
174
|
activate(context: ExtensionContext): void;
|
|
168
175
|
deactivate(context: ExtensionContext): void;
|
package/dist/index.js
CHANGED
|
@@ -823,7 +823,7 @@ function getPerimeterShape(options) {
|
|
|
823
823
|
const { features } = options;
|
|
824
824
|
if (features && features.length > 0) {
|
|
825
825
|
const edgeFeatures = features.filter(
|
|
826
|
-
(f) => !f.
|
|
826
|
+
(f) => !f.renderBehavior || f.renderBehavior === "edge"
|
|
827
827
|
);
|
|
828
828
|
const adds = [];
|
|
829
829
|
const subtracts = [];
|
|
@@ -831,10 +831,78 @@ function getPerimeterShape(options) {
|
|
|
831
831
|
const pos = resolveFeaturePosition(f, options);
|
|
832
832
|
const center = new import_paper2.default.Point(pos.x, pos.y);
|
|
833
833
|
const item = createFeatureItem(f, center);
|
|
834
|
-
if (f.
|
|
835
|
-
|
|
834
|
+
if (f.bridge && f.bridge.type === "vertical") {
|
|
835
|
+
const itemBounds = item.bounds;
|
|
836
|
+
const mainBounds = mainShape.bounds;
|
|
837
|
+
const bridgeTop = mainBounds.top;
|
|
838
|
+
const bridgeBottom = itemBounds.top;
|
|
839
|
+
if (bridgeBottom > bridgeTop) {
|
|
840
|
+
const startY = bridgeBottom + 1;
|
|
841
|
+
const bridgeRect = new import_paper2.default.Path.Rectangle({
|
|
842
|
+
from: [itemBounds.left, bridgeTop],
|
|
843
|
+
to: [itemBounds.right, startY],
|
|
844
|
+
insert: false
|
|
845
|
+
});
|
|
846
|
+
const gaps = bridgeRect.subtract(mainShape);
|
|
847
|
+
bridgeRect.remove();
|
|
848
|
+
let bridgePart = null;
|
|
849
|
+
const isBottomPart = (part) => {
|
|
850
|
+
return Math.abs(part.bounds.bottom - startY) < 2;
|
|
851
|
+
};
|
|
852
|
+
if (gaps instanceof import_paper2.default.CompoundPath) {
|
|
853
|
+
const children = gaps.children;
|
|
854
|
+
let maxBottom = -Infinity;
|
|
855
|
+
let bestChild = null;
|
|
856
|
+
for (const child of children) {
|
|
857
|
+
if (child.bounds.bottom > maxBottom) {
|
|
858
|
+
maxBottom = child.bounds.bottom;
|
|
859
|
+
bestChild = child;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (bestChild && isBottomPart(bestChild)) {
|
|
863
|
+
bridgePart = bestChild.clone();
|
|
864
|
+
}
|
|
865
|
+
} else if (gaps instanceof import_paper2.default.Path) {
|
|
866
|
+
if (isBottomPart(gaps)) {
|
|
867
|
+
bridgePart = gaps.clone();
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
gaps.remove();
|
|
871
|
+
if (bridgePart) {
|
|
872
|
+
const bounds = bridgePart.bounds;
|
|
873
|
+
if (bounds.height > 0) {
|
|
874
|
+
const overlap = 1;
|
|
875
|
+
const scaleY = (bounds.height + overlap) / bounds.height;
|
|
876
|
+
bridgePart.scale(1, scaleY, new import_paper2.default.Point(bounds.center.x, bounds.bottom));
|
|
877
|
+
}
|
|
878
|
+
const unitedItem = item.unite(bridgePart);
|
|
879
|
+
item.remove();
|
|
880
|
+
bridgePart.remove();
|
|
881
|
+
if (f.operation === "add") {
|
|
882
|
+
adds.push(unitedItem);
|
|
883
|
+
} else {
|
|
884
|
+
subtracts.push(unitedItem);
|
|
885
|
+
}
|
|
886
|
+
} else {
|
|
887
|
+
if (f.operation === "add") {
|
|
888
|
+
adds.push(item);
|
|
889
|
+
} else {
|
|
890
|
+
subtracts.push(item);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
if (f.operation === "add") {
|
|
895
|
+
adds.push(item);
|
|
896
|
+
} else {
|
|
897
|
+
subtracts.push(item);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
836
900
|
} else {
|
|
837
|
-
|
|
901
|
+
if (f.operation === "add") {
|
|
902
|
+
adds.push(item);
|
|
903
|
+
} else {
|
|
904
|
+
subtracts.push(item);
|
|
905
|
+
}
|
|
838
906
|
}
|
|
839
907
|
});
|
|
840
908
|
if (adds.length > 0) {
|
|
@@ -867,10 +935,12 @@ function getPerimeterShape(options) {
|
|
|
867
935
|
return mainShape;
|
|
868
936
|
}
|
|
869
937
|
function applySurfaceFeatures(shape, features, options) {
|
|
870
|
-
const
|
|
871
|
-
|
|
938
|
+
const surfaceFeatures = features.filter(
|
|
939
|
+
(f) => f.renderBehavior === "surface"
|
|
940
|
+
);
|
|
941
|
+
if (surfaceFeatures.length === 0) return shape;
|
|
872
942
|
let result = shape;
|
|
873
|
-
for (const f of
|
|
943
|
+
for (const f of surfaceFeatures) {
|
|
874
944
|
const pos = resolveFeaturePosition(f, options);
|
|
875
945
|
const center = new import_paper2.default.Point(pos.x, pos.y);
|
|
876
946
|
const item = createFeatureItem(f, center);
|
|
@@ -927,9 +997,17 @@ function generateBleedZonePath(originalOptions, offsetOptions, offset) {
|
|
|
927
997
|
ensurePaper(paperWidth, paperHeight);
|
|
928
998
|
import_paper2.default.project.activeLayer.removeChildren();
|
|
929
999
|
const pOriginal = getPerimeterShape(originalOptions);
|
|
930
|
-
const shapeOriginal = applySurfaceFeatures(
|
|
1000
|
+
const shapeOriginal = applySurfaceFeatures(
|
|
1001
|
+
pOriginal,
|
|
1002
|
+
originalOptions.features,
|
|
1003
|
+
originalOptions
|
|
1004
|
+
);
|
|
931
1005
|
const pOffset = getPerimeterShape(offsetOptions);
|
|
932
|
-
const shapeOffset = applySurfaceFeatures(
|
|
1006
|
+
const shapeOffset = applySurfaceFeatures(
|
|
1007
|
+
pOffset,
|
|
1008
|
+
offsetOptions.features,
|
|
1009
|
+
offsetOptions
|
|
1010
|
+
);
|
|
933
1011
|
let bleedZone;
|
|
934
1012
|
if (offset > 0) {
|
|
935
1013
|
bleedZone = shapeOffset.subtract(shapeOriginal);
|
|
@@ -942,13 +1020,29 @@ function generateBleedZonePath(originalOptions, offsetOptions, offset) {
|
|
|
942
1020
|
bleedZone.remove();
|
|
943
1021
|
return pathData;
|
|
944
1022
|
}
|
|
1023
|
+
function getLowestPointOnDieline(options) {
|
|
1024
|
+
ensurePaper(options.width * 2, options.height * 2);
|
|
1025
|
+
import_paper2.default.project.activeLayer.removeChildren();
|
|
1026
|
+
const shape = createBaseShape(options);
|
|
1027
|
+
const bounds = shape.bounds;
|
|
1028
|
+
const result = {
|
|
1029
|
+
x: bounds.center.x,
|
|
1030
|
+
y: bounds.bottom
|
|
1031
|
+
};
|
|
1032
|
+
shape.remove();
|
|
1033
|
+
return result;
|
|
1034
|
+
}
|
|
945
1035
|
function getNearestPointOnDieline(point, options) {
|
|
946
1036
|
ensurePaper(options.width * 2, options.height * 2);
|
|
947
1037
|
import_paper2.default.project.activeLayer.removeChildren();
|
|
948
1038
|
const shape = createBaseShape(options);
|
|
949
1039
|
const p = new import_paper2.default.Point(point.x, point.y);
|
|
950
|
-
const
|
|
951
|
-
const result = {
|
|
1040
|
+
const location = shape.getNearestLocation(p);
|
|
1041
|
+
const result = {
|
|
1042
|
+
x: location.point.x,
|
|
1043
|
+
y: location.point.y,
|
|
1044
|
+
normal: location.normal ? { x: location.normal.x, y: location.normal.y } : void 0
|
|
1045
|
+
};
|
|
952
1046
|
shape.remove();
|
|
953
1047
|
return result;
|
|
954
1048
|
}
|
|
@@ -1898,22 +1992,60 @@ var ConstraintRegistry = class {
|
|
|
1898
1992
|
static register(type, handler) {
|
|
1899
1993
|
this.handlers.set(type, handler);
|
|
1900
1994
|
}
|
|
1901
|
-
static apply(x, y, feature, context) {
|
|
1902
|
-
|
|
1995
|
+
static apply(x, y, feature, context, constraints) {
|
|
1996
|
+
const list = constraints || feature.constraints;
|
|
1997
|
+
if (!list || list.length === 0) {
|
|
1903
1998
|
return { x, y };
|
|
1904
1999
|
}
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
2000
|
+
let currentX = x;
|
|
2001
|
+
let currentY = y;
|
|
2002
|
+
for (const constraint of list) {
|
|
2003
|
+
const handler = this.handlers.get(constraint.type);
|
|
2004
|
+
if (handler) {
|
|
2005
|
+
const result = handler(currentX, currentY, feature, context, constraint.params || {});
|
|
2006
|
+
currentX = result.x;
|
|
2007
|
+
currentY = result.y;
|
|
2008
|
+
}
|
|
1908
2009
|
}
|
|
1909
|
-
return { x, y };
|
|
2010
|
+
return { x: currentX, y: currentY };
|
|
1910
2011
|
}
|
|
1911
2012
|
};
|
|
1912
2013
|
ConstraintRegistry.handlers = /* @__PURE__ */ new Map();
|
|
1913
|
-
var
|
|
1914
|
-
|
|
2014
|
+
var pathConstraint = (x, y, feature, context, params) => {
|
|
2015
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
2016
|
+
if (!geometry) return { x, y };
|
|
2017
|
+
const minX = geometry.x - geometry.width / 2;
|
|
2018
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2019
|
+
const absX = minX + x * geometry.width;
|
|
2020
|
+
const absY = minY + y * geometry.height;
|
|
2021
|
+
const nearest = getNearestPointOnDieline(
|
|
2022
|
+
{ x: absX, y: absY },
|
|
2023
|
+
geometry
|
|
2024
|
+
);
|
|
2025
|
+
let finalX = nearest.x;
|
|
2026
|
+
let finalY = nearest.y;
|
|
2027
|
+
const hasOffsetParams = params.minOffset !== void 0 || params.maxOffset !== void 0;
|
|
2028
|
+
if (hasOffsetParams && nearest.normal) {
|
|
2029
|
+
const dx = absX - nearest.x;
|
|
2030
|
+
const dy = absY - nearest.y;
|
|
2031
|
+
const nx2 = nearest.normal.x;
|
|
2032
|
+
const ny2 = nearest.normal.y;
|
|
2033
|
+
const dist = dx * nx2 + dy * ny2;
|
|
2034
|
+
const scale = dielineWidth > 0 ? geometry.width / dielineWidth : 1;
|
|
2035
|
+
const rawMin = params.minOffset !== void 0 ? params.minOffset : 0;
|
|
2036
|
+
const rawMax = params.maxOffset !== void 0 ? params.maxOffset : 0;
|
|
2037
|
+
const minOffset = rawMin * scale;
|
|
2038
|
+
const maxOffset = rawMax * scale;
|
|
2039
|
+
const clampedDist = Math.max(minOffset, Math.min(dist, maxOffset));
|
|
2040
|
+
finalX = nearest.x + nx2 * clampedDist;
|
|
2041
|
+
finalY = nearest.y + ny2 * clampedDist;
|
|
2042
|
+
}
|
|
2043
|
+
const nx = geometry.width > 0 ? (finalX - minX) / geometry.width : 0.5;
|
|
2044
|
+
const ny = geometry.height > 0 ? (finalY - minY) / geometry.height : 0.5;
|
|
2045
|
+
return { x: nx, y: ny };
|
|
2046
|
+
};
|
|
2047
|
+
var edgeConstraint = (x, y, feature, context, params) => {
|
|
1915
2048
|
const { dielineWidth, dielineHeight } = context;
|
|
1916
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1917
2049
|
const allowedEdges = params.allowedEdges || [
|
|
1918
2050
|
"top",
|
|
1919
2051
|
"bottom",
|
|
@@ -1974,10 +2106,8 @@ var edgeConstraint = (x, y, feature, context) => {
|
|
|
1974
2106
|
}
|
|
1975
2107
|
return { x: newX, y: newY };
|
|
1976
2108
|
};
|
|
1977
|
-
var internalConstraint = (x, y, feature, context) => {
|
|
1978
|
-
var _a;
|
|
2109
|
+
var internalConstraint = (x, y, feature, context, params) => {
|
|
1979
2110
|
const { dielineWidth, dielineHeight } = context;
|
|
1980
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1981
2111
|
const margin = params.margin || 0;
|
|
1982
2112
|
const fw = feature.width || 0;
|
|
1983
2113
|
const fh = feature.height || 0;
|
|
@@ -1989,10 +2119,8 @@ var internalConstraint = (x, y, feature, context) => {
|
|
|
1989
2119
|
const clampedY = minY > maxY ? 0.5 : Math.max(minY, Math.min(y, maxY));
|
|
1990
2120
|
return { x: clampedX, y: clampedY };
|
|
1991
2121
|
};
|
|
1992
|
-
var tangentBottomConstraint = (x, y, feature, context) => {
|
|
1993
|
-
var _a;
|
|
2122
|
+
var tangentBottomConstraint = (x, y, feature, context, params) => {
|
|
1994
2123
|
const { dielineWidth, dielineHeight } = context;
|
|
1995
|
-
const params = ((_a = feature.constraints) == null ? void 0 : _a.params) || {};
|
|
1996
2124
|
const gap = params.gap || 0;
|
|
1997
2125
|
const confineX = params.confineX !== false;
|
|
1998
2126
|
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
@@ -2006,18 +2134,38 @@ var tangentBottomConstraint = (x, y, feature, context) => {
|
|
|
2006
2134
|
}
|
|
2007
2135
|
return { x: newX, y: newY };
|
|
2008
2136
|
};
|
|
2137
|
+
var lowestTangentConstraint = (x, y, feature, context, params) => {
|
|
2138
|
+
const { dielineWidth, dielineHeight, geometry } = context;
|
|
2139
|
+
if (!geometry) return { x, y };
|
|
2140
|
+
const lowest = getLowestPointOnDieline(geometry);
|
|
2141
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2142
|
+
const normY = (lowest.y - minY) / geometry.height;
|
|
2143
|
+
const gap = params.gap || 0;
|
|
2144
|
+
const confineX = params.confineX !== false;
|
|
2145
|
+
const extentY = feature.shape === "circle" ? feature.radius || 0 : (feature.height || 0) / 2;
|
|
2146
|
+
const newY = normY + (extentY + gap) / dielineHeight;
|
|
2147
|
+
let newX = x;
|
|
2148
|
+
if (confineX) {
|
|
2149
|
+
const extentX = feature.shape === "circle" ? feature.radius || 0 : (feature.width || 0) / 2;
|
|
2150
|
+
const minX = extentX / dielineWidth;
|
|
2151
|
+
const maxX = 1 - extentX / dielineWidth;
|
|
2152
|
+
newX = minX > maxX ? 0.5 : Math.max(minX, Math.min(newX, maxX));
|
|
2153
|
+
}
|
|
2154
|
+
return { x: newX, y: newY };
|
|
2155
|
+
};
|
|
2156
|
+
ConstraintRegistry.register("path", pathConstraint);
|
|
2009
2157
|
ConstraintRegistry.register("edge", edgeConstraint);
|
|
2010
2158
|
ConstraintRegistry.register("internal", internalConstraint);
|
|
2011
2159
|
ConstraintRegistry.register("tangent-bottom", tangentBottomConstraint);
|
|
2160
|
+
ConstraintRegistry.register("lowest-tangent", lowestTangentConstraint);
|
|
2012
2161
|
|
|
2013
2162
|
// src/featureComplete.ts
|
|
2014
2163
|
function validateFeaturesStrict(features, context) {
|
|
2015
|
-
var _a;
|
|
2016
2164
|
const eps = 1e-6;
|
|
2017
2165
|
const issues = [];
|
|
2018
2166
|
for (const f of features) {
|
|
2019
|
-
if (!
|
|
2020
|
-
const constrained = ConstraintRegistry.apply(f.x, f.y, f, context);
|
|
2167
|
+
if (!f.constraints || f.constraints.length === 0) continue;
|
|
2168
|
+
const constrained = ConstraintRegistry.apply(f.x, f.y, f, context, f.constraints);
|
|
2021
2169
|
if (Math.abs(constrained.x - f.x) > eps || Math.abs(constrained.y - f.y) > eps) {
|
|
2022
2170
|
issues.push({
|
|
2023
2171
|
featureId: f.id,
|
|
@@ -2283,14 +2431,16 @@ var FeatureTool = class {
|
|
|
2283
2431
|
const newFeature = {
|
|
2284
2432
|
id: Date.now().toString(),
|
|
2285
2433
|
operation: type,
|
|
2286
|
-
placement: "edge",
|
|
2287
2434
|
shape: "rect",
|
|
2288
2435
|
x: 0.5,
|
|
2289
2436
|
y: 0,
|
|
2290
2437
|
// Top edge
|
|
2291
2438
|
width: 10,
|
|
2292
2439
|
height: 10,
|
|
2293
|
-
rotation: 0
|
|
2440
|
+
rotation: 0,
|
|
2441
|
+
renderBehavior: "edge",
|
|
2442
|
+
// Default constraint: path (snap to edge)
|
|
2443
|
+
constraints: [{ type: "path" }]
|
|
2294
2444
|
};
|
|
2295
2445
|
this.setWorkingFeatures([...this.workingFeatures || [], newFeature]);
|
|
2296
2446
|
this.redraw();
|
|
@@ -2306,22 +2456,24 @@ var FeatureTool = class {
|
|
|
2306
2456
|
groupId,
|
|
2307
2457
|
operation: "add",
|
|
2308
2458
|
shape: "circle",
|
|
2309
|
-
placement: "edge",
|
|
2310
2459
|
x: 0.5,
|
|
2311
2460
|
y: 0,
|
|
2312
2461
|
radius: 20,
|
|
2313
|
-
rotation: 0
|
|
2462
|
+
rotation: 0,
|
|
2463
|
+
renderBehavior: "edge",
|
|
2464
|
+
constraints: [{ type: "path" }]
|
|
2314
2465
|
};
|
|
2315
2466
|
const hole = {
|
|
2316
2467
|
id: `${timestamp}-hole`,
|
|
2317
2468
|
groupId,
|
|
2318
2469
|
operation: "subtract",
|
|
2319
2470
|
shape: "circle",
|
|
2320
|
-
placement: "edge",
|
|
2321
2471
|
x: 0.5,
|
|
2322
2472
|
y: 0,
|
|
2323
2473
|
radius: 15,
|
|
2324
|
-
rotation: 0
|
|
2474
|
+
rotation: 0,
|
|
2475
|
+
renderBehavior: "edge",
|
|
2476
|
+
constraints: [{ type: "path" }]
|
|
2325
2477
|
};
|
|
2326
2478
|
this.setWorkingFeatures([...this.workingFeatures || [], lug, hole]);
|
|
2327
2479
|
this.redraw();
|
|
@@ -2460,50 +2612,32 @@ var FeatureTool = class {
|
|
|
2460
2612
|
this.canvasService.requestRenderAll();
|
|
2461
2613
|
}
|
|
2462
2614
|
constrainPosition(p, geometry, limit, feature) {
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
const nx = geometry.width > 0 ? (p.x - minX) / geometry.width : 0.5;
|
|
2467
|
-
const ny = geometry.height > 0 ? (p.y - minY) / geometry.height : 0.5;
|
|
2468
|
-
const scale2 = geometry.scale || 1;
|
|
2469
|
-
const dielineWidth = geometry.width / scale2;
|
|
2470
|
-
const dielineHeight = geometry.height / scale2;
|
|
2471
|
-
const constrained = ConstraintRegistry.apply(nx, ny, feature, {
|
|
2472
|
-
dielineWidth,
|
|
2473
|
-
dielineHeight
|
|
2474
|
-
});
|
|
2475
|
-
return {
|
|
2476
|
-
x: minX + constrained.x * geometry.width,
|
|
2477
|
-
y: minY + constrained.y * geometry.height
|
|
2478
|
-
};
|
|
2479
|
-
}
|
|
2480
|
-
if (feature && feature.placement === "internal") {
|
|
2481
|
-
const minX = geometry.x - geometry.width / 2;
|
|
2482
|
-
const maxX = geometry.x + geometry.width / 2;
|
|
2483
|
-
const minY = geometry.y - geometry.height / 2;
|
|
2484
|
-
const maxY = geometry.y + geometry.height / 2;
|
|
2485
|
-
return {
|
|
2486
|
-
x: Math.max(minX, Math.min(maxX, p.x)),
|
|
2487
|
-
y: Math.max(minY, Math.min(maxY, p.y))
|
|
2488
|
-
};
|
|
2615
|
+
var _a;
|
|
2616
|
+
if (!feature) {
|
|
2617
|
+
return { x: p.x, y: p.y };
|
|
2489
2618
|
}
|
|
2490
|
-
const
|
|
2491
|
-
|
|
2619
|
+
const minX = geometry.x - geometry.width / 2;
|
|
2620
|
+
const minY = geometry.y - geometry.height / 2;
|
|
2621
|
+
const nx = geometry.width > 0 ? (p.x - minX) / geometry.width : 0.5;
|
|
2622
|
+
const ny = geometry.height > 0 ? (p.y - minY) / geometry.height : 0.5;
|
|
2623
|
+
const scale = geometry.scale || 1;
|
|
2624
|
+
const dielineWidth = geometry.width / scale;
|
|
2625
|
+
const dielineHeight = geometry.height / scale;
|
|
2626
|
+
const activeConstraints = (_a = feature.constraints) == null ? void 0 : _a.filter((c) => !c.validateOnly);
|
|
2627
|
+
const constrained = ConstraintRegistry.apply(
|
|
2628
|
+
nx,
|
|
2629
|
+
ny,
|
|
2630
|
+
feature,
|
|
2492
2631
|
{
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2632
|
+
dielineWidth,
|
|
2633
|
+
dielineHeight,
|
|
2634
|
+
geometry
|
|
2635
|
+
},
|
|
2636
|
+
activeConstraints
|
|
2496
2637
|
);
|
|
2497
|
-
const dx = p.x - nearest.x;
|
|
2498
|
-
const dy = p.y - nearest.y;
|
|
2499
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
2500
|
-
if (dist <= limit) {
|
|
2501
|
-
return { x: p.x, y: p.y };
|
|
2502
|
-
}
|
|
2503
|
-
const scale = limit / dist;
|
|
2504
2638
|
return {
|
|
2505
|
-
x:
|
|
2506
|
-
y:
|
|
2639
|
+
x: minX + constrained.x * geometry.width,
|
|
2640
|
+
y: minY + constrained.y * geometry.height
|
|
2507
2641
|
};
|
|
2508
2642
|
}
|
|
2509
2643
|
syncFeatureFromCanvas(target) {
|
|
@@ -2594,6 +2728,33 @@ var FeatureTool = class {
|
|
|
2594
2728
|
if (feature.rotation) {
|
|
2595
2729
|
shape.rotate(feature.rotation);
|
|
2596
2730
|
}
|
|
2731
|
+
if (feature.bridge && feature.bridge.type === "vertical") {
|
|
2732
|
+
const bridgeIndicator = new import_fabric4.Rect({
|
|
2733
|
+
width: visualWidth,
|
|
2734
|
+
height: 100 * featureScale,
|
|
2735
|
+
// Arbitrary long length to show direction
|
|
2736
|
+
fill: "transparent",
|
|
2737
|
+
stroke: "#888",
|
|
2738
|
+
strokeWidth: 1,
|
|
2739
|
+
strokeDashArray: [2, 2],
|
|
2740
|
+
originX: "center",
|
|
2741
|
+
originY: "bottom",
|
|
2742
|
+
// Anchor at bottom so it extends up
|
|
2743
|
+
left: pos.x,
|
|
2744
|
+
top: pos.y - visualHeight / 2,
|
|
2745
|
+
// Start from top of feature
|
|
2746
|
+
opacity: 0.5,
|
|
2747
|
+
selectable: false,
|
|
2748
|
+
evented: false
|
|
2749
|
+
});
|
|
2750
|
+
const group = new import_fabric4.Group([bridgeIndicator, shape], {
|
|
2751
|
+
originX: "center",
|
|
2752
|
+
originY: "center",
|
|
2753
|
+
left: pos.x,
|
|
2754
|
+
top: pos.y
|
|
2755
|
+
});
|
|
2756
|
+
return group;
|
|
2757
|
+
}
|
|
2597
2758
|
return shape;
|
|
2598
2759
|
};
|
|
2599
2760
|
singles.forEach(({ feature, index }) => {
|