brepjs 20.11.0 → 20.11.1
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/brepjs.cjs +368 -47
- package/dist/brepjs.js +368 -47
- package/dist/{importFns-D_tBVKl2.js → importFns-Cfw7SIjn.js} +46 -9
- package/dist/{importFns-DI3Q8B0Q.cjs → importFns-D5wRI_Cc.cjs} +46 -9
- package/dist/io/dxfExportFns.d.ts +2 -2
- package/dist/io/dxfImportFns.d.ts +4 -2
- package/dist/io.cjs +1 -1
- package/dist/io.js +1 -1
- package/package.json +1 -1
package/dist/brepjs.cjs
CHANGED
|
@@ -29,7 +29,7 @@ const require_measureFns = require("./measureFns-BoNCUOKe.cjs");
|
|
|
29
29
|
const require_cornerFinder = require("./cornerFinder-DVHtBOzM.cjs");
|
|
30
30
|
const require_boolean2D = require("./boolean2D-B21GheGE.cjs");
|
|
31
31
|
const require_blueprintFns = require("./blueprintFns-DDiWI0Ol.cjs");
|
|
32
|
-
const require_importFns = require("./importFns-
|
|
32
|
+
const require_importFns = require("./importFns-D5wRI_Cc.cjs");
|
|
33
33
|
const require_textBlueprints = require("./textBlueprints-jlqCGG4p.cjs");
|
|
34
34
|
const require_loftFns = require("./loftFns-tGsV_hHY.cjs");
|
|
35
35
|
const require_refResolveFns = require("./refResolveFns-DvDeMCVU.cjs");
|
|
@@ -6181,7 +6181,7 @@ function sub(a, b) {
|
|
|
6181
6181
|
function dot(a, b) {
|
|
6182
6182
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
6183
6183
|
}
|
|
6184
|
-
function cross(a, b) {
|
|
6184
|
+
function cross$1(a, b) {
|
|
6185
6185
|
return [
|
|
6186
6186
|
a[1] * b[2] - a[2] * b[1],
|
|
6187
6187
|
a[2] * b[0] - a[0] * b[2],
|
|
@@ -6205,7 +6205,7 @@ function normalize(a) {
|
|
|
6205
6205
|
}
|
|
6206
6206
|
/** A unit vector perpendicular to `v` (for the parallel-normals degenerate case). */
|
|
6207
6207
|
function anyPerpendicular(v) {
|
|
6208
|
-
return normalize(cross(v, Math.abs(v[0]) < .9 ? [
|
|
6208
|
+
return normalize(cross$1(v, Math.abs(v[0]) < .9 ? [
|
|
6209
6209
|
1,
|
|
6210
6210
|
0,
|
|
6211
6211
|
0
|
|
@@ -6285,7 +6285,7 @@ function solveAngle(ref, dep, angleRad) {
|
|
|
6285
6285
|
1
|
|
6286
6286
|
]);
|
|
6287
6287
|
const phi = Math.acos(Math.max(-1, Math.min(1, dot(nDep, nRef))));
|
|
6288
|
-
const c = cross(nDep, nRef);
|
|
6288
|
+
const c = cross$1(nDep, nRef);
|
|
6289
6289
|
const axis = Math.hypot(c[0], c[1], c[2]) < 1e-9 ? anyPerpendicular(nDep) : c;
|
|
6290
6290
|
return {
|
|
6291
6291
|
position: [
|
|
@@ -6792,63 +6792,378 @@ function parseEntities(text) {
|
|
|
6792
6792
|
current = {
|
|
6793
6793
|
type: value,
|
|
6794
6794
|
layer: "0",
|
|
6795
|
-
data: /* @__PURE__ */ new Map()
|
|
6795
|
+
data: /* @__PURE__ */ new Map(),
|
|
6796
|
+
pairs: []
|
|
6796
6797
|
};
|
|
6797
6798
|
continue;
|
|
6798
6799
|
}
|
|
6799
6800
|
if (current) {
|
|
6801
|
+
current.pairs.push([code, value]);
|
|
6800
6802
|
if (code === 8) current.layer = value;
|
|
6801
6803
|
else current.data.set(code, value);
|
|
6802
6804
|
}
|
|
6803
6805
|
}
|
|
6804
6806
|
return entities;
|
|
6805
6807
|
}
|
|
6806
|
-
function
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
const n = parseFloat(v);
|
|
6808
|
+
function num(value, fallback = 0) {
|
|
6809
|
+
if (value === void 0) return fallback;
|
|
6810
|
+
const n = parseFloat(value);
|
|
6810
6811
|
return isNaN(n) ? fallback : n;
|
|
6811
6812
|
}
|
|
6812
|
-
function
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6813
|
+
function getNum(data, code, fallback = 0) {
|
|
6814
|
+
return num(data.get(code), fallback);
|
|
6815
|
+
}
|
|
6816
|
+
/** LWPOLYLINE vertices: each 10 starts one and its 20 and 42 follow; 38 is the elevation. */
|
|
6817
|
+
function lwVertices(entity) {
|
|
6818
|
+
const z = getNum(entity.data, 38);
|
|
6819
|
+
const out = [];
|
|
6820
|
+
for (const [code, value] of entity.pairs) {
|
|
6821
|
+
const last = out[out.length - 1];
|
|
6822
|
+
if (code === 10) out.push({
|
|
6823
|
+
point: [
|
|
6824
|
+
num(value),
|
|
6825
|
+
0,
|
|
6826
|
+
z
|
|
6827
|
+
],
|
|
6828
|
+
bulge: 0
|
|
6829
|
+
});
|
|
6830
|
+
else if (code === 20 && last) last.point[1] = num(value);
|
|
6831
|
+
else if (code === 42 && last) last.bulge = num(value);
|
|
6832
|
+
}
|
|
6833
|
+
return out;
|
|
6834
|
+
}
|
|
6835
|
+
/**
|
|
6836
|
+
* The DXF R12 polyline: a POLYLINE header, its VERTEX entities, then SEQEND. They arrive as
|
|
6837
|
+
* separate entities, so the header gathers the vertices that follow it.
|
|
6838
|
+
*/
|
|
6839
|
+
function gatherPolylines(entities) {
|
|
6840
|
+
const out = [];
|
|
6841
|
+
for (let i = 0; i < entities.length; i++) {
|
|
6842
|
+
const e = entities[i];
|
|
6843
|
+
if (e === void 0) continue;
|
|
6844
|
+
if (e.type !== "POLYLINE") {
|
|
6845
|
+
if (e.type !== "VERTEX" && e.type !== "SEQEND") out.push(e);
|
|
6846
|
+
continue;
|
|
6847
|
+
}
|
|
6848
|
+
const vertices = [];
|
|
6849
|
+
let j = i + 1;
|
|
6850
|
+
for (; j < entities.length && entities[j]?.type === "VERTEX"; j++) {
|
|
6851
|
+
const v = entities[j];
|
|
6852
|
+
if (v === void 0) continue;
|
|
6853
|
+
vertices.push([10, v.data.get(10) ?? "0"], [20, v.data.get(20) ?? "0"], [30, v.data.get(30) ?? "0"], [42, v.data.get(42) ?? "0"]);
|
|
6854
|
+
}
|
|
6855
|
+
if (entities[j]?.type === "SEQEND") j++;
|
|
6856
|
+
const own = e.pairs.filter(([code]) => code !== 10 && code !== 20 && code !== 30);
|
|
6857
|
+
out.push({
|
|
6858
|
+
...e,
|
|
6859
|
+
pairs: [...own, ...vertices]
|
|
6860
|
+
});
|
|
6861
|
+
i = j - 1;
|
|
6862
|
+
}
|
|
6863
|
+
return out;
|
|
6864
|
+
}
|
|
6865
|
+
function polyVertices(entity) {
|
|
6866
|
+
if (entity.type === "LWPOLYLINE") return lwVertices(entity);
|
|
6867
|
+
const out = [];
|
|
6868
|
+
const p = entity.pairs;
|
|
6869
|
+
for (let k = 0; k < p.length; k++) {
|
|
6870
|
+
if (p[k]?.[0] !== 10) continue;
|
|
6871
|
+
out.push({
|
|
6872
|
+
point: [
|
|
6873
|
+
num(p[k]?.[1]),
|
|
6874
|
+
num(p[k + 1]?.[1]),
|
|
6875
|
+
num(p[k + 2]?.[1])
|
|
6876
|
+
],
|
|
6877
|
+
bulge: num(p[k + 3]?.[1])
|
|
6878
|
+
});
|
|
6879
|
+
}
|
|
6880
|
+
return out;
|
|
6881
|
+
}
|
|
6882
|
+
var JOIN_TOL = 1e-7;
|
|
6883
|
+
var TURN = 2 * Math.PI;
|
|
6884
|
+
function cross(a, b) {
|
|
6885
|
+
return [
|
|
6886
|
+
a[1] * b[2] - a[2] * b[1],
|
|
6887
|
+
a[2] * b[0] - a[0] * b[2],
|
|
6888
|
+
a[0] * b[1] - a[1] * b[0]
|
|
6889
|
+
];
|
|
6890
|
+
}
|
|
6891
|
+
function unit(v) {
|
|
6892
|
+
const l = Math.hypot(v[0], v[1], v[2]) || 1;
|
|
6893
|
+
return [
|
|
6894
|
+
v[0] / l,
|
|
6895
|
+
v[1] / l,
|
|
6896
|
+
v[2] / l
|
|
6897
|
+
];
|
|
6898
|
+
}
|
|
6899
|
+
/**
|
|
6900
|
+
* The entity's object coordinate system, from its extrusion direction (210/220/230), by DXF's
|
|
6901
|
+
* arbitrary axis algorithm. Planar entities (circles, arcs, 2D polylines) store their points in
|
|
6902
|
+
* it; the default extrusion +Z makes it the world frame.
|
|
6903
|
+
*/
|
|
6904
|
+
function ocsOf(data) {
|
|
6905
|
+
const normal = unit([
|
|
6906
|
+
getNum(data, 210),
|
|
6907
|
+
getNum(data, 220),
|
|
6908
|
+
getNum(data, 230, 1)
|
|
6823
6909
|
]);
|
|
6824
|
-
if (
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6910
|
+
if (normal[0] === 0 && normal[1] === 0 && normal[2] > 0) return {
|
|
6911
|
+
normal: [
|
|
6912
|
+
0,
|
|
6913
|
+
0,
|
|
6914
|
+
1
|
|
6915
|
+
],
|
|
6916
|
+
identity: true,
|
|
6917
|
+
toWorld: (p) => p
|
|
6918
|
+
};
|
|
6919
|
+
const ax = unit(cross(Math.abs(normal[0]) < 1 / 64 && Math.abs(normal[1]) < 1 / 64 ? [
|
|
6920
|
+
0,
|
|
6921
|
+
1,
|
|
6922
|
+
0
|
|
6923
|
+
] : [
|
|
6829
6924
|
0,
|
|
6830
6925
|
0,
|
|
6831
6926
|
1
|
|
6832
|
-
],
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6927
|
+
], normal));
|
|
6928
|
+
const ay = unit(cross(normal, ax));
|
|
6929
|
+
return {
|
|
6930
|
+
normal,
|
|
6931
|
+
identity: false,
|
|
6932
|
+
toWorld: ([x, y, z]) => [
|
|
6933
|
+
ax[0] * x + ay[0] * y + normal[0] * z,
|
|
6934
|
+
ax[1] * x + ay[1] * y + normal[1] * z,
|
|
6935
|
+
ax[2] * x + ay[2] * y + normal[2] * z
|
|
6936
|
+
]
|
|
6937
|
+
};
|
|
6938
|
+
}
|
|
6939
|
+
function apart(a, b) {
|
|
6940
|
+
return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]) > JOIN_TOL;
|
|
6941
|
+
}
|
|
6942
|
+
function linePiece(a, b) {
|
|
6943
|
+
return {
|
|
6944
|
+
start: a,
|
|
6945
|
+
end: b,
|
|
6946
|
+
build: () => require_shapeTypes.getKernel().makeLineEdge(a, b)
|
|
6947
|
+
};
|
|
6948
|
+
}
|
|
6949
|
+
/**
|
|
6950
|
+
* An ARC entity about OCS center `c`, counterclockwise from angle `from` through `sweep` (0, 2π].
|
|
6951
|
+
* In the default OCS, which is most files, it's built from its center and angles, which stays
|
|
6952
|
+
* exact for a shallow arc. In a rotated OCS, whose in-plane axes the kernel doesn't share, it goes
|
|
6953
|
+
* through three points on it, or is a line when its sagitta is under the tolerance.
|
|
6954
|
+
*/
|
|
6955
|
+
function arcPiece(c, r, from, sweep, ocs) {
|
|
6956
|
+
const on = (t) => ocs.toWorld([
|
|
6957
|
+
c[0] + r * Math.cos(t),
|
|
6958
|
+
c[1] + r * Math.sin(t),
|
|
6959
|
+
c[2]
|
|
6960
|
+
]);
|
|
6961
|
+
const start = on(from);
|
|
6962
|
+
const end = on(from + sweep);
|
|
6963
|
+
if (ocs.identity) return {
|
|
6964
|
+
start,
|
|
6965
|
+
end,
|
|
6966
|
+
build: () => require_shapeTypes.getKernel().makeCircleArc(c, [
|
|
6967
|
+
0,
|
|
6968
|
+
0,
|
|
6969
|
+
1
|
|
6970
|
+
], r, from, from + sweep)
|
|
6971
|
+
};
|
|
6972
|
+
if (r * (1 - Math.cos(sweep / 2)) <= JOIN_TOL) return linePiece(start, end);
|
|
6973
|
+
const mid = on(from + sweep / 2);
|
|
6974
|
+
return {
|
|
6975
|
+
start,
|
|
6976
|
+
end,
|
|
6977
|
+
build: () => require_shapeTypes.getKernel().makeArcEdge(start, mid, end)
|
|
6978
|
+
};
|
|
6979
|
+
}
|
|
6980
|
+
/**
|
|
6981
|
+
* A polyline segment in its OCS: straight, or the arc a bulge describes. A bulge is tan(θ/4) of
|
|
6982
|
+
* the arc's included angle, counterclockwise when positive, so the arc's midpoint lies the sagitta
|
|
6983
|
+
* (bulge × half the chord) off the chord's midpoint, to its right for a positive bulge. The arc
|
|
6984
|
+
* goes through the supplied vertices exactly, so it meets its neighbours; one whose sagitta is
|
|
6985
|
+
* under the tolerance is a line to the kernel and is built as one.
|
|
6986
|
+
*/
|
|
6987
|
+
function segment(a, b, bulge, ocs) {
|
|
6988
|
+
const dx = b[0] - a[0];
|
|
6989
|
+
const dy = b[1] - a[1];
|
|
6990
|
+
const d = Math.hypot(dx, dy);
|
|
6991
|
+
const s = bulge * d / 2;
|
|
6992
|
+
if (Math.abs(s) <= JOIN_TOL) return linePiece(ocs.toWorld(a), ocs.toWorld(b));
|
|
6993
|
+
const mid = [
|
|
6994
|
+
(a[0] + b[0]) / 2 + dy / d * s,
|
|
6995
|
+
(a[1] + b[1]) / 2 - dx / d * s,
|
|
6996
|
+
a[2]
|
|
6997
|
+
];
|
|
6998
|
+
const [wa, wm, wb] = [
|
|
6999
|
+
ocs.toWorld(a),
|
|
7000
|
+
ocs.toWorld(mid),
|
|
7001
|
+
ocs.toWorld(b)
|
|
7002
|
+
];
|
|
7003
|
+
return {
|
|
7004
|
+
start: wa,
|
|
7005
|
+
end: wb,
|
|
7006
|
+
build: () => require_shapeTypes.getKernel().makeArcEdge(wa, wm, wb)
|
|
7007
|
+
};
|
|
7008
|
+
}
|
|
7009
|
+
var CLOSED = 1;
|
|
7010
|
+
var POLYLINE_3D = 8;
|
|
7011
|
+
var MESH_FORMS = 80;
|
|
7012
|
+
function polylinePieces(entity) {
|
|
7013
|
+
const flags = getNum(entity.data, 70);
|
|
7014
|
+
if (entity.type === "POLYLINE" && (flags & MESH_FORMS) !== 0) return [];
|
|
7015
|
+
const is3d = entity.type === "POLYLINE" && (flags & POLYLINE_3D) !== 0;
|
|
7016
|
+
const ocs = is3d ? {
|
|
7017
|
+
normal: [
|
|
6841
7018
|
0,
|
|
6842
7019
|
0,
|
|
6843
7020
|
1
|
|
6844
|
-
],
|
|
7021
|
+
],
|
|
7022
|
+
identity: true,
|
|
7023
|
+
toWorld: (p) => p
|
|
7024
|
+
} : ocsOf(entity.data);
|
|
7025
|
+
const elevation = entity.type === "POLYLINE" && !is3d ? getNum(entity.data, 30) : void 0;
|
|
7026
|
+
const vertices = polyVertices(entity).map((v) => elevation === void 0 ? v : {
|
|
7027
|
+
...v,
|
|
7028
|
+
point: [
|
|
7029
|
+
v.point[0],
|
|
7030
|
+
v.point[1],
|
|
7031
|
+
elevation
|
|
7032
|
+
]
|
|
7033
|
+
});
|
|
7034
|
+
const closed = (flags & CLOSED) === CLOSED;
|
|
7035
|
+
const pieces = [];
|
|
7036
|
+
const count = closed ? vertices.length : vertices.length - 1;
|
|
7037
|
+
for (let k = 0; k < count; k++) {
|
|
7038
|
+
const a = vertices[k];
|
|
7039
|
+
const b = vertices[(k + 1) % vertices.length];
|
|
7040
|
+
if (!a || !b || !apart(a.point, b.point)) continue;
|
|
7041
|
+
pieces.push(segment(a.point, b.point, is3d ? 0 : a.bulge, ocs));
|
|
7042
|
+
}
|
|
7043
|
+
return pieces;
|
|
7044
|
+
}
|
|
7045
|
+
function entityToPieces(entity) {
|
|
7046
|
+
const { type, data } = entity;
|
|
7047
|
+
if (type === "LINE") {
|
|
7048
|
+
const start = [
|
|
7049
|
+
getNum(data, 10),
|
|
7050
|
+
getNum(data, 20),
|
|
7051
|
+
getNum(data, 30)
|
|
7052
|
+
];
|
|
7053
|
+
const end = [
|
|
7054
|
+
getNum(data, 11),
|
|
7055
|
+
getNum(data, 21),
|
|
7056
|
+
getNum(data, 31)
|
|
7057
|
+
];
|
|
7058
|
+
return apart(start, end) ? [linePiece(start, end)] : [];
|
|
6845
7059
|
}
|
|
7060
|
+
if (type === "CIRCLE" || type === "ARC") {
|
|
7061
|
+
const ocs = ocsOf(data);
|
|
7062
|
+
const c = [
|
|
7063
|
+
getNum(data, 10),
|
|
7064
|
+
getNum(data, 20),
|
|
7065
|
+
getNum(data, 30)
|
|
7066
|
+
];
|
|
7067
|
+
const r = getNum(data, 40);
|
|
7068
|
+
if (!(r > 0) || !Number.isFinite(r)) return [];
|
|
7069
|
+
if (type === "CIRCLE") {
|
|
7070
|
+
const center = ocs.toWorld(c);
|
|
7071
|
+
const at = ocs.toWorld([
|
|
7072
|
+
c[0] + r,
|
|
7073
|
+
c[1],
|
|
7074
|
+
c[2]
|
|
7075
|
+
]);
|
|
7076
|
+
return [{
|
|
7077
|
+
start: at,
|
|
7078
|
+
end: at,
|
|
7079
|
+
build: () => require_shapeTypes.getKernel().makeCircleEdge(center, ocs.normal, r)
|
|
7080
|
+
}];
|
|
7081
|
+
}
|
|
7082
|
+
const from = getNum(data, 50) * Math.PI / 180;
|
|
7083
|
+
const to = getNum(data, 51) * Math.PI / 180;
|
|
7084
|
+
if (!Number.isFinite(from) || !Number.isFinite(to)) return [];
|
|
7085
|
+
let sweep = (to - from) % TURN;
|
|
7086
|
+
if (sweep <= 0) sweep += TURN;
|
|
7087
|
+
return [arcPiece(c, r, from % TURN, sweep, ocs)];
|
|
7088
|
+
}
|
|
7089
|
+
if (type === "LWPOLYLINE" || type === "POLYLINE") return polylinePieces(entity);
|
|
7090
|
+
return [];
|
|
7091
|
+
}
|
|
7092
|
+
/** Gives endpoints within JOIN_TOL of each other one id, by a grid of JOIN_TOL cells. */
|
|
7093
|
+
function pointIds() {
|
|
7094
|
+
const cells = /* @__PURE__ */ new Map();
|
|
7095
|
+
let next = 0;
|
|
7096
|
+
return (p) => {
|
|
7097
|
+
const c = p.map((v) => Math.floor(v / JOIN_TOL));
|
|
7098
|
+
for (let dx = -1; dx <= 1; dx++) for (let dy = -1; dy <= 1; dy++) for (let dz = -1; dz <= 1; dz++) {
|
|
7099
|
+
const hit = cells.get(`${(c[0] ?? 0) + dx},${(c[1] ?? 0) + dy},${(c[2] ?? 0) + dz}`)?.find((e) => !apart(e.p, p));
|
|
7100
|
+
if (hit) return hit.id;
|
|
7101
|
+
}
|
|
7102
|
+
const key = c.join(",");
|
|
7103
|
+
const id = next++;
|
|
7104
|
+
const cell = cells.get(key);
|
|
7105
|
+
if (cell) cell.push({
|
|
7106
|
+
p,
|
|
7107
|
+
id
|
|
7108
|
+
});
|
|
7109
|
+
else cells.set(key, [{
|
|
7110
|
+
p,
|
|
7111
|
+
id
|
|
7112
|
+
}]);
|
|
7113
|
+
return id;
|
|
7114
|
+
};
|
|
7115
|
+
}
|
|
7116
|
+
/** The pieces in connected chains, each in walking order, so every chain makes one wire. */
|
|
7117
|
+
function chainPieces(pieces) {
|
|
7118
|
+
const idOf = pointIds();
|
|
7119
|
+
const ends = pieces.map((p) => [idOf(p.start), idOf(p.end)]);
|
|
7120
|
+
const at = /* @__PURE__ */ new Map();
|
|
7121
|
+
ends.forEach(([s, e], i) => {
|
|
7122
|
+
for (const id of s === e ? [s] : [s, e]) {
|
|
7123
|
+
const list = at.get(id);
|
|
7124
|
+
if (list) list.push(i);
|
|
7125
|
+
else at.set(id, [i]);
|
|
7126
|
+
}
|
|
7127
|
+
});
|
|
7128
|
+
const used = /* @__PURE__ */ new Set();
|
|
7129
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
7130
|
+
const step = (tip) => {
|
|
7131
|
+
const list = at.get(tip) ?? [];
|
|
7132
|
+
let c = cursor.get(tip) ?? 0;
|
|
7133
|
+
while (c < list.length && used.has(list[c] ?? -1)) c++;
|
|
7134
|
+
cursor.set(tip, c + 1);
|
|
7135
|
+
const i = list[c];
|
|
7136
|
+
if (i === void 0) return void 0;
|
|
7137
|
+
used.add(i);
|
|
7138
|
+
const [s, e] = ends[i] ?? [tip, tip];
|
|
7139
|
+
return {
|
|
7140
|
+
i,
|
|
7141
|
+
tip: s === tip ? e : s
|
|
7142
|
+
};
|
|
7143
|
+
};
|
|
7144
|
+
const chains = [];
|
|
7145
|
+
pieces.forEach((first, i) => {
|
|
7146
|
+
if (used.has(i)) return;
|
|
7147
|
+
used.add(i);
|
|
7148
|
+
const chain = [first];
|
|
7149
|
+
const [s, e] = ends[i] ?? [0, 0];
|
|
7150
|
+
for (const [dir, from] of [[1, e], [-1, s]]) for (let hop = step(from); hop; hop = step(hop.tip)) {
|
|
7151
|
+
const piece = pieces[hop.i];
|
|
7152
|
+
if (!piece) continue;
|
|
7153
|
+
if (dir === 1) chain.push(piece);
|
|
7154
|
+
else chain.unshift(piece);
|
|
7155
|
+
}
|
|
7156
|
+
chains.push(chain);
|
|
7157
|
+
});
|
|
7158
|
+
return chains;
|
|
6846
7159
|
}
|
|
6847
7160
|
/**
|
|
6848
7161
|
* Import a DXF file from a Blob, returning kernel wires.
|
|
6849
7162
|
*
|
|
6850
|
-
* Parses ASCII DXF LINE, CIRCLE, and
|
|
6851
|
-
*
|
|
7163
|
+
* Parses ASCII DXF LINE, CIRCLE, ARC, LWPOLYLINE and R12 POLYLINE entities, polyline bulges
|
|
7164
|
+
* included, in world coordinates (planar entities are mapped out of their object coordinate
|
|
7165
|
+
* system). Polygon and polyface meshes are skipped. Edges that meet end to end become one wire,
|
|
7166
|
+
* so disconnected outlines come back as separate wires.
|
|
6852
7167
|
*
|
|
6853
7168
|
* @param blob - A Blob containing ASCII DXF data.
|
|
6854
7169
|
* @param options - Optional import settings (layer filter).
|
|
@@ -6861,22 +7176,28 @@ async function importDXF(blob, options) {
|
|
|
6861
7176
|
} catch (cause) {
|
|
6862
7177
|
return require_errors.err(require_errors.ioError(require_errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to read DXF blob", cause));
|
|
6863
7178
|
}
|
|
6864
|
-
const allEntities = parseEntities(text);
|
|
6865
|
-
const
|
|
6866
|
-
if (
|
|
7179
|
+
const allEntities = gatherPolylines(parseEntities(text));
|
|
7180
|
+
const pieces = (options?.layer !== void 0 ? allEntities.filter((e) => e.layer === options.layer) : allEntities).flatMap(entityToPieces);
|
|
7181
|
+
if (pieces.length === 0) return require_errors.ok([]);
|
|
7182
|
+
const kernel = require_shapeTypes.getKernel();
|
|
6867
7183
|
const edges = [];
|
|
7184
|
+
const wires = [];
|
|
6868
7185
|
try {
|
|
6869
|
-
for (const
|
|
6870
|
-
const
|
|
6871
|
-
|
|
7186
|
+
for (const chain of chainPieces(pieces)) {
|
|
7187
|
+
const chainEdges = [];
|
|
7188
|
+
for (const p of chain) {
|
|
7189
|
+
const edge = p.build();
|
|
7190
|
+
edges.push(edge);
|
|
7191
|
+
chainEdges.push(edge);
|
|
7192
|
+
}
|
|
7193
|
+
wires.push(require_shapeTypes.createWire(kernel.makeWire(chainEdges)));
|
|
6872
7194
|
}
|
|
6873
|
-
|
|
6874
|
-
const wire = require_shapeTypes.getKernel().makeWire(edges);
|
|
6875
|
-
return require_errors.ok([require_shapeTypes.createWire(wire)]);
|
|
7195
|
+
return require_errors.ok(wires);
|
|
6876
7196
|
} catch (cause) {
|
|
7197
|
+
for (const w of wires) w[Symbol.dispose]();
|
|
6877
7198
|
return require_errors.err(require_errors.ioError(require_errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to convert DXF entities to geometry", cause));
|
|
6878
7199
|
} finally {
|
|
6879
|
-
for (const edge of edges)
|
|
7200
|
+
for (const edge of edges) kernel.dispose(edge);
|
|
6880
7201
|
}
|
|
6881
7202
|
}
|
|
6882
7203
|
// src/io/ioUtils.ts
|
package/dist/brepjs.js
CHANGED
|
@@ -27,7 +27,7 @@ import { a as measureDistance, c as measureLinearProps, d as measureVolumeProps,
|
|
|
27
27
|
import { t as cornerFinder } from "./cornerFinder-DHg0ej_Q.js";
|
|
28
28
|
import { a as fuseBlueprints, c as roundedRectangleBlueprint, i as cutBlueprints, n as fuse2D, o as intersectBlueprints, r as intersect2D, s as polysidesBlueprint, t as cut2D } from "./boolean2D-DYAua9O_.js";
|
|
29
29
|
import { S as reverseCurve, _ as curve2dIsOnCurve, a as isInside2D, b as curve2dSplitAt, c as scale2D, d as stretch2D, f as toSVGPathD, g as curve2dFirstPoint, h as curve2dDistanceFrom, i as getOrientation2D, l as sketchOnFace2D, m as curve2dBoundingBox, n as createCompoundBlueprint, o as mirror2D, p as translate2D, r as getBounds2D, s as rotate2D, t as createBlueprint, u as sketchOnPlane2D, v as curve2dLastPoint, x as curve2dTangentAt, y as curve2dParameter } from "./blueprintFns-C0x5vPm-.js";
|
|
30
|
-
import { a as importSVG, c as blueprintToDXF, d as exportGltf, f as exportOBJ, i as exportSTEPConfigured, l as exportDXF, n as importSTEP, o as importSVGPathD, r as importSTL, s as exportThreeMF, t as importIGES, u as exportGlb } from "./importFns-
|
|
30
|
+
import { a as importSVG, c as blueprintToDXF, d as exportGltf, f as exportOBJ, i as exportSTEPConfigured, l as exportDXF, n as importSTEP, o as importSVGPathD, r as importSTL, s as exportThreeMF, t as importIGES, u as exportGlb } from "./importFns-Cfw7SIjn.js";
|
|
31
31
|
import { a as Sketch, b as extrudeAll, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, n as getFont, o as compoundSketchExtrude, p as sketchRevolve, r as loadFont, s as compoundSketchFace, t as textBlueprints, u as sketchExtrude, v as CompoundSketch, x as revolve$2, y as extrude$2 } from "./textBlueprints-BlfIkOUx.js";
|
|
32
32
|
import { a as multiSectionSweep, c as twistExtrude, i as guidedSweep, n as loftAll, o as supportExtrude, r as complexExtrude, s as sweep$1, t as loft$2 } from "./loftFns-DIsFP0VL.js";
|
|
33
33
|
import { _ as createRef, a as isVertexRef, b as defaultScorer, c as resolveRefParams, d as createVertexRef, f as resolveVertexRef, g as captureHint, h as assignRoles, i as isLineageRef, l as createDerivedFaceRef, m as resolveEdgeRef, n as isEdgeRef, o as resolveLineageRef, p as createEdgeRef, r as isFaceRef, s as resolveRefIn, t as isDerivedFaceRef, u as resolveDerivedFaceRef, v as resolveRef, y as updateRoles } from "./refResolveFns-BxvibZPu.js";
|
|
@@ -6190,7 +6190,7 @@ function sub(a, b) {
|
|
|
6190
6190
|
function dot(a, b) {
|
|
6191
6191
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
6192
6192
|
}
|
|
6193
|
-
function cross(a, b) {
|
|
6193
|
+
function cross$1(a, b) {
|
|
6194
6194
|
return [
|
|
6195
6195
|
a[1] * b[2] - a[2] * b[1],
|
|
6196
6196
|
a[2] * b[0] - a[0] * b[2],
|
|
@@ -6214,7 +6214,7 @@ function normalize(a) {
|
|
|
6214
6214
|
}
|
|
6215
6215
|
/** A unit vector perpendicular to `v` (for the parallel-normals degenerate case). */
|
|
6216
6216
|
function anyPerpendicular(v) {
|
|
6217
|
-
return normalize(cross(v, Math.abs(v[0]) < .9 ? [
|
|
6217
|
+
return normalize(cross$1(v, Math.abs(v[0]) < .9 ? [
|
|
6218
6218
|
1,
|
|
6219
6219
|
0,
|
|
6220
6220
|
0
|
|
@@ -6294,7 +6294,7 @@ function solveAngle(ref, dep, angleRad) {
|
|
|
6294
6294
|
1
|
|
6295
6295
|
]);
|
|
6296
6296
|
const phi = Math.acos(Math.max(-1, Math.min(1, dot(nDep, nRef))));
|
|
6297
|
-
const c = cross(nDep, nRef);
|
|
6297
|
+
const c = cross$1(nDep, nRef);
|
|
6298
6298
|
const axis = Math.hypot(c[0], c[1], c[2]) < 1e-9 ? anyPerpendicular(nDep) : c;
|
|
6299
6299
|
return {
|
|
6300
6300
|
position: [
|
|
@@ -6801,63 +6801,378 @@ function parseEntities(text) {
|
|
|
6801
6801
|
current = {
|
|
6802
6802
|
type: value,
|
|
6803
6803
|
layer: "0",
|
|
6804
|
-
data: /* @__PURE__ */ new Map()
|
|
6804
|
+
data: /* @__PURE__ */ new Map(),
|
|
6805
|
+
pairs: []
|
|
6805
6806
|
};
|
|
6806
6807
|
continue;
|
|
6807
6808
|
}
|
|
6808
6809
|
if (current) {
|
|
6810
|
+
current.pairs.push([code, value]);
|
|
6809
6811
|
if (code === 8) current.layer = value;
|
|
6810
6812
|
else current.data.set(code, value);
|
|
6811
6813
|
}
|
|
6812
6814
|
}
|
|
6813
6815
|
return entities;
|
|
6814
6816
|
}
|
|
6815
|
-
function
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
const n = parseFloat(v);
|
|
6817
|
+
function num(value, fallback = 0) {
|
|
6818
|
+
if (value === void 0) return fallback;
|
|
6819
|
+
const n = parseFloat(value);
|
|
6819
6820
|
return isNaN(n) ? fallback : n;
|
|
6820
6821
|
}
|
|
6821
|
-
function
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6822
|
+
function getNum(data, code, fallback = 0) {
|
|
6823
|
+
return num(data.get(code), fallback);
|
|
6824
|
+
}
|
|
6825
|
+
/** LWPOLYLINE vertices: each 10 starts one and its 20 and 42 follow; 38 is the elevation. */
|
|
6826
|
+
function lwVertices(entity) {
|
|
6827
|
+
const z = getNum(entity.data, 38);
|
|
6828
|
+
const out = [];
|
|
6829
|
+
for (const [code, value] of entity.pairs) {
|
|
6830
|
+
const last = out[out.length - 1];
|
|
6831
|
+
if (code === 10) out.push({
|
|
6832
|
+
point: [
|
|
6833
|
+
num(value),
|
|
6834
|
+
0,
|
|
6835
|
+
z
|
|
6836
|
+
],
|
|
6837
|
+
bulge: 0
|
|
6838
|
+
});
|
|
6839
|
+
else if (code === 20 && last) last.point[1] = num(value);
|
|
6840
|
+
else if (code === 42 && last) last.bulge = num(value);
|
|
6841
|
+
}
|
|
6842
|
+
return out;
|
|
6843
|
+
}
|
|
6844
|
+
/**
|
|
6845
|
+
* The DXF R12 polyline: a POLYLINE header, its VERTEX entities, then SEQEND. They arrive as
|
|
6846
|
+
* separate entities, so the header gathers the vertices that follow it.
|
|
6847
|
+
*/
|
|
6848
|
+
function gatherPolylines(entities) {
|
|
6849
|
+
const out = [];
|
|
6850
|
+
for (let i = 0; i < entities.length; i++) {
|
|
6851
|
+
const e = entities[i];
|
|
6852
|
+
if (e === void 0) continue;
|
|
6853
|
+
if (e.type !== "POLYLINE") {
|
|
6854
|
+
if (e.type !== "VERTEX" && e.type !== "SEQEND") out.push(e);
|
|
6855
|
+
continue;
|
|
6856
|
+
}
|
|
6857
|
+
const vertices = [];
|
|
6858
|
+
let j = i + 1;
|
|
6859
|
+
for (; j < entities.length && entities[j]?.type === "VERTEX"; j++) {
|
|
6860
|
+
const v = entities[j];
|
|
6861
|
+
if (v === void 0) continue;
|
|
6862
|
+
vertices.push([10, v.data.get(10) ?? "0"], [20, v.data.get(20) ?? "0"], [30, v.data.get(30) ?? "0"], [42, v.data.get(42) ?? "0"]);
|
|
6863
|
+
}
|
|
6864
|
+
if (entities[j]?.type === "SEQEND") j++;
|
|
6865
|
+
const own = e.pairs.filter(([code]) => code !== 10 && code !== 20 && code !== 30);
|
|
6866
|
+
out.push({
|
|
6867
|
+
...e,
|
|
6868
|
+
pairs: [...own, ...vertices]
|
|
6869
|
+
});
|
|
6870
|
+
i = j - 1;
|
|
6871
|
+
}
|
|
6872
|
+
return out;
|
|
6873
|
+
}
|
|
6874
|
+
function polyVertices(entity) {
|
|
6875
|
+
if (entity.type === "LWPOLYLINE") return lwVertices(entity);
|
|
6876
|
+
const out = [];
|
|
6877
|
+
const p = entity.pairs;
|
|
6878
|
+
for (let k = 0; k < p.length; k++) {
|
|
6879
|
+
if (p[k]?.[0] !== 10) continue;
|
|
6880
|
+
out.push({
|
|
6881
|
+
point: [
|
|
6882
|
+
num(p[k]?.[1]),
|
|
6883
|
+
num(p[k + 1]?.[1]),
|
|
6884
|
+
num(p[k + 2]?.[1])
|
|
6885
|
+
],
|
|
6886
|
+
bulge: num(p[k + 3]?.[1])
|
|
6887
|
+
});
|
|
6888
|
+
}
|
|
6889
|
+
return out;
|
|
6890
|
+
}
|
|
6891
|
+
var JOIN_TOL = 1e-7;
|
|
6892
|
+
var TURN = 2 * Math.PI;
|
|
6893
|
+
function cross(a, b) {
|
|
6894
|
+
return [
|
|
6895
|
+
a[1] * b[2] - a[2] * b[1],
|
|
6896
|
+
a[2] * b[0] - a[0] * b[2],
|
|
6897
|
+
a[0] * b[1] - a[1] * b[0]
|
|
6898
|
+
];
|
|
6899
|
+
}
|
|
6900
|
+
function unit(v) {
|
|
6901
|
+
const l = Math.hypot(v[0], v[1], v[2]) || 1;
|
|
6902
|
+
return [
|
|
6903
|
+
v[0] / l,
|
|
6904
|
+
v[1] / l,
|
|
6905
|
+
v[2] / l
|
|
6906
|
+
];
|
|
6907
|
+
}
|
|
6908
|
+
/**
|
|
6909
|
+
* The entity's object coordinate system, from its extrusion direction (210/220/230), by DXF's
|
|
6910
|
+
* arbitrary axis algorithm. Planar entities (circles, arcs, 2D polylines) store their points in
|
|
6911
|
+
* it; the default extrusion +Z makes it the world frame.
|
|
6912
|
+
*/
|
|
6913
|
+
function ocsOf(data) {
|
|
6914
|
+
const normal = unit([
|
|
6915
|
+
getNum(data, 210),
|
|
6916
|
+
getNum(data, 220),
|
|
6917
|
+
getNum(data, 230, 1)
|
|
6832
6918
|
]);
|
|
6833
|
-
if (
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6919
|
+
if (normal[0] === 0 && normal[1] === 0 && normal[2] > 0) return {
|
|
6920
|
+
normal: [
|
|
6921
|
+
0,
|
|
6922
|
+
0,
|
|
6923
|
+
1
|
|
6924
|
+
],
|
|
6925
|
+
identity: true,
|
|
6926
|
+
toWorld: (p) => p
|
|
6927
|
+
};
|
|
6928
|
+
const ax = unit(cross(Math.abs(normal[0]) < 1 / 64 && Math.abs(normal[1]) < 1 / 64 ? [
|
|
6929
|
+
0,
|
|
6930
|
+
1,
|
|
6931
|
+
0
|
|
6932
|
+
] : [
|
|
6838
6933
|
0,
|
|
6839
6934
|
0,
|
|
6840
6935
|
1
|
|
6841
|
-
],
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6936
|
+
], normal));
|
|
6937
|
+
const ay = unit(cross(normal, ax));
|
|
6938
|
+
return {
|
|
6939
|
+
normal,
|
|
6940
|
+
identity: false,
|
|
6941
|
+
toWorld: ([x, y, z]) => [
|
|
6942
|
+
ax[0] * x + ay[0] * y + normal[0] * z,
|
|
6943
|
+
ax[1] * x + ay[1] * y + normal[1] * z,
|
|
6944
|
+
ax[2] * x + ay[2] * y + normal[2] * z
|
|
6945
|
+
]
|
|
6946
|
+
};
|
|
6947
|
+
}
|
|
6948
|
+
function apart(a, b) {
|
|
6949
|
+
return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]) > JOIN_TOL;
|
|
6950
|
+
}
|
|
6951
|
+
function linePiece(a, b) {
|
|
6952
|
+
return {
|
|
6953
|
+
start: a,
|
|
6954
|
+
end: b,
|
|
6955
|
+
build: () => getKernel().makeLineEdge(a, b)
|
|
6956
|
+
};
|
|
6957
|
+
}
|
|
6958
|
+
/**
|
|
6959
|
+
* An ARC entity about OCS center `c`, counterclockwise from angle `from` through `sweep` (0, 2π].
|
|
6960
|
+
* In the default OCS, which is most files, it's built from its center and angles, which stays
|
|
6961
|
+
* exact for a shallow arc. In a rotated OCS, whose in-plane axes the kernel doesn't share, it goes
|
|
6962
|
+
* through three points on it, or is a line when its sagitta is under the tolerance.
|
|
6963
|
+
*/
|
|
6964
|
+
function arcPiece(c, r, from, sweep, ocs) {
|
|
6965
|
+
const on = (t) => ocs.toWorld([
|
|
6966
|
+
c[0] + r * Math.cos(t),
|
|
6967
|
+
c[1] + r * Math.sin(t),
|
|
6968
|
+
c[2]
|
|
6969
|
+
]);
|
|
6970
|
+
const start = on(from);
|
|
6971
|
+
const end = on(from + sweep);
|
|
6972
|
+
if (ocs.identity) return {
|
|
6973
|
+
start,
|
|
6974
|
+
end,
|
|
6975
|
+
build: () => getKernel().makeCircleArc(c, [
|
|
6976
|
+
0,
|
|
6977
|
+
0,
|
|
6978
|
+
1
|
|
6979
|
+
], r, from, from + sweep)
|
|
6980
|
+
};
|
|
6981
|
+
if (r * (1 - Math.cos(sweep / 2)) <= JOIN_TOL) return linePiece(start, end);
|
|
6982
|
+
const mid = on(from + sweep / 2);
|
|
6983
|
+
return {
|
|
6984
|
+
start,
|
|
6985
|
+
end,
|
|
6986
|
+
build: () => getKernel().makeArcEdge(start, mid, end)
|
|
6987
|
+
};
|
|
6988
|
+
}
|
|
6989
|
+
/**
|
|
6990
|
+
* A polyline segment in its OCS: straight, or the arc a bulge describes. A bulge is tan(θ/4) of
|
|
6991
|
+
* the arc's included angle, counterclockwise when positive, so the arc's midpoint lies the sagitta
|
|
6992
|
+
* (bulge × half the chord) off the chord's midpoint, to its right for a positive bulge. The arc
|
|
6993
|
+
* goes through the supplied vertices exactly, so it meets its neighbours; one whose sagitta is
|
|
6994
|
+
* under the tolerance is a line to the kernel and is built as one.
|
|
6995
|
+
*/
|
|
6996
|
+
function segment(a, b, bulge, ocs) {
|
|
6997
|
+
const dx = b[0] - a[0];
|
|
6998
|
+
const dy = b[1] - a[1];
|
|
6999
|
+
const d = Math.hypot(dx, dy);
|
|
7000
|
+
const s = bulge * d / 2;
|
|
7001
|
+
if (Math.abs(s) <= JOIN_TOL) return linePiece(ocs.toWorld(a), ocs.toWorld(b));
|
|
7002
|
+
const mid = [
|
|
7003
|
+
(a[0] + b[0]) / 2 + dy / d * s,
|
|
7004
|
+
(a[1] + b[1]) / 2 - dx / d * s,
|
|
7005
|
+
a[2]
|
|
7006
|
+
];
|
|
7007
|
+
const [wa, wm, wb] = [
|
|
7008
|
+
ocs.toWorld(a),
|
|
7009
|
+
ocs.toWorld(mid),
|
|
7010
|
+
ocs.toWorld(b)
|
|
7011
|
+
];
|
|
7012
|
+
return {
|
|
7013
|
+
start: wa,
|
|
7014
|
+
end: wb,
|
|
7015
|
+
build: () => getKernel().makeArcEdge(wa, wm, wb)
|
|
7016
|
+
};
|
|
7017
|
+
}
|
|
7018
|
+
var CLOSED = 1;
|
|
7019
|
+
var POLYLINE_3D = 8;
|
|
7020
|
+
var MESH_FORMS = 80;
|
|
7021
|
+
function polylinePieces(entity) {
|
|
7022
|
+
const flags = getNum(entity.data, 70);
|
|
7023
|
+
if (entity.type === "POLYLINE" && (flags & MESH_FORMS) !== 0) return [];
|
|
7024
|
+
const is3d = entity.type === "POLYLINE" && (flags & POLYLINE_3D) !== 0;
|
|
7025
|
+
const ocs = is3d ? {
|
|
7026
|
+
normal: [
|
|
6850
7027
|
0,
|
|
6851
7028
|
0,
|
|
6852
7029
|
1
|
|
6853
|
-
],
|
|
7030
|
+
],
|
|
7031
|
+
identity: true,
|
|
7032
|
+
toWorld: (p) => p
|
|
7033
|
+
} : ocsOf(entity.data);
|
|
7034
|
+
const elevation = entity.type === "POLYLINE" && !is3d ? getNum(entity.data, 30) : void 0;
|
|
7035
|
+
const vertices = polyVertices(entity).map((v) => elevation === void 0 ? v : {
|
|
7036
|
+
...v,
|
|
7037
|
+
point: [
|
|
7038
|
+
v.point[0],
|
|
7039
|
+
v.point[1],
|
|
7040
|
+
elevation
|
|
7041
|
+
]
|
|
7042
|
+
});
|
|
7043
|
+
const closed = (flags & CLOSED) === CLOSED;
|
|
7044
|
+
const pieces = [];
|
|
7045
|
+
const count = closed ? vertices.length : vertices.length - 1;
|
|
7046
|
+
for (let k = 0; k < count; k++) {
|
|
7047
|
+
const a = vertices[k];
|
|
7048
|
+
const b = vertices[(k + 1) % vertices.length];
|
|
7049
|
+
if (!a || !b || !apart(a.point, b.point)) continue;
|
|
7050
|
+
pieces.push(segment(a.point, b.point, is3d ? 0 : a.bulge, ocs));
|
|
7051
|
+
}
|
|
7052
|
+
return pieces;
|
|
7053
|
+
}
|
|
7054
|
+
function entityToPieces(entity) {
|
|
7055
|
+
const { type, data } = entity;
|
|
7056
|
+
if (type === "LINE") {
|
|
7057
|
+
const start = [
|
|
7058
|
+
getNum(data, 10),
|
|
7059
|
+
getNum(data, 20),
|
|
7060
|
+
getNum(data, 30)
|
|
7061
|
+
];
|
|
7062
|
+
const end = [
|
|
7063
|
+
getNum(data, 11),
|
|
7064
|
+
getNum(data, 21),
|
|
7065
|
+
getNum(data, 31)
|
|
7066
|
+
];
|
|
7067
|
+
return apart(start, end) ? [linePiece(start, end)] : [];
|
|
6854
7068
|
}
|
|
7069
|
+
if (type === "CIRCLE" || type === "ARC") {
|
|
7070
|
+
const ocs = ocsOf(data);
|
|
7071
|
+
const c = [
|
|
7072
|
+
getNum(data, 10),
|
|
7073
|
+
getNum(data, 20),
|
|
7074
|
+
getNum(data, 30)
|
|
7075
|
+
];
|
|
7076
|
+
const r = getNum(data, 40);
|
|
7077
|
+
if (!(r > 0) || !Number.isFinite(r)) return [];
|
|
7078
|
+
if (type === "CIRCLE") {
|
|
7079
|
+
const center = ocs.toWorld(c);
|
|
7080
|
+
const at = ocs.toWorld([
|
|
7081
|
+
c[0] + r,
|
|
7082
|
+
c[1],
|
|
7083
|
+
c[2]
|
|
7084
|
+
]);
|
|
7085
|
+
return [{
|
|
7086
|
+
start: at,
|
|
7087
|
+
end: at,
|
|
7088
|
+
build: () => getKernel().makeCircleEdge(center, ocs.normal, r)
|
|
7089
|
+
}];
|
|
7090
|
+
}
|
|
7091
|
+
const from = getNum(data, 50) * Math.PI / 180;
|
|
7092
|
+
const to = getNum(data, 51) * Math.PI / 180;
|
|
7093
|
+
if (!Number.isFinite(from) || !Number.isFinite(to)) return [];
|
|
7094
|
+
let sweep = (to - from) % TURN;
|
|
7095
|
+
if (sweep <= 0) sweep += TURN;
|
|
7096
|
+
return [arcPiece(c, r, from % TURN, sweep, ocs)];
|
|
7097
|
+
}
|
|
7098
|
+
if (type === "LWPOLYLINE" || type === "POLYLINE") return polylinePieces(entity);
|
|
7099
|
+
return [];
|
|
7100
|
+
}
|
|
7101
|
+
/** Gives endpoints within JOIN_TOL of each other one id, by a grid of JOIN_TOL cells. */
|
|
7102
|
+
function pointIds() {
|
|
7103
|
+
const cells = /* @__PURE__ */ new Map();
|
|
7104
|
+
let next = 0;
|
|
7105
|
+
return (p) => {
|
|
7106
|
+
const c = p.map((v) => Math.floor(v / JOIN_TOL));
|
|
7107
|
+
for (let dx = -1; dx <= 1; dx++) for (let dy = -1; dy <= 1; dy++) for (let dz = -1; dz <= 1; dz++) {
|
|
7108
|
+
const hit = cells.get(`${(c[0] ?? 0) + dx},${(c[1] ?? 0) + dy},${(c[2] ?? 0) + dz}`)?.find((e) => !apart(e.p, p));
|
|
7109
|
+
if (hit) return hit.id;
|
|
7110
|
+
}
|
|
7111
|
+
const key = c.join(",");
|
|
7112
|
+
const id = next++;
|
|
7113
|
+
const cell = cells.get(key);
|
|
7114
|
+
if (cell) cell.push({
|
|
7115
|
+
p,
|
|
7116
|
+
id
|
|
7117
|
+
});
|
|
7118
|
+
else cells.set(key, [{
|
|
7119
|
+
p,
|
|
7120
|
+
id
|
|
7121
|
+
}]);
|
|
7122
|
+
return id;
|
|
7123
|
+
};
|
|
7124
|
+
}
|
|
7125
|
+
/** The pieces in connected chains, each in walking order, so every chain makes one wire. */
|
|
7126
|
+
function chainPieces(pieces) {
|
|
7127
|
+
const idOf = pointIds();
|
|
7128
|
+
const ends = pieces.map((p) => [idOf(p.start), idOf(p.end)]);
|
|
7129
|
+
const at = /* @__PURE__ */ new Map();
|
|
7130
|
+
ends.forEach(([s, e], i) => {
|
|
7131
|
+
for (const id of s === e ? [s] : [s, e]) {
|
|
7132
|
+
const list = at.get(id);
|
|
7133
|
+
if (list) list.push(i);
|
|
7134
|
+
else at.set(id, [i]);
|
|
7135
|
+
}
|
|
7136
|
+
});
|
|
7137
|
+
const used = /* @__PURE__ */ new Set();
|
|
7138
|
+
const cursor = /* @__PURE__ */ new Map();
|
|
7139
|
+
const step = (tip) => {
|
|
7140
|
+
const list = at.get(tip) ?? [];
|
|
7141
|
+
let c = cursor.get(tip) ?? 0;
|
|
7142
|
+
while (c < list.length && used.has(list[c] ?? -1)) c++;
|
|
7143
|
+
cursor.set(tip, c + 1);
|
|
7144
|
+
const i = list[c];
|
|
7145
|
+
if (i === void 0) return void 0;
|
|
7146
|
+
used.add(i);
|
|
7147
|
+
const [s, e] = ends[i] ?? [tip, tip];
|
|
7148
|
+
return {
|
|
7149
|
+
i,
|
|
7150
|
+
tip: s === tip ? e : s
|
|
7151
|
+
};
|
|
7152
|
+
};
|
|
7153
|
+
const chains = [];
|
|
7154
|
+
pieces.forEach((first, i) => {
|
|
7155
|
+
if (used.has(i)) return;
|
|
7156
|
+
used.add(i);
|
|
7157
|
+
const chain = [first];
|
|
7158
|
+
const [s, e] = ends[i] ?? [0, 0];
|
|
7159
|
+
for (const [dir, from] of [[1, e], [-1, s]]) for (let hop = step(from); hop; hop = step(hop.tip)) {
|
|
7160
|
+
const piece = pieces[hop.i];
|
|
7161
|
+
if (!piece) continue;
|
|
7162
|
+
if (dir === 1) chain.push(piece);
|
|
7163
|
+
else chain.unshift(piece);
|
|
7164
|
+
}
|
|
7165
|
+
chains.push(chain);
|
|
7166
|
+
});
|
|
7167
|
+
return chains;
|
|
6855
7168
|
}
|
|
6856
7169
|
/**
|
|
6857
7170
|
* Import a DXF file from a Blob, returning kernel wires.
|
|
6858
7171
|
*
|
|
6859
|
-
* Parses ASCII DXF LINE, CIRCLE, and
|
|
6860
|
-
*
|
|
7172
|
+
* Parses ASCII DXF LINE, CIRCLE, ARC, LWPOLYLINE and R12 POLYLINE entities, polyline bulges
|
|
7173
|
+
* included, in world coordinates (planar entities are mapped out of their object coordinate
|
|
7174
|
+
* system). Polygon and polyface meshes are skipped. Edges that meet end to end become one wire,
|
|
7175
|
+
* so disconnected outlines come back as separate wires.
|
|
6861
7176
|
*
|
|
6862
7177
|
* @param blob - A Blob containing ASCII DXF data.
|
|
6863
7178
|
* @param options - Optional import settings (layer filter).
|
|
@@ -6870,22 +7185,28 @@ async function importDXF(blob, options) {
|
|
|
6870
7185
|
} catch (cause) {
|
|
6871
7186
|
return err(ioError(BrepErrorCode.DXF_IMPORT_FAILED, "Failed to read DXF blob", cause));
|
|
6872
7187
|
}
|
|
6873
|
-
const allEntities = parseEntities(text);
|
|
6874
|
-
const
|
|
6875
|
-
if (
|
|
7188
|
+
const allEntities = gatherPolylines(parseEntities(text));
|
|
7189
|
+
const pieces = (options?.layer !== void 0 ? allEntities.filter((e) => e.layer === options.layer) : allEntities).flatMap(entityToPieces);
|
|
7190
|
+
if (pieces.length === 0) return ok([]);
|
|
7191
|
+
const kernel = getKernel();
|
|
6876
7192
|
const edges = [];
|
|
7193
|
+
const wires = [];
|
|
6877
7194
|
try {
|
|
6878
|
-
for (const
|
|
6879
|
-
const
|
|
6880
|
-
|
|
7195
|
+
for (const chain of chainPieces(pieces)) {
|
|
7196
|
+
const chainEdges = [];
|
|
7197
|
+
for (const p of chain) {
|
|
7198
|
+
const edge = p.build();
|
|
7199
|
+
edges.push(edge);
|
|
7200
|
+
chainEdges.push(edge);
|
|
7201
|
+
}
|
|
7202
|
+
wires.push(createWire(kernel.makeWire(chainEdges)));
|
|
6881
7203
|
}
|
|
6882
|
-
|
|
6883
|
-
const wire = getKernel().makeWire(edges);
|
|
6884
|
-
return ok([createWire(wire)]);
|
|
7204
|
+
return ok(wires);
|
|
6885
7205
|
} catch (cause) {
|
|
7206
|
+
for (const w of wires) w[Symbol.dispose]();
|
|
6886
7207
|
return err(ioError(BrepErrorCode.DXF_IMPORT_FAILED, "Failed to convert DXF entities to geometry", cause));
|
|
6887
7208
|
} finally {
|
|
6888
|
-
for (const edge of edges)
|
|
7209
|
+
for (const edge of edges) kernel.dispose(edge);
|
|
6889
7210
|
}
|
|
6890
7211
|
}
|
|
6891
7212
|
// src/io/ioUtils.ts
|
|
@@ -507,6 +507,50 @@ function buildBinaryBuffer(mesh) {
|
|
|
507
507
|
return buffer;
|
|
508
508
|
}
|
|
509
509
|
// src/io/dxfExportFns.ts
|
|
510
|
+
/** One entity's group-code lines in the ENTITIES section. */
|
|
511
|
+
function entityLines(entity, layer) {
|
|
512
|
+
if (entity.type === "LINE") {
|
|
513
|
+
const [x1, y1] = entity.start;
|
|
514
|
+
const [x2, y2] = entity.end;
|
|
515
|
+
return [
|
|
516
|
+
"0",
|
|
517
|
+
"LINE",
|
|
518
|
+
"8",
|
|
519
|
+
layer,
|
|
520
|
+
"10",
|
|
521
|
+
String(x1),
|
|
522
|
+
"20",
|
|
523
|
+
String(y1),
|
|
524
|
+
"30",
|
|
525
|
+
"0"
|
|
526
|
+
].concat([
|
|
527
|
+
"11",
|
|
528
|
+
String(x2),
|
|
529
|
+
"21",
|
|
530
|
+
String(y2),
|
|
531
|
+
"31",
|
|
532
|
+
"0"
|
|
533
|
+
]);
|
|
534
|
+
}
|
|
535
|
+
const out = [
|
|
536
|
+
"0",
|
|
537
|
+
"POLYLINE",
|
|
538
|
+
"8",
|
|
539
|
+
layer,
|
|
540
|
+
"66",
|
|
541
|
+
"1",
|
|
542
|
+
"10",
|
|
543
|
+
"0",
|
|
544
|
+
"20",
|
|
545
|
+
"0",
|
|
546
|
+
"30",
|
|
547
|
+
"0"
|
|
548
|
+
];
|
|
549
|
+
out.push("70", entity.closed ? "1" : "0");
|
|
550
|
+
for (const [x, y] of entity.points) out.push("0", "VERTEX", "8", layer, "10", String(x), "20", String(y), "30", "0");
|
|
551
|
+
out.push("0", "SEQEND", "8", layer);
|
|
552
|
+
return out;
|
|
553
|
+
}
|
|
510
554
|
/**
|
|
511
555
|
* Export DXF entities to a DXF R12 ASCII string.
|
|
512
556
|
*
|
|
@@ -541,14 +585,7 @@ function exportDXF(entities, options) {
|
|
|
541
585
|
lines.push("0", "ENDTAB");
|
|
542
586
|
lines.push("0", "ENDSEC");
|
|
543
587
|
lines.push("0", "SECTION", "2", "ENTITIES");
|
|
544
|
-
for (const entity of entities)
|
|
545
|
-
const entLayer = entity.layer ?? layer;
|
|
546
|
-
if (entity.type === "LINE") lines.push("0", "LINE", "8", entLayer, "10", String(entity.start[0]), "20", String(entity.start[1]), "30", "0", "11", String(entity.end[0]), "21", String(entity.end[1]), "31", "0");
|
|
547
|
-
else {
|
|
548
|
-
lines.push("0", "LWPOLYLINE", "8", entLayer, "90", String(entity.points.length), "70", entity.closed ? "1" : "0");
|
|
549
|
-
for (const pt of entity.points) lines.push("10", String(pt[0]), "20", String(pt[1]));
|
|
550
|
-
}
|
|
551
|
-
}
|
|
588
|
+
for (const entity of entities) for (const line of entityLines(entity, entity.layer ?? layer)) lines.push(line);
|
|
552
589
|
lines.push("0", "ENDSEC");
|
|
553
590
|
lines.push("0", "EOF");
|
|
554
591
|
return lines.join("\n") + "\n";
|
|
@@ -557,7 +594,7 @@ function exportDXF(entities, options) {
|
|
|
557
594
|
* Convert a Blueprint (or CompoundBlueprint/Blueprints) to a DXF string.
|
|
558
595
|
*
|
|
559
596
|
* Each straight segment becomes a LINE entity; arcs, ellipses, splines,
|
|
560
|
-
* and other curves are approximated as
|
|
597
|
+
* and other curves are approximated as POLYLINE entities.
|
|
561
598
|
*
|
|
562
599
|
* @param drawing - A Blueprint, CompoundBlueprint, or Blueprints collection.
|
|
563
600
|
* @param options - Layer name and curve approximation settings.
|
|
@@ -507,6 +507,50 @@ function buildBinaryBuffer(mesh) {
|
|
|
507
507
|
return buffer;
|
|
508
508
|
}
|
|
509
509
|
// src/io/dxfExportFns.ts
|
|
510
|
+
/** One entity's group-code lines in the ENTITIES section. */
|
|
511
|
+
function entityLines(entity, layer) {
|
|
512
|
+
if (entity.type === "LINE") {
|
|
513
|
+
const [x1, y1] = entity.start;
|
|
514
|
+
const [x2, y2] = entity.end;
|
|
515
|
+
return [
|
|
516
|
+
"0",
|
|
517
|
+
"LINE",
|
|
518
|
+
"8",
|
|
519
|
+
layer,
|
|
520
|
+
"10",
|
|
521
|
+
String(x1),
|
|
522
|
+
"20",
|
|
523
|
+
String(y1),
|
|
524
|
+
"30",
|
|
525
|
+
"0"
|
|
526
|
+
].concat([
|
|
527
|
+
"11",
|
|
528
|
+
String(x2),
|
|
529
|
+
"21",
|
|
530
|
+
String(y2),
|
|
531
|
+
"31",
|
|
532
|
+
"0"
|
|
533
|
+
]);
|
|
534
|
+
}
|
|
535
|
+
const out = [
|
|
536
|
+
"0",
|
|
537
|
+
"POLYLINE",
|
|
538
|
+
"8",
|
|
539
|
+
layer,
|
|
540
|
+
"66",
|
|
541
|
+
"1",
|
|
542
|
+
"10",
|
|
543
|
+
"0",
|
|
544
|
+
"20",
|
|
545
|
+
"0",
|
|
546
|
+
"30",
|
|
547
|
+
"0"
|
|
548
|
+
];
|
|
549
|
+
out.push("70", entity.closed ? "1" : "0");
|
|
550
|
+
for (const [x, y] of entity.points) out.push("0", "VERTEX", "8", layer, "10", String(x), "20", String(y), "30", "0");
|
|
551
|
+
out.push("0", "SEQEND", "8", layer);
|
|
552
|
+
return out;
|
|
553
|
+
}
|
|
510
554
|
/**
|
|
511
555
|
* Export DXF entities to a DXF R12 ASCII string.
|
|
512
556
|
*
|
|
@@ -541,14 +585,7 @@ function exportDXF(entities, options) {
|
|
|
541
585
|
lines.push("0", "ENDTAB");
|
|
542
586
|
lines.push("0", "ENDSEC");
|
|
543
587
|
lines.push("0", "SECTION", "2", "ENTITIES");
|
|
544
|
-
for (const entity of entities)
|
|
545
|
-
const entLayer = entity.layer ?? layer;
|
|
546
|
-
if (entity.type === "LINE") lines.push("0", "LINE", "8", entLayer, "10", String(entity.start[0]), "20", String(entity.start[1]), "30", "0", "11", String(entity.end[0]), "21", String(entity.end[1]), "31", "0");
|
|
547
|
-
else {
|
|
548
|
-
lines.push("0", "LWPOLYLINE", "8", entLayer, "90", String(entity.points.length), "70", entity.closed ? "1" : "0");
|
|
549
|
-
for (const pt of entity.points) lines.push("10", String(pt[0]), "20", String(pt[1]));
|
|
550
|
-
}
|
|
551
|
-
}
|
|
588
|
+
for (const entity of entities) for (const line of entityLines(entity, entity.layer ?? layer)) lines.push(line);
|
|
552
589
|
lines.push("0", "ENDSEC");
|
|
553
590
|
lines.push("0", "EOF");
|
|
554
591
|
return lines.join("\n") + "\n";
|
|
@@ -557,7 +594,7 @@ function exportDXF(entities, options) {
|
|
|
557
594
|
* Convert a Blueprint (or CompoundBlueprint/Blueprints) to a DXF string.
|
|
558
595
|
*
|
|
559
596
|
* Each straight segment becomes a LINE entity; arcs, ellipses, splines,
|
|
560
|
-
* and other curves are approximated as
|
|
597
|
+
* and other curves are approximated as POLYLINE entities.
|
|
561
598
|
*
|
|
562
599
|
* @param drawing - A Blueprint, CompoundBlueprint, or Blueprints collection.
|
|
563
600
|
* @param options - Layer name and curve approximation settings.
|
|
@@ -6,7 +6,7 @@ import { default as Blueprints } from '../2d/blueprints/blueprints.js';
|
|
|
6
6
|
* A single DXF entity (LINE or POLYLINE).
|
|
7
7
|
*
|
|
8
8
|
* LINE maps directly to a DXF LINE entity.
|
|
9
|
-
* POLYLINE maps to an
|
|
9
|
+
* POLYLINE maps to an R12 POLYLINE (its VERTEX entities and a SEQEND), optionally closed.
|
|
10
10
|
*/
|
|
11
11
|
export type DXFEntity = {
|
|
12
12
|
type: 'LINE';
|
|
@@ -51,7 +51,7 @@ export declare function exportDXF(entities: DXFEntity[], options?: DXFExportOpti
|
|
|
51
51
|
* Convert a Blueprint (or CompoundBlueprint/Blueprints) to a DXF string.
|
|
52
52
|
*
|
|
53
53
|
* Each straight segment becomes a LINE entity; arcs, ellipses, splines,
|
|
54
|
-
* and other curves are approximated as
|
|
54
|
+
* and other curves are approximated as POLYLINE entities.
|
|
55
55
|
*
|
|
56
56
|
* @param drawing - A Blueprint, CompoundBlueprint, or Blueprints collection.
|
|
57
57
|
* @param options - Layer name and curve approximation settings.
|
|
@@ -6,8 +6,10 @@ export interface DXFImportOptions {
|
|
|
6
6
|
/**
|
|
7
7
|
* Import a DXF file from a Blob, returning kernel wires.
|
|
8
8
|
*
|
|
9
|
-
* Parses ASCII DXF LINE, CIRCLE, and
|
|
10
|
-
*
|
|
9
|
+
* Parses ASCII DXF LINE, CIRCLE, ARC, LWPOLYLINE and R12 POLYLINE entities, polyline bulges
|
|
10
|
+
* included, in world coordinates (planar entities are mapped out of their object coordinate
|
|
11
|
+
* system). Polygon and polyface meshes are skipped. Edges that meet end to end become one wire,
|
|
12
|
+
* so disconnected outlines come back as separate wires.
|
|
11
13
|
*
|
|
12
14
|
* @param blob - A Blob containing ASCII DXF data.
|
|
13
15
|
* @param options - Optional import settings (layer filter).
|
package/dist/io.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_meshFns = require("./meshFns-0W1-80zv.cjs");
|
|
3
|
-
const require_importFns = require("./importFns-
|
|
3
|
+
const require_importFns = require("./importFns-D5wRI_Cc.cjs");
|
|
4
4
|
exports.blueprintToDXF = require_importFns.blueprintToDXF;
|
|
5
5
|
exports.exportDXF = require_importFns.exportDXF;
|
|
6
6
|
exports.exportGlb = require_importFns.exportGlb;
|
package/dist/io.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as exportSTEP, r as exportSTL, t as exportIGES } from "./meshFns-B9jPfcB2.js";
|
|
2
|
-
import { a as importSVG, c as blueprintToDXF, d as exportGltf, f as exportOBJ, i as exportSTEPConfigured, l as exportDXF, n as importSTEP, o as importSVGPathD, r as importSTL, s as exportThreeMF, t as importIGES, u as exportGlb } from "./importFns-
|
|
2
|
+
import { a as importSVG, c as blueprintToDXF, d as exportGltf, f as exportOBJ, i as exportSTEPConfigured, l as exportDXF, n as importSTEP, o as importSVGPathD, r as importSTL, s as exportThreeMF, t as importIGES, u as exportGlb } from "./importFns-Cfw7SIjn.js";
|
|
3
3
|
export { blueprintToDXF, exportDXF, exportGlb, exportGltf, exportIGES, exportOBJ, exportSTEP, exportSTEPConfigured, exportSTL, exportThreeMF, importIGES, importSTEP, importSTL, importSVG, importSVGPathD };
|