@linkiez/dxf-renew 5.3.1 → 7.1.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/{docs/CODE_PATTERNS.md → .github/instructions/code-patterns.instructions.md} +4 -1
- package/.github/instructions/exdxf.instruction.md +161 -0
- package/.github/instructions/tdd.instructions.md +271 -0
- package/.github/workflows/release.yml +4 -5
- package/.releaserc.json +1 -1
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +59 -0
- package/CONTRIBUTING.md +16 -14
- package/PLAN.md +34 -84
- package/README.md +43 -8
- package/dist/dxf.js +1388 -376
- package/docs/DIMENSION_SUMMARY.md +11 -5
- package/docs/DXF_VERSION_SUPPORT.md +45 -0
- package/docs/ENTITY_SVG_ROADMAP.md +96 -0
- package/docs/EZDXF_REFERENCE_SITEMAP.md +55 -0
- package/docs/FIXTURE_VALIDATION_EZDXF.md +62 -0
- package/docs/README.md +22 -0
- package/docs/SVG_RENDERING_INTEGRATION_TESTS.md +119 -0
- package/docs/TEXT-MTEXT-DIMENSION-SUPPORT.md +1 -1
- package/lib/Helper.cjs +2 -2
- package/lib/Helper.cjs.map +2 -2
- package/lib/Helper.js +2 -2
- package/lib/Helper.js.map +2 -2
- package/lib/denormalise.cjs +131 -91
- package/lib/denormalise.cjs.map +2 -2
- package/lib/denormalise.js +131 -91
- package/lib/denormalise.js.map +2 -2
- package/lib/dimensionToSVG.cjs +318 -53
- package/lib/dimensionToSVG.cjs.map +3 -3
- package/lib/dimensionToSVG.js +316 -52
- package/lib/dimensionToSVG.js.map +2 -2
- package/lib/handlers/entities.cjs +90 -26
- package/lib/handlers/entities.cjs.map +3 -3
- package/lib/handlers/entities.js +90 -26
- package/lib/handlers/entities.js.map +3 -3
- package/lib/handlers/entity/dgnUnderlay.cjs +106 -0
- package/lib/handlers/entity/dgnUnderlay.cjs.map +7 -0
- package/lib/handlers/entity/dgnUnderlay.js +71 -0
- package/lib/handlers/entity/dgnUnderlay.js.map +7 -0
- package/lib/handlers/entity/dimension.cjs +24 -0
- package/lib/handlers/entity/dimension.cjs.map +2 -2
- package/lib/handlers/entity/dimension.js +24 -0
- package/lib/handlers/entity/dimension.js.map +2 -2
- package/lib/handlers/entity/dwfUnderlay.cjs +106 -0
- package/lib/handlers/entity/dwfUnderlay.cjs.map +7 -0
- package/lib/handlers/entity/dwfUnderlay.js +71 -0
- package/lib/handlers/entity/dwfUnderlay.js.map +7 -0
- package/lib/handlers/entity/image.cjs +123 -0
- package/lib/handlers/entity/image.cjs.map +7 -0
- package/lib/handlers/entity/image.js +88 -0
- package/lib/handlers/entity/image.js.map +7 -0
- package/lib/handlers/entity/leader.cjs +148 -0
- package/lib/handlers/entity/leader.cjs.map +7 -0
- package/lib/handlers/entity/leader.js +113 -0
- package/lib/handlers/entity/leader.js.map +7 -0
- package/lib/handlers/entity/pdfUnderlay.cjs +106 -0
- package/lib/handlers/entity/pdfUnderlay.cjs.map +7 -0
- package/lib/handlers/entity/pdfUnderlay.js +71 -0
- package/lib/handlers/entity/pdfUnderlay.js.map +7 -0
- package/lib/handlers/entity/tolerance.cjs +90 -0
- package/lib/handlers/entity/tolerance.cjs.map +7 -0
- package/lib/handlers/entity/tolerance.js +55 -0
- package/lib/handlers/entity/tolerance.js.map +7 -0
- package/lib/handlers/objects.cjs +257 -136
- package/lib/handlers/objects.cjs.map +2 -2
- package/lib/handlers/objects.js +257 -136
- package/lib/handlers/objects.js.map +2 -2
- package/lib/toSVG.cjs +71 -8
- package/lib/toSVG.cjs.map +3 -3
- package/lib/toSVG.js +72 -9
- package/lib/toSVG.js.map +2 -2
- package/lib/types/dimension-entity.cjs.map +1 -1
- package/lib/types/entity.cjs.map +1 -1
- package/lib/types/image-entity.cjs +17 -0
- package/lib/types/image-entity.cjs.map +7 -0
- package/lib/types/image-entity.js +1 -0
- package/lib/types/image-entity.js.map +7 -0
- package/lib/types/index.cjs +8 -0
- package/lib/types/index.cjs.map +2 -2
- package/lib/types/index.js +4 -0
- package/lib/types/index.js.map +2 -2
- package/lib/types/leader-entity.cjs +17 -0
- package/lib/types/leader-entity.cjs.map +7 -0
- package/lib/types/leader-entity.js +1 -0
- package/lib/types/leader-entity.js.map +7 -0
- package/lib/types/options.cjs.map +1 -1
- package/lib/types/tables.cjs.map +1 -1
- package/lib/types/tolerance-entity.cjs +17 -0
- package/lib/types/tolerance-entity.cjs.map +7 -0
- package/lib/types/tolerance-entity.js +1 -0
- package/lib/types/tolerance-entity.js.map +7 -0
- package/lib/types/underlay-entity.cjs +17 -0
- package/lib/types/underlay-entity.cjs.map +7 -0
- package/lib/types/underlay-entity.js +1 -0
- package/lib/types/underlay-entity.js.map +7 -0
- package/lib/util/escapeXmlText.cjs +27 -0
- package/lib/util/escapeXmlText.cjs.map +7 -0
- package/lib/util/escapeXmlText.js +7 -0
- package/lib/util/escapeXmlText.js.map +7 -0
- package/package.json +13 -4
- package/playwright.config.cjs +20 -0
- package/src/Helper.ts +3 -3
- package/src/denormalise.ts +182 -116
- package/src/dimensionToSVG.ts +466 -54
- package/src/handlers/entities.ts +109 -34
- package/src/handlers/entity/dgnUnderlay.ts +94 -0
- package/src/handlers/entity/dimension.ts +27 -1
- package/src/handlers/entity/dwfUnderlay.ts +94 -0
- package/src/handlers/entity/image.ts +118 -0
- package/src/handlers/entity/leader.ts +153 -0
- package/src/handlers/entity/pdfUnderlay.ts +94 -0
- package/src/handlers/entity/tolerance.ts +75 -0
- package/src/handlers/objects.ts +323 -139
- package/src/toSVG.ts +98 -7
- package/src/types/dimension-entity.ts +11 -0
- package/src/types/entity.ts +10 -0
- package/src/types/image-entity.ts +35 -0
- package/src/types/index.ts +4 -0
- package/src/types/leader-entity.ts +40 -0
- package/src/types/options.ts +41 -0
- package/src/types/tables.ts +84 -0
- package/src/types/tolerance-entity.ts +20 -0
- package/src/types/underlay-entity.ts +35 -0
- package/src/util/escapeXmlText.ts +10 -0
- package/tools/browser_test_server.cjs +87 -0
- package/tools/ezdxf_generate_dimensions_all_types.py +246 -0
- package/tools/ezdxf_generate_dimensions_angular_3p.py +59 -0
- package/tools/ezdxf_generate_dimensions_large_scale.py +87 -0
- package/tools/ezdxf_regenerate_problem_fixtures.py +184 -0
- package/tools/ezdxf_validate_fixtures.py +165 -0
- package/docs/DIMENSION_SUMMARY.pt-BR.md +0 -248
- package/docs/IMPLEMENTED-2D-ENTITIES.pt-BR.md +0 -54
- package/docs/TEXT-MTEXT-DIMENSION-SUPPORT.pt-BR.md +0 -169
package/lib/dimensionToSVG.js
CHANGED
|
@@ -1,5 +1,167 @@
|
|
|
1
1
|
import { Box2 } from "vecks";
|
|
2
2
|
import colors from "./util/colors";
|
|
3
|
+
import escapeXmlText from "./util/escapeXmlText";
|
|
4
|
+
import round10 from "./util/round10";
|
|
5
|
+
const DEFAULT_DIMENSION_DECIMALS = 2;
|
|
6
|
+
const AUTOSCALE_VIEWPORT_REFERENCE = 40;
|
|
7
|
+
const computeViewportAutoScaleFactor = (viewport, options) => {
|
|
8
|
+
const viewportMin = Math.min(Math.abs(viewport.width), Math.abs(viewport.height));
|
|
9
|
+
if (!Number.isFinite(viewportMin) || viewportMin <= 0) return 1;
|
|
10
|
+
const reference = options?.dimension?.autoScaleViewportReference;
|
|
11
|
+
const safeReference = Number.isFinite(reference) && (reference ?? 0) > 0 ? reference : AUTOSCALE_VIEWPORT_REFERENCE;
|
|
12
|
+
return viewportMin / safeReference;
|
|
13
|
+
};
|
|
14
|
+
const getViewportMin = (viewport) => {
|
|
15
|
+
const viewportMin = Math.min(Math.abs(viewport.width), Math.abs(viewport.height));
|
|
16
|
+
return Number.isFinite(viewportMin) ? viewportMin : Number.NaN;
|
|
17
|
+
};
|
|
18
|
+
const getViewportPercentageSize = (viewport, percent) => {
|
|
19
|
+
if (!Number.isFinite(percent) || (percent ?? 0) <= 0) return void 0;
|
|
20
|
+
const viewportMin = getViewportMin(viewport);
|
|
21
|
+
if (!Number.isFinite(viewportMin) || viewportMin <= 0) return void 0;
|
|
22
|
+
return viewportMin * (percent / 100);
|
|
23
|
+
};
|
|
24
|
+
const getDimensionGeometryBBox = (entity) => {
|
|
25
|
+
const bbox = new Box2();
|
|
26
|
+
const points = [
|
|
27
|
+
entity.start,
|
|
28
|
+
entity.angleVertex,
|
|
29
|
+
entity.arcPoint,
|
|
30
|
+
entity.textMidpoint,
|
|
31
|
+
entity.measureStart,
|
|
32
|
+
entity.measureEnd
|
|
33
|
+
];
|
|
34
|
+
for (const p of points) {
|
|
35
|
+
if (!p) continue;
|
|
36
|
+
const x = p.x;
|
|
37
|
+
const y = p.y;
|
|
38
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) continue;
|
|
39
|
+
bbox.expandByPoint({ x, y });
|
|
40
|
+
}
|
|
41
|
+
return bbox;
|
|
42
|
+
};
|
|
43
|
+
const getScaledDimensionSizes = (dimStyle, options, viewport) => {
|
|
44
|
+
const autoScale = options?.dimension?.autoScale === true;
|
|
45
|
+
const baseArrowSize = dimStyle?.dimAsz ?? 2.5;
|
|
46
|
+
const baseTextHeight = dimStyle?.dimTxt ?? 2.5;
|
|
47
|
+
const baseExtLineOffset = dimStyle?.dimExo ?? 0.625;
|
|
48
|
+
const baseExtLineExtension = dimStyle?.dimExe ?? 1.25;
|
|
49
|
+
if (!autoScale || !viewport) {
|
|
50
|
+
return {
|
|
51
|
+
arrowSize: baseArrowSize,
|
|
52
|
+
textHeight: baseTextHeight,
|
|
53
|
+
extLineOffset: baseExtLineOffset,
|
|
54
|
+
extLineExtension: baseExtLineExtension
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const scale = computeViewportAutoScaleFactor(viewport, options);
|
|
58
|
+
const perc = options?.dimension?.autoScaleViewportPercentages;
|
|
59
|
+
const arrowFromPct = getViewportPercentageSize(viewport, perc?.arrowSize);
|
|
60
|
+
const textFromPct = getViewportPercentageSize(viewport, perc?.textHeight);
|
|
61
|
+
const offsetFromPct = getViewportPercentageSize(viewport, perc?.extLineOffset);
|
|
62
|
+
const extensionFromPct = getViewportPercentageSize(viewport, perc?.extLineExtension);
|
|
63
|
+
return {
|
|
64
|
+
arrowSize: arrowFromPct ?? baseArrowSize * scale,
|
|
65
|
+
textHeight: textFromPct ?? baseTextHeight * scale,
|
|
66
|
+
extLineOffset: offsetFromPct ?? baseExtLineOffset * scale,
|
|
67
|
+
extLineExtension: extensionFromPct ?? baseExtLineExtension * scale
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
const formatDimensionValue = (value, decimals = DEFAULT_DIMENSION_DECIMALS) => {
|
|
71
|
+
if (!Number.isFinite(value)) return "";
|
|
72
|
+
const rounded = round10(value, -decimals);
|
|
73
|
+
return rounded.toFixed(decimals);
|
|
74
|
+
};
|
|
75
|
+
const computeRadiusFallback = (entity) => {
|
|
76
|
+
const cx = entity.start?.x ?? 0;
|
|
77
|
+
const cy = entity.start?.y ?? 0;
|
|
78
|
+
const x1 = entity.measureStart?.x ?? 0;
|
|
79
|
+
const y1 = entity.measureStart?.y ?? 0;
|
|
80
|
+
const x2 = entity.measureEnd?.x ?? 0;
|
|
81
|
+
const y2 = entity.measureEnd?.y ?? 0;
|
|
82
|
+
const r1 = Math.hypot(x1 - cx, y1 - cy);
|
|
83
|
+
const r2 = Math.hypot(x2 - cx, y2 - cy);
|
|
84
|
+
const chord = Math.hypot(x2 - x1, y2 - y1);
|
|
85
|
+
return Math.max(r1, r2, chord);
|
|
86
|
+
};
|
|
87
|
+
const computeLinearDistance = (x1, y1, x2, y2) => Math.hypot(x2 - x1, y2 - y1);
|
|
88
|
+
const computeAngularDegreesMinimal = (cx, cy, x1, y1, x2, y2) => {
|
|
89
|
+
const a1 = Math.atan2(y1 - cy, x1 - cx);
|
|
90
|
+
const a2 = Math.atan2(y2 - cy, x2 - cx);
|
|
91
|
+
let delta = Math.abs(a2 - a1);
|
|
92
|
+
while (delta > Math.PI * 2) delta -= Math.PI * 2;
|
|
93
|
+
if (delta > Math.PI) delta = Math.PI * 2 - delta;
|
|
94
|
+
return delta * 180 / Math.PI;
|
|
95
|
+
};
|
|
96
|
+
const computeAngularDegreesCCW = (cx, cy, x1, y1, x2, y2) => {
|
|
97
|
+
const a1 = Math.atan2(y1 - cy, x1 - cx);
|
|
98
|
+
const a2 = Math.atan2(y2 - cy, x2 - cx);
|
|
99
|
+
let delta = a2 - a1;
|
|
100
|
+
while (delta < 0) delta += Math.PI * 2;
|
|
101
|
+
while (delta >= Math.PI * 2) delta -= Math.PI * 2;
|
|
102
|
+
return delta * 180 / Math.PI;
|
|
103
|
+
};
|
|
104
|
+
const computeDimensionMeasurement = (entity) => {
|
|
105
|
+
const x1 = entity.measureStart?.x ?? 0;
|
|
106
|
+
const y1 = entity.measureStart?.y ?? 0;
|
|
107
|
+
const x2 = entity.measureEnd?.x ?? 0;
|
|
108
|
+
const y2 = entity.measureEnd?.y ?? 0;
|
|
109
|
+
switch (entity.dimensionType) {
|
|
110
|
+
case 0:
|
|
111
|
+
case 1:
|
|
112
|
+
case 6: {
|
|
113
|
+
const dist = computeLinearDistance(x1, y1, x2, y2);
|
|
114
|
+
return formatDimensionValue(dist);
|
|
115
|
+
}
|
|
116
|
+
case 3: {
|
|
117
|
+
const dist = computeLinearDistance(x1, y1, x2, y2);
|
|
118
|
+
if (dist > 0) return formatDimensionValue(dist);
|
|
119
|
+
const radius = computeRadiusFallback(entity);
|
|
120
|
+
return formatDimensionValue(radius * 2);
|
|
121
|
+
}
|
|
122
|
+
case 4: {
|
|
123
|
+
const dist = computeLinearDistance(x1, y1, x2, y2);
|
|
124
|
+
if (dist > 0) return formatDimensionValue(dist);
|
|
125
|
+
const radius = computeRadiusFallback(entity);
|
|
126
|
+
return formatDimensionValue(radius);
|
|
127
|
+
}
|
|
128
|
+
case 2: {
|
|
129
|
+
const cx = entity.start?.x ?? 0;
|
|
130
|
+
const cy = entity.start?.y ?? 0;
|
|
131
|
+
const degrees = computeAngularDegreesMinimal(cx, cy, x1, y1, x2, y2);
|
|
132
|
+
const formatted = formatDimensionValue(degrees);
|
|
133
|
+
return formatted ? `${formatted}\xB0` : "";
|
|
134
|
+
}
|
|
135
|
+
case 5: {
|
|
136
|
+
const cx = entity.angleVertex?.x ?? 0;
|
|
137
|
+
const cy = entity.angleVertex?.y ?? 0;
|
|
138
|
+
const degrees = computeAngularDegreesCCW(cx, cy, x1, y1, x2, y2);
|
|
139
|
+
const formatted = formatDimensionValue(degrees);
|
|
140
|
+
return formatted ? `${formatted}\xB0` : "";
|
|
141
|
+
}
|
|
142
|
+
default:
|
|
143
|
+
return "";
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const resolveDimensionText = (entity) => {
|
|
147
|
+
const raw = typeof entity.text === "string" ? entity.text : "";
|
|
148
|
+
const trimmed = raw.trim();
|
|
149
|
+
const measured = computeDimensionMeasurement(entity);
|
|
150
|
+
if (!trimmed) return measured;
|
|
151
|
+
if (trimmed.includes("<>")) {
|
|
152
|
+
return trimmed.split("<>").join(measured);
|
|
153
|
+
}
|
|
154
|
+
return trimmed;
|
|
155
|
+
};
|
|
156
|
+
const expandBBoxForMarker = (bbox, x, y, size) => {
|
|
157
|
+
bbox.expandByPoint({ x: x - size, y: y - size });
|
|
158
|
+
bbox.expandByPoint({ x: x + size, y: y + size });
|
|
159
|
+
};
|
|
160
|
+
const expandBBoxForText = (bbox, x, y, height, content) => {
|
|
161
|
+
const textWidth = content.length * height * 0.6;
|
|
162
|
+
bbox.expandByPoint({ x: x - textWidth / 2, y: y - height });
|
|
163
|
+
bbox.expandByPoint({ x: x + textWidth / 2, y: y + height });
|
|
164
|
+
};
|
|
3
165
|
function colorNumberToSVG(colorNumber) {
|
|
4
166
|
if (colorNumber === void 0 || colorNumber < 0) {
|
|
5
167
|
return "currentColor";
|
|
@@ -22,38 +184,117 @@ function getDimensionColors(dimStyle) {
|
|
|
22
184
|
extLineWeight: dimStyle?.dimLwe ?? 0.5
|
|
23
185
|
};
|
|
24
186
|
}
|
|
25
|
-
function dimensionToSVG(entity, dimStyle) {
|
|
187
|
+
function dimensionToSVG(entity, dimStyle, options, viewport) {
|
|
26
188
|
switch (entity.dimensionType) {
|
|
27
189
|
case 0:
|
|
28
190
|
// Rotated, horizontal, or vertical
|
|
29
191
|
case 1:
|
|
30
|
-
return renderLinearDimension(entity, dimStyle);
|
|
192
|
+
return renderLinearDimension(entity, dimStyle, options, viewport);
|
|
31
193
|
case 2:
|
|
32
|
-
return renderAngularDimension(entity, dimStyle);
|
|
194
|
+
return renderAngularDimension(entity, dimStyle, options, viewport);
|
|
195
|
+
case 5:
|
|
196
|
+
return renderAngular3PointDimension(entity, dimStyle, options, viewport);
|
|
33
197
|
case 3:
|
|
34
|
-
return renderDiameterDimension(entity, dimStyle);
|
|
198
|
+
return renderDiameterDimension(entity, dimStyle, options, viewport);
|
|
35
199
|
case 4:
|
|
36
|
-
return renderRadialDimension(entity, dimStyle);
|
|
200
|
+
return renderRadialDimension(entity, dimStyle, options, viewport);
|
|
37
201
|
case 6:
|
|
38
|
-
return renderOrdinateDimension(entity, dimStyle);
|
|
202
|
+
return renderOrdinateDimension(entity, dimStyle, options, viewport);
|
|
39
203
|
default:
|
|
40
204
|
return renderFallbackDimension(entity);
|
|
41
205
|
}
|
|
42
206
|
}
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
|
|
207
|
+
function renderAngular3PointDimension(entity, dimStyle, options, viewport) {
|
|
208
|
+
const bbox = new Box2();
|
|
209
|
+
const elements = [];
|
|
210
|
+
const markers = [];
|
|
211
|
+
const { arrowSize, textHeight } = getScaledDimensionSizes(dimStyle, options, viewport);
|
|
212
|
+
const { dimLineColor, extLineColor, textColor, dimLineWeight, extLineWeight } = getDimensionColors(dimStyle);
|
|
213
|
+
const vertexX = entity.angleVertex?.x ?? 0;
|
|
214
|
+
const vertexY = entity.angleVertex?.y ?? 0;
|
|
215
|
+
const x1 = entity.measureStart?.x ?? 0;
|
|
216
|
+
const y1 = entity.measureStart?.y ?? 0;
|
|
217
|
+
const x2 = entity.measureEnd?.x ?? 0;
|
|
218
|
+
const y2 = entity.measureEnd?.y ?? 0;
|
|
219
|
+
const startArcX = entity.start?.x ?? 0;
|
|
220
|
+
const startArcY = entity.start?.y ?? 0;
|
|
221
|
+
const arcPointX = entity.arcPoint?.x;
|
|
222
|
+
const arcPointY = entity.arcPoint?.y;
|
|
223
|
+
const arcPointRadius = Number.isFinite(arcPointX) && Number.isFinite(arcPointY) ? Math.hypot(arcPointX - vertexX, arcPointY - vertexY) : Number.NaN;
|
|
224
|
+
const useArcPoint = Number.isFinite(arcPointRadius) && arcPointRadius > 1e-9;
|
|
225
|
+
const arcLocationX = useArcPoint ? arcPointX : startArcX;
|
|
226
|
+
const arcLocationY = useArcPoint ? arcPointY : startArcY;
|
|
227
|
+
const textX = entity.textMidpoint?.x ?? arcLocationX;
|
|
228
|
+
const textY = entity.textMidpoint?.y ?? arcLocationY;
|
|
229
|
+
bbox.expandByPoint({ x: vertexX, y: vertexY });
|
|
230
|
+
bbox.expandByPoint({ x: x1, y: y1 });
|
|
231
|
+
bbox.expandByPoint({ x: x2, y: y2 });
|
|
232
|
+
bbox.expandByPoint({ x: arcLocationX, y: arcLocationY });
|
|
233
|
+
bbox.expandByPoint({ x: textX, y: textY });
|
|
234
|
+
const a1 = Math.atan2(y1 - vertexY, x1 - vertexX);
|
|
235
|
+
const a2 = Math.atan2(y2 - vertexY, x2 - vertexX);
|
|
236
|
+
let radius = Math.hypot(arcLocationX - vertexX, arcLocationY - vertexY);
|
|
237
|
+
if (!Number.isFinite(radius) || radius <= 1e-9) {
|
|
238
|
+
radius = Math.hypot(textX - vertexX, textY - vertexY);
|
|
239
|
+
}
|
|
240
|
+
if (!Number.isFinite(radius) || radius <= 1e-9) {
|
|
241
|
+
radius = Math.max(
|
|
242
|
+
Math.hypot(x1 - vertexX, y1 - vertexY),
|
|
243
|
+
Math.hypot(x2 - vertexX, y2 - vertexY)
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
const arcStartX = vertexX + radius * Math.cos(a1);
|
|
247
|
+
const arcStartY = vertexY + radius * Math.sin(a1);
|
|
248
|
+
const arcEndX = vertexX + radius * Math.cos(a2);
|
|
249
|
+
const arcEndY = vertexY + radius * Math.sin(a2);
|
|
250
|
+
bbox.expandByPoint({ x: arcStartX, y: arcStartY });
|
|
251
|
+
bbox.expandByPoint({ x: arcEndX, y: arcEndY });
|
|
252
|
+
const markerId1 = `dim-angular-3p-arrow-start-${Date.now()}`;
|
|
253
|
+
const markerId2 = `dim-angular-3p-arrow-end-${Date.now()}`;
|
|
254
|
+
markers.push(
|
|
255
|
+
createArrowMarker(markerId1, arrowSize, dimLineColor, "backward"),
|
|
256
|
+
createArrowMarker(markerId2, arrowSize, dimLineColor, "forward")
|
|
257
|
+
);
|
|
258
|
+
elements.push(
|
|
259
|
+
`<line x1="${x1}" y1="${y1}" x2="${arcStartX}" y2="${arcStartY}" stroke="${extLineColor}" stroke-width="${extLineWeight}" />`,
|
|
260
|
+
`<line x1="${x2}" y1="${y2}" x2="${arcEndX}" y2="${arcEndY}" stroke="${extLineColor}" stroke-width="${extLineWeight}" />`
|
|
261
|
+
);
|
|
262
|
+
let delta = a2 - a1;
|
|
263
|
+
while (delta < 0) delta += Math.PI * 2;
|
|
264
|
+
while (delta >= Math.PI * 2) delta -= Math.PI * 2;
|
|
265
|
+
const largeArcFlag = delta > Math.PI ? 1 : 0;
|
|
266
|
+
const sweepFlag = 1;
|
|
267
|
+
expandBBoxForMarker(bbox, arcStartX, arcStartY, arrowSize);
|
|
268
|
+
expandBBoxForMarker(bbox, arcEndX, arcEndY, arrowSize);
|
|
269
|
+
elements.push(
|
|
270
|
+
`<path d="M ${arcStartX} ${arcStartY} A ${radius} ${radius} 0 ${largeArcFlag} ${sweepFlag} ${arcEndX} ${arcEndY}" fill="none" stroke="${dimLineColor}" stroke-width="${dimLineWeight}" marker-start="url(#${markerId1})" marker-end="url(#${markerId2})" />`
|
|
271
|
+
);
|
|
272
|
+
const resolvedText = resolveDimensionText(entity);
|
|
273
|
+
if (resolvedText) {
|
|
274
|
+
const midAngle = a1 + delta / 2;
|
|
275
|
+
const textRotation = midAngle * 180 / Math.PI;
|
|
276
|
+
expandBBoxForText(bbox, textX, textY, textHeight, resolvedText);
|
|
277
|
+
elements.push(
|
|
278
|
+
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${escapeXmlText(resolvedText)}</text>`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
bbox,
|
|
283
|
+
element: `<defs>${markers.join("")}</defs><g>${elements.join("")}</g>`
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function createArrowMarker(id, size, color, direction = "forward") {
|
|
287
|
+
const arrowPath = direction === "forward" ? `M 0 0 L ${size} ${size / 2} L 0 ${size} z` : `M ${size} 0 L 0 ${size / 2} L ${size} ${size} z`;
|
|
288
|
+
const refX = direction === "forward" ? size : 0;
|
|
289
|
+
return `<marker id="${id}" markerWidth="${size}" markerHeight="${size}" refX="${refX}" refY="${size / 2}" orient="auto" markerUnits="userSpaceOnUse">
|
|
46
290
|
<path d="${arrowPath}" fill="${color}" />
|
|
47
291
|
</marker>`;
|
|
48
292
|
}
|
|
49
|
-
function renderLinearDimension(entity, dimStyle) {
|
|
293
|
+
function renderLinearDimension(entity, dimStyle, options, viewport) {
|
|
50
294
|
const bbox = new Box2();
|
|
51
295
|
const elements = [];
|
|
52
296
|
const markers = [];
|
|
53
|
-
const arrowSize = dimStyle
|
|
54
|
-
const textHeight = dimStyle?.dimTxt ?? 2.5;
|
|
55
|
-
const extLineOffset = dimStyle?.dimExo ?? 0.625;
|
|
56
|
-
const extLineExtension = dimStyle?.dimExe ?? 1.25;
|
|
297
|
+
const { arrowSize, textHeight, extLineOffset, extLineExtension } = getScaledDimensionSizes(dimStyle, options, viewport);
|
|
57
298
|
const { dimLineColor, extLineColor, textColor, dimLineWeight, extLineWeight } = getDimensionColors(dimStyle);
|
|
58
299
|
const defPoint1X = entity.measureStart?.x ?? 0;
|
|
59
300
|
const defPoint1Y = entity.measureStart?.y ?? 0;
|
|
@@ -76,8 +317,8 @@ function renderLinearDimension(entity, dimStyle) {
|
|
|
76
317
|
const markerId1 = `dim-arrow-start-${Date.now()}`;
|
|
77
318
|
const markerId2 = `dim-arrow-end-${Date.now()}`;
|
|
78
319
|
markers.push(
|
|
79
|
-
createArrowMarker(markerId1, arrowSize, dimLineColor),
|
|
80
|
-
createArrowMarker(markerId2, arrowSize, dimLineColor)
|
|
320
|
+
createArrowMarker(markerId1, arrowSize, dimLineColor, "backward"),
|
|
321
|
+
createArrowMarker(markerId2, arrowSize, dimLineColor, "forward")
|
|
81
322
|
);
|
|
82
323
|
const extLine1StartX = defPoint1X + Math.cos(perpAngle) * extLineOffset;
|
|
83
324
|
const extLine1StartY = defPoint1Y + Math.sin(perpAngle) * extLineOffset;
|
|
@@ -87,15 +328,23 @@ function renderLinearDimension(entity, dimStyle) {
|
|
|
87
328
|
const extLine2StartY = defPoint2Y + Math.sin(perpAngle) * extLineOffset;
|
|
88
329
|
const extLine2EndX = dimLine2X + Math.cos(perpAngle) * extLineExtension;
|
|
89
330
|
const extLine2EndY = dimLine2Y + Math.sin(perpAngle) * extLineExtension;
|
|
331
|
+
bbox.expandByPoint({ x: extLine1StartX, y: extLine1StartY });
|
|
332
|
+
bbox.expandByPoint({ x: extLine1EndX, y: extLine1EndY });
|
|
333
|
+
bbox.expandByPoint({ x: extLine2StartX, y: extLine2StartY });
|
|
334
|
+
bbox.expandByPoint({ x: extLine2EndX, y: extLine2EndY });
|
|
335
|
+
expandBBoxForMarker(bbox, dimLine1X, dimLine1Y, arrowSize);
|
|
336
|
+
expandBBoxForMarker(bbox, dimLine2X, dimLine2Y, arrowSize);
|
|
90
337
|
elements.push(
|
|
91
338
|
`<line x1="${extLine1StartX}" y1="${extLine1StartY}" x2="${extLine1EndX}" y2="${extLine1EndY}" stroke="${extLineColor}" stroke-width="${extLineWeight}" />`,
|
|
92
339
|
`<line x1="${extLine2StartX}" y1="${extLine2StartY}" x2="${extLine2EndX}" y2="${extLine2EndY}" stroke="${extLineColor}" stroke-width="${extLineWeight}" />`,
|
|
93
340
|
`<line x1="${dimLine1X}" y1="${dimLine1Y}" x2="${dimLine2X}" y2="${dimLine2Y}" stroke="${dimLineColor}" stroke-width="${dimLineWeight}" marker-start="url(#${markerId1})" marker-end="url(#${markerId2})" />`
|
|
94
341
|
);
|
|
95
|
-
|
|
342
|
+
const resolvedText = resolveDimensionText(entity);
|
|
343
|
+
if (resolvedText) {
|
|
96
344
|
const textRotation = angle * 180 / Math.PI;
|
|
345
|
+
expandBBoxForText(bbox, textX, textY, textHeight, resolvedText);
|
|
97
346
|
elements.push(
|
|
98
|
-
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${
|
|
347
|
+
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${escapeXmlText(resolvedText)}</text>`
|
|
99
348
|
);
|
|
100
349
|
}
|
|
101
350
|
return {
|
|
@@ -103,12 +352,11 @@ function renderLinearDimension(entity, dimStyle) {
|
|
|
103
352
|
element: `<defs>${markers.join("")}</defs><g>${elements.join("")}</g>`
|
|
104
353
|
};
|
|
105
354
|
}
|
|
106
|
-
function renderAngularDimension(entity, dimStyle) {
|
|
355
|
+
function renderAngularDimension(entity, dimStyle, options, viewport) {
|
|
107
356
|
const bbox = new Box2();
|
|
108
357
|
const elements = [];
|
|
109
358
|
const markers = [];
|
|
110
|
-
const arrowSize = dimStyle
|
|
111
|
-
const textHeight = dimStyle?.dimTxt ?? 2.5;
|
|
359
|
+
const { arrowSize, textHeight } = getScaledDimensionSizes(dimStyle, options, viewport);
|
|
112
360
|
const { dimLineColor, extLineColor, textColor, dimLineWeight, extLineWeight } = getDimensionColors(dimStyle);
|
|
113
361
|
const centerX = entity.start?.x ?? 0;
|
|
114
362
|
const centerY = entity.start?.y ?? 0;
|
|
@@ -125,8 +373,8 @@ function renderAngularDimension(entity, dimStyle) {
|
|
|
125
373
|
const markerId1 = `dim-angular-arrow-start-${Date.now()}`;
|
|
126
374
|
const markerId2 = `dim-angular-arrow-end-${Date.now()}`;
|
|
127
375
|
markers.push(
|
|
128
|
-
createArrowMarker(markerId1, arrowSize, dimLineColor),
|
|
129
|
-
createArrowMarker(markerId2, arrowSize, dimLineColor)
|
|
376
|
+
createArrowMarker(markerId1, arrowSize, dimLineColor, "backward"),
|
|
377
|
+
createArrowMarker(markerId2, arrowSize, dimLineColor, "forward")
|
|
130
378
|
);
|
|
131
379
|
elements.push(
|
|
132
380
|
`<line x1="${centerX}" y1="${centerY}" x2="${x1}" y2="${y1}" stroke="${extLineColor}" stroke-width="${extLineWeight}" />`,
|
|
@@ -143,11 +391,13 @@ function renderAngularDimension(entity, dimStyle) {
|
|
|
143
391
|
elements.push(
|
|
144
392
|
`<path d="M ${arcStartX} ${arcStartY} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${arcEndX} ${arcEndY}" fill="none" stroke="${dimLineColor}" stroke-width="${dimLineWeight}" marker-start="url(#${markerId1})" marker-end="url(#${markerId2})" />`
|
|
145
393
|
);
|
|
146
|
-
|
|
394
|
+
const resolvedText = resolveDimensionText(entity);
|
|
395
|
+
if (resolvedText) {
|
|
147
396
|
const midAngle = (startAngle + endAngle) / 2;
|
|
148
397
|
const textRotation = midAngle * 180 / Math.PI;
|
|
398
|
+
expandBBoxForText(bbox, textX, textY, textHeight, resolvedText);
|
|
149
399
|
elements.push(
|
|
150
|
-
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${
|
|
400
|
+
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${escapeXmlText(resolvedText)}</text>`
|
|
151
401
|
);
|
|
152
402
|
}
|
|
153
403
|
return {
|
|
@@ -155,12 +405,11 @@ function renderAngularDimension(entity, dimStyle) {
|
|
|
155
405
|
element: `<defs>${markers.join("")}</defs><g>${elements.join("")}</g>`
|
|
156
406
|
};
|
|
157
407
|
}
|
|
158
|
-
function renderDiameterDimension(entity, dimStyle) {
|
|
408
|
+
function renderDiameterDimension(entity, dimStyle, options, viewport) {
|
|
159
409
|
const bbox = new Box2();
|
|
160
410
|
const elements = [];
|
|
161
411
|
const markers = [];
|
|
162
|
-
const arrowSize = dimStyle
|
|
163
|
-
const textHeight = dimStyle?.dimTxt ?? 2.5;
|
|
412
|
+
const { arrowSize, textHeight } = getScaledDimensionSizes(dimStyle, options, viewport);
|
|
164
413
|
const { dimLineColor, textColor, dimLineWeight } = getDimensionColors(dimStyle);
|
|
165
414
|
const x1 = entity.measureStart?.x ?? 0;
|
|
166
415
|
const y1 = entity.measureStart?.y ?? 0;
|
|
@@ -171,28 +420,33 @@ function renderDiameterDimension(entity, dimStyle) {
|
|
|
171
420
|
bbox.expandByPoint({ x: x1, y: y1 });
|
|
172
421
|
bbox.expandByPoint({ x: x2, y: y2 });
|
|
173
422
|
bbox.expandByPoint({ x: textX, y: textY });
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
423
|
+
const diameterLen = Math.hypot(x2 - x1, y2 - y1);
|
|
424
|
+
if (Number.isFinite(diameterLen) && diameterLen > 1e-6) {
|
|
425
|
+
const markerId = `dim-diameter-arrow-${Date.now()}`;
|
|
426
|
+
markers.push(createArrowMarker(markerId, arrowSize, dimLineColor, "backward"));
|
|
427
|
+
elements.push(
|
|
428
|
+
`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${dimLineColor}" stroke-width="${dimLineWeight}" marker-end="url(#${markerId})" />`
|
|
429
|
+
);
|
|
430
|
+
expandBBoxForMarker(bbox, x2, y2, arrowSize);
|
|
431
|
+
}
|
|
432
|
+
const resolvedText = resolveDimensionText(entity);
|
|
433
|
+
const diameterText = resolvedText ? `\u2300${resolvedText}` : "\u2300";
|
|
180
434
|
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
181
435
|
const textRotation = angle * 180 / Math.PI;
|
|
436
|
+
expandBBoxForText(bbox, textX, textY, textHeight, diameterText);
|
|
182
437
|
elements.push(
|
|
183
|
-
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${diameterText}</text>`
|
|
438
|
+
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${escapeXmlText(diameterText)}</text>`
|
|
184
439
|
);
|
|
185
440
|
return {
|
|
186
441
|
bbox,
|
|
187
442
|
element: `<defs>${markers.join("")}</defs><g>${elements.join("")}</g>`
|
|
188
443
|
};
|
|
189
444
|
}
|
|
190
|
-
function renderRadialDimension(entity, dimStyle) {
|
|
445
|
+
function renderRadialDimension(entity, dimStyle, options, viewport) {
|
|
191
446
|
const bbox = new Box2();
|
|
192
447
|
const elements = [];
|
|
193
448
|
const markers = [];
|
|
194
|
-
const arrowSize = dimStyle
|
|
195
|
-
const textHeight = dimStyle?.dimTxt ?? 2.5;
|
|
449
|
+
const { arrowSize, textHeight } = getScaledDimensionSizes(dimStyle, options, viewport);
|
|
196
450
|
const { dimLineColor, textColor, dimLineWeight } = getDimensionColors(dimStyle);
|
|
197
451
|
const x1 = entity.measureStart?.x ?? 0;
|
|
198
452
|
const y1 = entity.measureStart?.y ?? 0;
|
|
@@ -203,26 +457,32 @@ function renderRadialDimension(entity, dimStyle) {
|
|
|
203
457
|
bbox.expandByPoint({ x: x1, y: y1 });
|
|
204
458
|
bbox.expandByPoint({ x: x2, y: y2 });
|
|
205
459
|
bbox.expandByPoint({ x: textX, y: textY });
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
460
|
+
const radiusLen = Math.hypot(x2 - x1, y2 - y1);
|
|
461
|
+
if (Number.isFinite(radiusLen) && radiusLen > 1e-6) {
|
|
462
|
+
const markerId = `dim-radius-arrow-${Date.now()}`;
|
|
463
|
+
markers.push(createArrowMarker(markerId, arrowSize, dimLineColor, "backward"));
|
|
464
|
+
elements.push(
|
|
465
|
+
`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${dimLineColor}" stroke-width="${dimLineWeight}" marker-end="url(#${markerId})" />`
|
|
466
|
+
);
|
|
467
|
+
expandBBoxForMarker(bbox, x2, y2, arrowSize);
|
|
468
|
+
}
|
|
469
|
+
const resolvedText = resolveDimensionText(entity);
|
|
470
|
+
const radiusText = resolvedText ? `R${resolvedText}` : "R";
|
|
212
471
|
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
213
472
|
const textRotation = angle * 180 / Math.PI;
|
|
473
|
+
expandBBoxForText(bbox, textX, textY, textHeight, radiusText);
|
|
214
474
|
elements.push(
|
|
215
|
-
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${radiusText}</text>`
|
|
475
|
+
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${escapeXmlText(radiusText)}</text>`
|
|
216
476
|
);
|
|
217
477
|
return {
|
|
218
478
|
bbox,
|
|
219
479
|
element: `<defs>${markers.join("")}</defs><g>${elements.join("")}</g>`
|
|
220
480
|
};
|
|
221
481
|
}
|
|
222
|
-
function renderOrdinateDimension(entity, dimStyle) {
|
|
482
|
+
function renderOrdinateDimension(entity, dimStyle, options, viewport) {
|
|
223
483
|
const bbox = new Box2();
|
|
224
484
|
const elements = [];
|
|
225
|
-
const textHeight = dimStyle
|
|
485
|
+
const { textHeight } = getScaledDimensionSizes(dimStyle, options, viewport);
|
|
226
486
|
const { dimLineColor, textColor, dimLineWeight } = getDimensionColors(dimStyle);
|
|
227
487
|
const x1 = entity.measureStart?.x ?? 0;
|
|
228
488
|
const y1 = entity.measureStart?.y ?? 0;
|
|
@@ -236,11 +496,13 @@ function renderOrdinateDimension(entity, dimStyle) {
|
|
|
236
496
|
elements.push(
|
|
237
497
|
`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${dimLineColor}" stroke-width="${dimLineWeight}" />`
|
|
238
498
|
);
|
|
239
|
-
|
|
499
|
+
const resolvedText = resolveDimensionText(entity);
|
|
500
|
+
if (resolvedText) {
|
|
240
501
|
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
241
502
|
const textRotation = angle * 180 / Math.PI;
|
|
503
|
+
expandBBoxForText(bbox, textX, textY, textHeight, resolvedText);
|
|
242
504
|
elements.push(
|
|
243
|
-
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${
|
|
505
|
+
`<text x="${textX}" y="${textY}" font-size="${textHeight}" fill="${textColor}" text-anchor="middle" transform="rotate(${-textRotation} ${textX} ${textY}) scale(1,-1) translate(0 ${-2 * textY})">${escapeXmlText(resolvedText)}</text>`
|
|
244
506
|
);
|
|
245
507
|
}
|
|
246
508
|
return {
|
|
@@ -255,9 +517,10 @@ function renderFallbackDimension(entity) {
|
|
|
255
517
|
const textX = entity.textMidpoint.x ?? 0;
|
|
256
518
|
const textY = entity.textMidpoint.y ?? 0;
|
|
257
519
|
bbox.expandByPoint({ x: textX, y: textY });
|
|
258
|
-
|
|
520
|
+
const resolvedText = resolveDimensionText(entity);
|
|
521
|
+
if (resolvedText) {
|
|
259
522
|
elements.push(
|
|
260
|
-
`<text x="${textX}" y="${textY}" font-size="2.5" text-anchor="middle" transform="scale(1,-1) translate(0 ${-2 * textY})">${
|
|
523
|
+
`<text x="${textX}" y="${textY}" font-size="2.5" text-anchor="middle" transform="scale(1,-1) translate(0 ${-2 * textY})">${escapeXmlText(resolvedText)}</text>`
|
|
261
524
|
);
|
|
262
525
|
}
|
|
263
526
|
}
|
|
@@ -268,6 +531,7 @@ function renderFallbackDimension(entity) {
|
|
|
268
531
|
}
|
|
269
532
|
export {
|
|
270
533
|
createArrowMarker,
|
|
271
|
-
dimensionToSVG as default
|
|
534
|
+
dimensionToSVG as default,
|
|
535
|
+
getDimensionGeometryBBox
|
|
272
536
|
};
|
|
273
537
|
//# sourceMappingURL=dimensionToSVG.js.map
|