fluidcad 0.0.35 → 0.0.37
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/LICENSE.txt +21 -504
- package/README.md +1 -1
- package/bin/commands/login.js +33 -5
- package/bin/commands/mcp.js +3 -2
- package/bin/commands/publish.js +103 -8
- package/bin/lib/api-client.js +8 -0
- package/bin/lib/model-config.js +27 -4
- package/bin/lib/prompt.js +97 -0
- package/lib/dist/common/edge.d.ts +1 -1
- package/lib/dist/common/face.d.ts +1 -1
- package/lib/dist/common/scene-object.d.ts +6 -0
- package/lib/dist/common/scene-object.js +8 -0
- package/lib/dist/common/shape-factory.d.ts +1 -1
- package/lib/dist/common/shape-history-tracker.d.ts +1 -1
- package/lib/dist/common/shape.d.ts +1 -1
- package/lib/dist/common/solid.d.ts +1 -1
- package/lib/dist/common/transformable-primitive.d.ts +12 -1
- package/lib/dist/common/transformable-primitive.js +27 -0
- package/lib/dist/common/vertex.d.ts +1 -1
- package/lib/dist/common/wire.d.ts +1 -1
- package/lib/dist/core/2d/index.d.ts +1 -0
- package/lib/dist/core/2d/index.js +1 -0
- package/lib/dist/core/2d/text.d.ts +30 -0
- package/lib/dist/core/2d/text.js +37 -0
- package/lib/dist/core/helix.d.ts +20 -0
- package/lib/dist/core/helix.js +36 -0
- package/lib/dist/core/index.d.ts +3 -1
- package/lib/dist/core/index.js +2 -0
- package/lib/dist/core/interfaces.d.ts +180 -0
- package/lib/dist/core/wrap.d.ts +17 -0
- package/lib/dist/core/wrap.js +39 -0
- package/lib/dist/features/2d/text.d.ts +67 -0
- package/lib/dist/features/2d/text.js +320 -0
- package/lib/dist/features/cylinder.d.ts +3 -1
- package/lib/dist/features/cylinder.js +5 -2
- package/lib/dist/features/extrude-base.d.ts +1 -0
- package/lib/dist/features/extrude-to-face.d.ts +1 -0
- package/lib/dist/features/extrude-to-face.js +6 -0
- package/lib/dist/features/fillet.d.ts +1 -1
- package/lib/dist/features/helix.d.ts +41 -0
- package/lib/dist/features/helix.js +337 -0
- package/lib/dist/features/select.js +32 -8
- package/lib/dist/features/simple-extruder.d.ts +1 -1
- package/lib/dist/features/simple-extruder.js +7 -2
- package/lib/dist/features/sphere.d.ts +3 -1
- package/lib/dist/features/sphere.js +5 -2
- package/lib/dist/features/sweep.js +7 -2
- package/lib/dist/features/wrap.d.ts +39 -0
- package/lib/dist/features/wrap.js +116 -0
- package/lib/dist/filters/edge/belongs-to-face.d.ts +3 -1
- package/lib/dist/filters/edge/belongs-to-face.js +14 -10
- package/lib/dist/filters/filter.d.ts +1 -1
- package/lib/dist/filters/from-object.d.ts +1 -1
- package/lib/dist/filters/tangent-expander.d.ts +1 -1
- package/lib/dist/filters/tangent-expander.js +57 -40
- package/lib/dist/helpers/scene-helpers.d.ts +2 -0
- package/lib/dist/helpers/scene-helpers.js +1 -1
- package/lib/dist/index.d.ts +2 -0
- package/lib/dist/index.js +3 -1
- package/lib/dist/io/file-import.d.ts +7 -0
- package/lib/dist/io/file-import.js +28 -1
- package/lib/dist/io/font-registry.d.ts +45 -0
- package/lib/dist/io/font-registry.js +272 -0
- package/lib/dist/math/bspline-interpolation.d.ts +29 -0
- package/lib/dist/math/bspline-interpolation.js +194 -0
- package/lib/dist/oc/boolean-ops.d.ts +3 -1
- package/lib/dist/oc/boolean-ops.js +15 -1
- package/lib/dist/oc/color-transfer.d.ts +1 -1
- package/lib/dist/oc/constraints/constraint-helpers.d.ts +4 -4
- package/lib/dist/oc/constraints/curve/tangent-circle-solver.js +10 -9
- package/lib/dist/oc/constraints/curve/tangent-line-solver.js +5 -6
- package/lib/dist/oc/convert.d.ts +1 -1
- package/lib/dist/oc/draft-ops.d.ts +1 -1
- package/lib/dist/oc/edge-ops.d.ts +2 -2
- package/lib/dist/oc/edge-ops.js +13 -14
- package/lib/dist/oc/edge-props.d.ts +1 -1
- package/lib/dist/oc/edge-query.d.ts +1 -1
- package/lib/dist/oc/edge-query.js +3 -8
- package/lib/dist/oc/errors.d.ts +8 -0
- package/lib/dist/oc/errors.js +27 -0
- package/lib/dist/oc/explorer.d.ts +2 -2
- package/lib/dist/oc/extrude-ops.d.ts +28 -2
- package/lib/dist/oc/extrude-ops.js +56 -7
- package/lib/dist/oc/face-ops.d.ts +2 -1
- package/lib/dist/oc/face-ops.js +11 -0
- package/lib/dist/oc/face-props.d.ts +1 -1
- package/lib/dist/oc/face-query.d.ts +12 -1
- package/lib/dist/oc/face-query.js +39 -0
- package/lib/dist/oc/fillet-ops.d.ts +1 -1
- package/lib/dist/oc/fillet-ops.js +4 -4
- package/lib/dist/oc/geometry.d.ts +1 -1
- package/lib/dist/oc/geometry.js +12 -14
- package/lib/dist/oc/helix-ops.d.ts +37 -0
- package/lib/dist/oc/helix-ops.js +88 -0
- package/lib/dist/oc/hit-test.d.ts +1 -1
- package/lib/dist/oc/index.d.ts +4 -0
- package/lib/dist/oc/index.js +2 -0
- package/lib/dist/oc/init.d.ts +1 -1
- package/lib/dist/oc/init.js +1 -1
- package/lib/dist/oc/intersection.js +1 -1
- package/lib/dist/oc/io.d.ts +6 -6
- package/lib/dist/oc/io.js +31 -24
- package/lib/dist/oc/measure/classify.d.ts +34 -0
- package/lib/dist/oc/measure/classify.js +246 -0
- package/lib/dist/oc/measure/measure-ops.d.ts +9 -0
- package/lib/dist/oc/measure/measure-ops.js +210 -0
- package/lib/dist/oc/measure/measure-types.d.ts +39 -0
- package/lib/dist/oc/measure/measure-types.js +1 -0
- package/lib/dist/oc/measure/sampling.d.ts +9 -0
- package/lib/dist/oc/measure/sampling.js +77 -0
- package/lib/dist/oc/measure/vec.d.ts +13 -0
- package/lib/dist/oc/measure/vec.js +23 -0
- package/lib/dist/oc/mesh.d.ts +1 -1
- package/lib/dist/oc/mesh.js +40 -28
- package/lib/dist/oc/path-sampler.d.ts +29 -0
- package/lib/dist/oc/path-sampler.js +63 -0
- package/lib/dist/oc/props.d.ts +1 -1
- package/lib/dist/oc/props.js +4 -1
- package/lib/dist/oc/shape-hash.d.ts +26 -0
- package/lib/dist/oc/shape-hash.js +32 -0
- package/lib/dist/oc/shape-ops.d.ts +5 -3
- package/lib/dist/oc/shape-ops.js +6 -5
- package/lib/dist/oc/sweep-ops.d.ts +22 -1
- package/lib/dist/oc/sweep-ops.js +206 -18
- package/lib/dist/oc/text-outline.d.ts +62 -0
- package/lib/dist/oc/text-outline.js +212 -0
- package/lib/dist/oc/topology-index.d.ts +1 -1
- package/lib/dist/oc/vertex-ops.d.ts +1 -1
- package/lib/dist/oc/wire-ops.d.ts +1 -1
- package/lib/dist/oc/wire-ops.js +1 -1
- package/lib/dist/oc/wrap-development.d.ts +105 -0
- package/lib/dist/oc/wrap-development.js +179 -0
- package/lib/dist/oc/wrap-ops.d.ts +100 -0
- package/lib/dist/oc/wrap-ops.js +406 -0
- package/lib/dist/rendering/render-solid.js +10 -2
- package/lib/dist/scene-manager.d.ts +2 -0
- package/lib/dist/scene-manager.js +29 -0
- package/lib/dist/tests/features/cylinder-curve-filter.test.js +3 -3
- package/lib/dist/tests/features/extrude-to-face.test.js +38 -1
- package/lib/dist/tests/features/helix.test.d.ts +1 -0
- package/lib/dist/tests/features/helix.test.js +295 -0
- package/lib/dist/tests/features/repeat-primitive.test.d.ts +1 -0
- package/lib/dist/tests/features/repeat-primitive.test.js +60 -0
- package/lib/dist/tests/features/rib.test.js +6 -1
- package/lib/dist/tests/features/sweep.test.js +125 -1
- package/lib/dist/tests/features/text.test.d.ts +1 -0
- package/lib/dist/tests/features/text.test.js +347 -0
- package/lib/dist/tests/features/wrap-development.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap-development.test.js +130 -0
- package/lib/dist/tests/features/wrap-extruded-target.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap-extruded-target.test.js +106 -0
- package/lib/dist/tests/features/wrap-repeat.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap-repeat.test.js +93 -0
- package/lib/dist/tests/features/wrap.test.d.ts +1 -0
- package/lib/dist/tests/features/wrap.test.js +331 -0
- package/lib/dist/tests/math/bspline-interpolation.test.d.ts +1 -0
- package/lib/dist/tests/math/bspline-interpolation.test.js +119 -0
- package/lib/dist/tests/measure.test.d.ts +1 -0
- package/lib/dist/tests/measure.test.js +288 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/llm-docs/api/helix.md +64 -0
- package/llm-docs/api/index.json +11 -2
- package/llm-docs/api/text.md +52 -0
- package/llm-docs/api/types/helix.md +105 -0
- package/llm-docs/api/types/text.md +138 -0
- package/llm-docs/api/types/wrap.md +131 -0
- package/llm-docs/api/wrap.md +62 -0
- package/llm-docs/index.json +121 -1
- package/mcp/dist/server.js +20 -1
- package/mcp/dist/tools/inspection.d.ts +17 -0
- package/mcp/dist/tools/inspection.js +14 -0
- package/package.json +7 -3
- package/server/dist/fluidcad-server.d.ts +29 -0
- package/server/dist/fluidcad-server.js +40 -0
- package/server/dist/index.js +4 -2
- package/server/dist/model-package/pack.js +7 -6
- package/server/dist/model-package/types.d.ts +4 -3
- package/server/dist/preferences.d.ts +4 -0
- package/server/dist/preferences.js +2 -0
- package/server/dist/routes/measure.d.ts +3 -0
- package/server/dist/routes/measure.js +32 -0
- package/server/dist/routes/preferences.js +6 -0
- package/server/dist/routes/sketch-edits.js +2 -1
- package/ui/dist/assets/{index-CDJmUpFI.css → index-dAFdg2Un.css} +1 -1
- package/ui/dist/assets/{index-MRqwG9Vh.js → index-no7mtr5s.js} +149 -102
- package/ui/dist/index.html +2 -2
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { getOC } from "./init.js";
|
|
2
|
+
import { Convert } from "./convert.js";
|
|
3
|
+
import { Edge } from "../common/edge.js";
|
|
4
|
+
import { CoordinateSystem } from "../math/coordinate-system.js";
|
|
5
|
+
/**
|
|
6
|
+
* Builds 3D helix edges with OCCT's TKHelix package. The analytic helix
|
|
7
|
+
* (`HelixGeom_HelixCurve`) is approximated as a single B-spline via
|
|
8
|
+
* `HelixGeom_Tools.ApprCurve3D`. Cylindrical and tapered (conical) helixes come
|
|
9
|
+
* from one uniform call — the taper is driven purely by the difference between
|
|
10
|
+
* the start and end radii over the axial range.
|
|
11
|
+
*
|
|
12
|
+
* NB: we deliberately do NOT use `HelixGeom_Tools.ApprHelix`, which hardcodes a
|
|
13
|
+
* 150-segment approximation budget. That is plenty for a cylinder (~3 segments
|
|
14
|
+
* per turn) but far too few for a many-turn tapered helix (~25+ per turn): the
|
|
15
|
+
* single-B-spline fit silently saturates the budget and oscillates wildly over
|
|
16
|
+
* the final turns while still reporting success (returnValue 0, theMaxError in
|
|
17
|
+
* the tens of mm). ApprCurve3D lets us scale the segment budget with the turn
|
|
18
|
+
* count so the adaptive fit can actually reach tolerance.
|
|
19
|
+
*/
|
|
20
|
+
export class HelixOps {
|
|
21
|
+
// B-spline approximation tolerance for the analytic helix, in mm.
|
|
22
|
+
static APPROX_TOLERANCE = 1e-4;
|
|
23
|
+
// Max B-spline degree for the fit (matches OCCT's ApprHelix default).
|
|
24
|
+
static MAX_DEGREE = 8;
|
|
25
|
+
// Segment budget per turn. A tapered helix needs ~25 segments/turn to reach
|
|
26
|
+
// APPROX_TOLERANCE; 40 leaves headroom. This is only a ceiling — the adaptive
|
|
27
|
+
// fit stops as soon as tolerance is met (a cylinder converges far below it).
|
|
28
|
+
static SEGMENTS_PER_TURN = 40;
|
|
29
|
+
// Floor (OCCT's ApprHelix default, ample for few-turn helixes) and ceiling on
|
|
30
|
+
// the per-build segment budget.
|
|
31
|
+
static MIN_SEGMENTS = 150;
|
|
32
|
+
static MAX_SEGMENTS = 4000;
|
|
33
|
+
/**
|
|
34
|
+
* Build a helix edge running `turns` full revolutions, climbing along
|
|
35
|
+
* `cs.mainDirection` from axial coordinate `zStart` to `zEnd` and starting at
|
|
36
|
+
* angle 0 (the `cs.xDirection` ray). `startRadius` is the radius at `zStart`;
|
|
37
|
+
* when `endRadius` differs the radius tapers linearly to it at `zEnd`, yielding
|
|
38
|
+
* a conical helix (`endRadius === startRadius` gives a constant-radius cylinder).
|
|
39
|
+
*/
|
|
40
|
+
static makeHelix(cs, startRadius, endRadius, zStart, zEnd, turns) {
|
|
41
|
+
const oc = getOC();
|
|
42
|
+
const height = zEnd - zStart;
|
|
43
|
+
const pitch = height / turns;
|
|
44
|
+
const taperAngle = Math.atan2(endRadius - startRadius, height);
|
|
45
|
+
const lastAngle = 2 * Math.PI * turns;
|
|
46
|
+
const maxSegments = Math.min(HelixOps.MAX_SEGMENTS, Math.max(HelixOps.MIN_SEGMENTS, Math.ceil(turns) * HelixOps.SEGMENTS_PER_TURN));
|
|
47
|
+
// Build the analytic helix in the canonical frame (axis +Z through the
|
|
48
|
+
// origin, angle 0 on +X) and approximate it as one B-spline spanning every
|
|
49
|
+
// turn. ApprCurve3D (not ApprHelix) so the segment budget scales with turns.
|
|
50
|
+
const adaptor = new oc.HelixGeom_HelixCurve();
|
|
51
|
+
adaptor.Load(0, lastAngle, pitch, startRadius, taperAngle, false);
|
|
52
|
+
const appr = oc.HelixGeom_Tools.ApprCurve3D(adaptor, HelixOps.APPROX_TOLERANCE, oc.GeomAbs_Shape.GeomAbs_C2, maxSegments, HelixOps.MAX_DEGREE);
|
|
53
|
+
if (appr.returnValue !== 0) {
|
|
54
|
+
appr[Symbol.dispose]();
|
|
55
|
+
adaptor.delete();
|
|
56
|
+
throw new Error(`HelixOps: helix approximation failed (status ${appr.returnValue}).`);
|
|
57
|
+
}
|
|
58
|
+
const edgeMaker = new oc.BRepBuilderAPI_MakeEdge(appr.theBSpl);
|
|
59
|
+
const canonicalEdge = edgeMaker.Edge();
|
|
60
|
+
// Relocate the canonical helix into the target frame (copies the geometry, so
|
|
61
|
+
// the result is independent of the approximation envelope released below).
|
|
62
|
+
const placedEdge = HelixOps.placeInFrame(canonicalEdge, cs, zStart);
|
|
63
|
+
edgeMaker.delete();
|
|
64
|
+
canonicalEdge.delete();
|
|
65
|
+
appr[Symbol.dispose]();
|
|
66
|
+
adaptor.delete();
|
|
67
|
+
return Edge.fromTopoDSEdge(placedEdge);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Rigidly move an edge built in the canonical frame (axis +Z through the
|
|
71
|
+
* origin) so it sits in `cs`, lifted along `cs.mainDirection` by `zStart`.
|
|
72
|
+
*/
|
|
73
|
+
static placeInFrame(edge, cs, zStart) {
|
|
74
|
+
const oc = getOC();
|
|
75
|
+
const origin = cs.origin.add(cs.mainDirection.normalize().multiply(zStart));
|
|
76
|
+
const placedCs = new CoordinateSystem(origin, cs.mainDirection, cs.xDirection);
|
|
77
|
+
const [ax3, disposeAx3] = Convert.toGpAx3(placedCs);
|
|
78
|
+
const trsf = new oc.gp_Trsf();
|
|
79
|
+
trsf.SetTransformation(ax3); // global coords → target frame …
|
|
80
|
+
trsf.Invert(); // … inverted places canonical geometry at the target frame
|
|
81
|
+
const transform = new oc.BRepBuilderAPI_Transform(edge, trsf, true);
|
|
82
|
+
const placedEdge = oc.TopoDS.Edge(transform.Shape());
|
|
83
|
+
transform.delete();
|
|
84
|
+
trsf.delete();
|
|
85
|
+
disposeAx3();
|
|
86
|
+
return placedEdge;
|
|
87
|
+
}
|
|
88
|
+
}
|
package/lib/dist/oc/index.d.ts
CHANGED
|
@@ -22,4 +22,8 @@ export { OcIO } from "./io.js";
|
|
|
22
22
|
export { ShapeProps } from './props.js';
|
|
23
23
|
export { SweepOps } from "./sweep-ops.js";
|
|
24
24
|
export { SectionOps } from "./section-ops.js";
|
|
25
|
+
export { HelixOps } from "./helix-ops.js";
|
|
25
26
|
export type { ShapeProperties } from './props.js';
|
|
27
|
+
export { MeasureOps } from "./measure/measure-ops.js";
|
|
28
|
+
export type { MeasureInput } from "./measure/measure-ops.js";
|
|
29
|
+
export type { MeasureResult, MeasureEntityRef, MeasureEntityInfo, MeasureEntityKind, MeasureDistanceValue, MeasurePrimaryKey, MeasureVec, } from "./measure/measure-types.js";
|
package/lib/dist/oc/index.js
CHANGED
|
@@ -20,3 +20,5 @@ export { OcIO } from "./io.js";
|
|
|
20
20
|
export { ShapeProps } from './props.js';
|
|
21
21
|
export { SweepOps } from "./sweep-ops.js";
|
|
22
22
|
export { SectionOps } from "./section-ops.js";
|
|
23
|
+
export { HelixOps } from "./helix-ops.js";
|
|
24
|
+
export { MeasureOps } from "./measure/measure-ops.js";
|
package/lib/dist/oc/init.d.ts
CHANGED
package/lib/dist/oc/init.js
CHANGED
|
@@ -20,7 +20,7 @@ export class ProjectionOps {
|
|
|
20
20
|
let wirePlane;
|
|
21
21
|
if (wirePlaneFinder.Found()) {
|
|
22
22
|
const handle = wirePlaneFinder.Plane();
|
|
23
|
-
const geomPln = handle
|
|
23
|
+
const geomPln = handle;
|
|
24
24
|
const pln = geomPln.Pln();
|
|
25
25
|
wirePlane = Convert.toPlane(pln);
|
|
26
26
|
// geomPln.delete();
|
package/lib/dist/oc/io.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TDocStd_Document, TopoDS_Shape } from "ocjs-fluidcad";
|
|
2
2
|
import { Shape } from "../common/shape.js";
|
|
3
3
|
import { Solid } from "../common/solid.js";
|
|
4
4
|
import { Face } from "../common/face.js";
|
|
@@ -11,7 +11,7 @@ export declare class OcIO {
|
|
|
11
11
|
static makeCompound(shapes: Shape[]): Shape;
|
|
12
12
|
static readBRepSolids(fileName: string, content: string): Solid[];
|
|
13
13
|
static writeSolidsAsBRep(solids: Solid[], fileName: string): string;
|
|
14
|
-
static extractSolidsAndColors(docHandle:
|
|
14
|
+
static extractSolidsAndColors(docHandle: TDocStd_Document): {
|
|
15
15
|
solids: Array<{
|
|
16
16
|
shape: Solid;
|
|
17
17
|
faceColors: Array<{
|
|
@@ -24,14 +24,14 @@ export declare class OcIO {
|
|
|
24
24
|
static writeBRepRaw(shape: TopoDS_Shape, fileName: string): string;
|
|
25
25
|
static readStepRaw(fileName: string, data: Uint8Array): TopoDS_Shape;
|
|
26
26
|
static readStepXCAF(fileName: string, data: Uint8Array): {
|
|
27
|
-
docHandle:
|
|
27
|
+
docHandle: TDocStd_Document;
|
|
28
28
|
cleanup: () => void;
|
|
29
29
|
};
|
|
30
|
-
static castToSolid(shape: TopoDS_Shape): import("
|
|
30
|
+
static castToSolid(shape: TopoDS_Shape): import("ocjs-fluidcad").TopoDS_Solid;
|
|
31
31
|
static findSolidsRaw(shape: TopoDS_Shape): TopoDS_Shape[];
|
|
32
32
|
static findFacesRaw(shape: TopoDS_Shape): TopoDS_Shape[];
|
|
33
|
-
static makeCompoundRaw(shapes: TopoDS_Shape[]): import("
|
|
34
|
-
static extractSolidsAndColorsRaw(docHandle:
|
|
33
|
+
static makeCompoundRaw(shapes: TopoDS_Shape[]): import("ocjs-fluidcad").TopoDS_Compound;
|
|
34
|
+
static extractSolidsAndColorsRaw(docHandle: TDocStd_Document): {
|
|
35
35
|
solids: Array<{
|
|
36
36
|
shape: TopoDS_Shape;
|
|
37
37
|
faceColors: Array<{
|
package/lib/dist/oc/io.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getOC } from "./init.js";
|
|
2
|
+
import { ShapeHasher } from "./shape-hash.js";
|
|
2
3
|
import { Explorer } from "./explorer.js";
|
|
3
4
|
import { Solid } from "../common/solid.js";
|
|
4
5
|
import { Face } from "../common/face.js";
|
|
@@ -79,7 +80,7 @@ export class OcIO {
|
|
|
79
80
|
static readStepRaw(fileName, data) {
|
|
80
81
|
const oc = getOC();
|
|
81
82
|
const uint8 = new Uint8Array(data);
|
|
82
|
-
oc.FS.
|
|
83
|
+
oc.FS.writeFile("/" + fileName, uint8);
|
|
83
84
|
const reader = new oc.STEPControl_Reader();
|
|
84
85
|
const readResult = reader.ReadFile(fileName);
|
|
85
86
|
if (readResult !== oc.IFSelect_ReturnStatus.IFSelect_RetDone) {
|
|
@@ -98,11 +99,11 @@ export class OcIO {
|
|
|
98
99
|
static readStepXCAF(fileName, data) {
|
|
99
100
|
const oc = getOC();
|
|
100
101
|
const uint8 = new Uint8Array(data);
|
|
101
|
-
oc.FS.
|
|
102
|
+
oc.FS.writeFile("/" + fileName, uint8);
|
|
102
103
|
const app = new oc.TDocStd_Application();
|
|
103
|
-
const docHandle = new oc.Handle_TDocStd_Document();
|
|
104
104
|
const format = new oc.TCollection_ExtendedString('MDTV-XCAF');
|
|
105
|
-
|
|
105
|
+
const docHandle = new oc.TDocStd_Document(format);
|
|
106
|
+
app.InitDocument(docHandle);
|
|
106
107
|
format.delete();
|
|
107
108
|
const reader = new oc.STEPCAFControl_Reader();
|
|
108
109
|
reader.SetColorMode(true);
|
|
@@ -132,7 +133,10 @@ export class OcIO {
|
|
|
132
133
|
const cleanup = () => {
|
|
133
134
|
reader.delete();
|
|
134
135
|
oc.FS.unlink(fileName);
|
|
135
|
-
app.Close(
|
|
136
|
+
// No app.Close(): the doc was created via `new TDocStd_Document` +
|
|
137
|
+
// InitDocument, which (in OCCT V8) does NOT open it in the application
|
|
138
|
+
// session. Close() therefore throws "cannot close a document that has not
|
|
139
|
+
// been opened"; deleting the handle releases it.
|
|
136
140
|
docHandle.delete();
|
|
137
141
|
app.delete();
|
|
138
142
|
};
|
|
@@ -161,11 +165,11 @@ export class OcIO {
|
|
|
161
165
|
}
|
|
162
166
|
static extractSolidsAndColorsRaw(docHandle) {
|
|
163
167
|
const oc = getOC();
|
|
164
|
-
const doc = docHandle
|
|
168
|
+
const doc = docHandle;
|
|
165
169
|
const shapeToolHandle = oc.XCAFDoc_DocumentTool.ShapeTool(doc.Main());
|
|
166
170
|
const colorToolHandle = oc.XCAFDoc_DocumentTool.ColorTool(doc.Main());
|
|
167
|
-
const shapeTool = shapeToolHandle
|
|
168
|
-
const colorTool = colorToolHandle
|
|
171
|
+
const shapeTool = shapeToolHandle;
|
|
172
|
+
const colorTool = colorToolHandle;
|
|
169
173
|
const surfType = oc.XCAFDoc_ColorType.XCAFDoc_ColorSurf;
|
|
170
174
|
const colorLabels = new oc.TDF_LabelSequence();
|
|
171
175
|
colorTool.GetColors(colorLabels);
|
|
@@ -173,6 +177,7 @@ export class OcIO {
|
|
|
173
177
|
colorLabels.delete();
|
|
174
178
|
const faceColorByHash = new Map();
|
|
175
179
|
const solidColorByHash = new Map();
|
|
180
|
+
const shapeHasher = new ShapeHasher();
|
|
176
181
|
const allLabels = new oc.TDF_LabelSequence();
|
|
177
182
|
shapeTool.GetShapes(allLabels);
|
|
178
183
|
let simpleShapeCount = 0;
|
|
@@ -184,15 +189,15 @@ export class OcIO {
|
|
|
184
189
|
simpleShapeCount++;
|
|
185
190
|
const shape = oc.XCAFDoc_ShapeTool.GetShape(label);
|
|
186
191
|
const labelColor = new oc.Quantity_Color();
|
|
187
|
-
if (
|
|
192
|
+
if (oc.XCAFDoc_ColorTool.GetColor(label, surfType, labelColor)) {
|
|
188
193
|
const hex = OcIO.rgbToHex(labelColor.Red(), labelColor.Green(), labelColor.Blue());
|
|
189
194
|
const labelSolids = OcIO.findSolidsRaw(shape);
|
|
190
195
|
for (const s of labelSolids) {
|
|
191
|
-
solidColorByHash.set(
|
|
196
|
+
solidColorByHash.set(shapeHasher.key(s), hex);
|
|
192
197
|
}
|
|
193
198
|
const labelFaces = OcIO.findFacesRaw(shape);
|
|
194
199
|
for (const f of labelFaces) {
|
|
195
|
-
faceColorByHash.set(
|
|
200
|
+
faceColorByHash.set(shapeHasher.key(f), hex);
|
|
196
201
|
}
|
|
197
202
|
}
|
|
198
203
|
labelColor.delete();
|
|
@@ -201,9 +206,9 @@ export class OcIO {
|
|
|
201
206
|
for (let j = 1; j <= subLabels.Length(); j++) {
|
|
202
207
|
const subLabel = subLabels.Value(j);
|
|
203
208
|
const subColor = new oc.Quantity_Color();
|
|
204
|
-
if (
|
|
209
|
+
if (oc.XCAFDoc_ColorTool.GetColor(subLabel, surfType, subColor)) {
|
|
205
210
|
const subShape = oc.XCAFDoc_ShapeTool.GetShape(subLabel);
|
|
206
|
-
faceColorByHash.set(
|
|
211
|
+
faceColorByHash.set(shapeHasher.key(subShape), OcIO.rgbToHex(subColor.Red(), subColor.Green(), subColor.Blue()));
|
|
207
212
|
subShapeColorCount++;
|
|
208
213
|
}
|
|
209
214
|
subColor.delete();
|
|
@@ -224,7 +229,7 @@ export class OcIO {
|
|
|
224
229
|
const faceColors = [];
|
|
225
230
|
for (let fi = 0; fi < faces.length; fi++) {
|
|
226
231
|
const face = faces[fi];
|
|
227
|
-
const color = OcIO.findFaceColor(face, solidShape, colorTool, shapeTool, oc, surfType, faceColorByHash, solidColorByHash);
|
|
232
|
+
const color = OcIO.findFaceColor(face, solidShape, colorTool, shapeTool, oc, surfType, faceColorByHash, solidColorByHash, shapeHasher);
|
|
228
233
|
if (color) {
|
|
229
234
|
faceColors.push({ faceIndex: fi, color });
|
|
230
235
|
}
|
|
@@ -235,6 +240,7 @@ export class OcIO {
|
|
|
235
240
|
freeLabels.delete();
|
|
236
241
|
shapeToolHandle.delete();
|
|
237
242
|
colorToolHandle.delete();
|
|
243
|
+
shapeHasher.delete();
|
|
238
244
|
return { solids };
|
|
239
245
|
}
|
|
240
246
|
static writeStepRaw(compound, fileName) {
|
|
@@ -260,15 +266,15 @@ export class OcIO {
|
|
|
260
266
|
static writeStepXCAF(solids, fileName) {
|
|
261
267
|
const oc = getOC();
|
|
262
268
|
const app = new oc.TDocStd_Application();
|
|
263
|
-
const docHandle = new oc.Handle_TDocStd_Document();
|
|
264
269
|
const format = new oc.TCollection_ExtendedString('MDTV-XCAF');
|
|
265
|
-
|
|
270
|
+
const docHandle = new oc.TDocStd_Document(format);
|
|
271
|
+
app.InitDocument(docHandle);
|
|
266
272
|
format.delete();
|
|
267
|
-
const doc = docHandle
|
|
273
|
+
const doc = docHandle;
|
|
268
274
|
const shapeToolHandle = oc.XCAFDoc_DocumentTool.ShapeTool(doc.Main());
|
|
269
275
|
const colorToolHandle = oc.XCAFDoc_DocumentTool.ColorTool(doc.Main());
|
|
270
|
-
const shapeTool = shapeToolHandle
|
|
271
|
-
const colorTool = colorToolHandle
|
|
276
|
+
const shapeTool = shapeToolHandle;
|
|
277
|
+
const colorTool = colorToolHandle;
|
|
272
278
|
const surfType = oc.XCAFDoc_ColorType.XCAFDoc_ColorSurf;
|
|
273
279
|
// Use NewShape + SetShape (per OCC docs) instead of AddShape to avoid
|
|
274
280
|
// compound wrapping that triggers multi-file assembly output.
|
|
@@ -286,7 +292,8 @@ export class OcIO {
|
|
|
286
292
|
const cleanup = () => {
|
|
287
293
|
shapeToolHandle.delete();
|
|
288
294
|
colorToolHandle.delete();
|
|
289
|
-
app.Close(
|
|
295
|
+
// No app.Close(): see readStepXCAF — an InitDocument'd (never opened) doc
|
|
296
|
+
// cannot be closed in OCCT V8; deleting the handle releases it.
|
|
290
297
|
docHandle.delete();
|
|
291
298
|
};
|
|
292
299
|
const writer = new oc.STEPCAFControl_Writer();
|
|
@@ -364,8 +371,8 @@ export class OcIO {
|
|
|
364
371
|
parseInt(h.substring(4, 6), 16) / 255,
|
|
365
372
|
];
|
|
366
373
|
}
|
|
367
|
-
static findFaceColor(face, solidShape, colorTool, shapeTool, oc, surfType, faceColorByHash, solidColorByHash) {
|
|
368
|
-
const hashColor = faceColorByHash.get(
|
|
374
|
+
static findFaceColor(face, solidShape, colorTool, shapeTool, oc, surfType, faceColorByHash, solidColorByHash, shapeHasher) {
|
|
375
|
+
const hashColor = faceColorByHash.get(shapeHasher.key(face));
|
|
369
376
|
if (hashColor)
|
|
370
377
|
return hashColor;
|
|
371
378
|
const color = new oc.Quantity_Color();
|
|
@@ -390,14 +397,14 @@ export class OcIO {
|
|
|
390
397
|
identityLoc.delete();
|
|
391
398
|
const faceLabel = new oc.TDF_Label();
|
|
392
399
|
if (shapeTool.SearchUsingMap(face, faceLabel, true, true)) {
|
|
393
|
-
if (
|
|
400
|
+
if (oc.XCAFDoc_ColorTool.GetColor(faceLabel, surfType, color)) {
|
|
394
401
|
const hex = OcIO.rgbToHex(color.Red(), color.Green(), color.Blue());
|
|
395
402
|
color.delete();
|
|
396
403
|
return hex;
|
|
397
404
|
}
|
|
398
405
|
}
|
|
399
406
|
color.delete();
|
|
400
|
-
const solidHash = solidColorByHash.get(
|
|
407
|
+
const solidHash = solidColorByHash.get(shapeHasher.key(solidShape));
|
|
401
408
|
if (solidHash)
|
|
402
409
|
return solidHash;
|
|
403
410
|
const solidColor = new oc.Quantity_Color();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { TopoDS_Shape } from "ocjs-fluidcad";
|
|
2
|
+
import type { MeasureEntityKind, MeasureVec } from "./measure-types.js";
|
|
3
|
+
export type FaceForm = 'plane' | 'cylinder' | 'cone' | 'sphere' | 'torus' | 'surface';
|
|
4
|
+
export type EdgeForm = 'line' | 'circle' | 'arc' | 'ellipse' | 'curve';
|
|
5
|
+
/**
|
|
6
|
+
* Geometric summary of a selected face or edge, in plain JS values so all the
|
|
7
|
+
* pair math (angles, parallel distances, projections) runs without further
|
|
8
|
+
* OCCT calls.
|
|
9
|
+
*/
|
|
10
|
+
export interface ClassifiedEntity {
|
|
11
|
+
kind: MeasureEntityKind;
|
|
12
|
+
form: FaceForm | EdgeForm;
|
|
13
|
+
/** Unit direction characterizing the entity, or null when it has none. */
|
|
14
|
+
dir: MeasureVec | null;
|
|
15
|
+
/**
|
|
16
|
+
* How `dir` relates to the entity: a 'normal' is perpendicular to the entity
|
|
17
|
+
* (plane normal, circle-plane normal, torus axis), an 'axis' runs along it
|
|
18
|
+
* (line direction, cylinder/cone axis). Two entities lie parallel when
|
|
19
|
+
* normal∥normal, axis∥axis, or normal⊥axis.
|
|
20
|
+
*/
|
|
21
|
+
dirKind: 'normal' | 'axis' | null;
|
|
22
|
+
/** A point on the entity's defining element (plane location, axis location). */
|
|
23
|
+
point: MeasureVec | null;
|
|
24
|
+
/** True geometric center (circle/arc/ellipse/sphere/torus), else null. */
|
|
25
|
+
center: MeasureVec | null;
|
|
26
|
+
/** Representative point on the entity (face area centroid, edge midpoint) used to anchor measurement lines. */
|
|
27
|
+
anchor: MeasureVec;
|
|
28
|
+
radius?: number;
|
|
29
|
+
area?: number;
|
|
30
|
+
length?: number;
|
|
31
|
+
shape: TopoDS_Shape;
|
|
32
|
+
}
|
|
33
|
+
export declare function classifyFace(shape: TopoDS_Shape): ClassifiedEntity;
|
|
34
|
+
export declare function classifyEdge(shape: TopoDS_Shape): ClassifiedEntity;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { getOC } from "../init.js";
|
|
2
|
+
import { cross, dot, len, scale, sub } from "./vec.js";
|
|
3
|
+
function vecFromPnt(p) {
|
|
4
|
+
const v = { x: p.X(), y: p.Y(), z: p.Z() };
|
|
5
|
+
p.delete();
|
|
6
|
+
return v;
|
|
7
|
+
}
|
|
8
|
+
function vecFromDir(d) {
|
|
9
|
+
const v = { x: d.X(), y: d.Y(), z: d.Z() };
|
|
10
|
+
d.delete();
|
|
11
|
+
return v;
|
|
12
|
+
}
|
|
13
|
+
function axisData(axis) {
|
|
14
|
+
const data = { point: vecFromPnt(axis.Location()), dir: vecFromDir(axis.Direction()) };
|
|
15
|
+
axis.delete();
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
// Booleans, text outlines, wraps and lofts often carry geometrically planar
|
|
19
|
+
// faces / straight edges on fitted B-spline (or extruded-curve) geometry, so
|
|
20
|
+
// the adaptor type alone misses them. These sampling fallbacks recover the
|
|
21
|
+
// carrier plane/line numerically. (OCCT's GeomLib_IsPlanarSurface would do the
|
|
22
|
+
// face check natively but is not in the current ocjs binding.)
|
|
23
|
+
const CARRIER_FIT_TOL = 1e-6;
|
|
24
|
+
const PLANAR_GRID_STEPS = 5;
|
|
25
|
+
const STRAIGHT_EDGE_STEPS = 8;
|
|
26
|
+
function detectPlanarSurface(adaptor) {
|
|
27
|
+
const u1 = adaptor.FirstUParameter();
|
|
28
|
+
const u2 = adaptor.LastUParameter();
|
|
29
|
+
const v1 = adaptor.FirstVParameter();
|
|
30
|
+
const v2 = adaptor.LastVParameter();
|
|
31
|
+
if (!isFinite(u1) || !isFinite(u2) || !isFinite(v1) || !isFinite(v2)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const points = [];
|
|
35
|
+
for (let i = 0; i <= PLANAR_GRID_STEPS; i++) {
|
|
36
|
+
for (let j = 0; j <= PLANAR_GRID_STEPS; j++) {
|
|
37
|
+
const p = adaptor.Value(u1 + ((u2 - u1) * i) / PLANAR_GRID_STEPS, v1 + ((v2 - v1) * j) / PLANAR_GRID_STEPS);
|
|
38
|
+
points.push({ x: p.X(), y: p.Y(), z: p.Z() });
|
|
39
|
+
p.delete();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const origin = points[0];
|
|
43
|
+
let span = points[0];
|
|
44
|
+
let spanDist = 0;
|
|
45
|
+
for (const p of points) {
|
|
46
|
+
const d = len(sub(p, origin));
|
|
47
|
+
if (d > spanDist) {
|
|
48
|
+
spanDist = d;
|
|
49
|
+
span = p;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (spanDist < CARRIER_FIT_TOL) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const e1 = scale(sub(span, origin), 1 / spanDist);
|
|
56
|
+
let normal = null;
|
|
57
|
+
let normalLen = 0;
|
|
58
|
+
for (const p of points) {
|
|
59
|
+
const n = cross(e1, sub(p, origin));
|
|
60
|
+
const nLen = len(n);
|
|
61
|
+
if (nLen > normalLen) {
|
|
62
|
+
normalLen = nLen;
|
|
63
|
+
normal = n;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!normal || normalLen < CARRIER_FIT_TOL * spanDist) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const dir = scale(normal, 1 / normalLen);
|
|
70
|
+
const tol = CARRIER_FIT_TOL * (1 + spanDist);
|
|
71
|
+
for (const p of points) {
|
|
72
|
+
if (Math.abs(dot(sub(p, origin), dir)) > tol) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { point: origin, dir };
|
|
77
|
+
}
|
|
78
|
+
function detectStraightCurve(adaptor, first, last) {
|
|
79
|
+
const points = [];
|
|
80
|
+
for (let i = 0; i <= STRAIGHT_EDGE_STEPS; i++) {
|
|
81
|
+
const p = adaptor.Value(first + ((last - first) * i) / STRAIGHT_EDGE_STEPS);
|
|
82
|
+
points.push({ x: p.X(), y: p.Y(), z: p.Z() });
|
|
83
|
+
p.delete();
|
|
84
|
+
}
|
|
85
|
+
const chord = sub(points[points.length - 1], points[0]);
|
|
86
|
+
const chordLen = len(chord);
|
|
87
|
+
if (chordLen < CARRIER_FIT_TOL) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const dir = scale(chord, 1 / chordLen);
|
|
91
|
+
const tol = CARRIER_FIT_TOL * (1 + chordLen);
|
|
92
|
+
for (const p of points) {
|
|
93
|
+
if (len(cross(sub(p, points[0]), dir)) > tol) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { point: points[0], dir };
|
|
98
|
+
}
|
|
99
|
+
export function classifyFace(shape) {
|
|
100
|
+
const oc = getOC();
|
|
101
|
+
const face = oc.TopoDS.Face(shape);
|
|
102
|
+
const props = new oc.GProp_GProps();
|
|
103
|
+
oc.BRepGProp.SurfaceProperties(face, props, false, false);
|
|
104
|
+
const area = props.Mass();
|
|
105
|
+
const anchor = vecFromPnt(props.CentreOfMass());
|
|
106
|
+
props.delete();
|
|
107
|
+
const result = {
|
|
108
|
+
kind: 'face',
|
|
109
|
+
form: 'surface',
|
|
110
|
+
dir: null,
|
|
111
|
+
dirKind: null,
|
|
112
|
+
point: null,
|
|
113
|
+
center: null,
|
|
114
|
+
anchor,
|
|
115
|
+
area,
|
|
116
|
+
shape,
|
|
117
|
+
};
|
|
118
|
+
const adaptor = new oc.BRepAdaptor_Surface(face, true);
|
|
119
|
+
const type = adaptor.GetType();
|
|
120
|
+
if (type === oc.GeomAbs_SurfaceType.GeomAbs_Plane) {
|
|
121
|
+
const plane = adaptor.Plane();
|
|
122
|
+
const { point, dir } = axisData(plane.Axis());
|
|
123
|
+
plane.delete();
|
|
124
|
+
result.form = 'plane';
|
|
125
|
+
result.point = point;
|
|
126
|
+
result.dir = dir;
|
|
127
|
+
result.dirKind = 'normal';
|
|
128
|
+
}
|
|
129
|
+
else if (type === oc.GeomAbs_SurfaceType.GeomAbs_Cylinder) {
|
|
130
|
+
const cylinder = adaptor.Cylinder();
|
|
131
|
+
const { point, dir } = axisData(cylinder.Axis());
|
|
132
|
+
result.radius = cylinder.Radius();
|
|
133
|
+
cylinder.delete();
|
|
134
|
+
result.form = 'cylinder';
|
|
135
|
+
result.point = point;
|
|
136
|
+
result.dir = dir;
|
|
137
|
+
result.dirKind = 'axis';
|
|
138
|
+
}
|
|
139
|
+
else if (type === oc.GeomAbs_SurfaceType.GeomAbs_Cone) {
|
|
140
|
+
const cone = adaptor.Cone();
|
|
141
|
+
const { point, dir } = axisData(cone.Axis());
|
|
142
|
+
cone.delete();
|
|
143
|
+
result.form = 'cone';
|
|
144
|
+
result.point = point;
|
|
145
|
+
result.dir = dir;
|
|
146
|
+
result.dirKind = 'axis';
|
|
147
|
+
}
|
|
148
|
+
else if (type === oc.GeomAbs_SurfaceType.GeomAbs_Sphere) {
|
|
149
|
+
const sphere = adaptor.Sphere();
|
|
150
|
+
const center = vecFromPnt(sphere.Location());
|
|
151
|
+
result.radius = sphere.Radius();
|
|
152
|
+
sphere.delete();
|
|
153
|
+
result.form = 'sphere';
|
|
154
|
+
result.point = center;
|
|
155
|
+
result.center = center;
|
|
156
|
+
}
|
|
157
|
+
else if (type === oc.GeomAbs_SurfaceType.GeomAbs_Torus) {
|
|
158
|
+
const torus = adaptor.Torus();
|
|
159
|
+
const { point, dir } = axisData(torus.Axis());
|
|
160
|
+
torus.delete();
|
|
161
|
+
result.form = 'torus';
|
|
162
|
+
result.point = point;
|
|
163
|
+
result.center = point;
|
|
164
|
+
result.dir = dir;
|
|
165
|
+
result.dirKind = 'normal';
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
const planar = detectPlanarSurface(adaptor);
|
|
169
|
+
if (planar) {
|
|
170
|
+
result.form = 'plane';
|
|
171
|
+
result.point = planar.point;
|
|
172
|
+
result.dir = planar.dir;
|
|
173
|
+
result.dirKind = 'normal';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
adaptor.delete();
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
export function classifyEdge(shape) {
|
|
180
|
+
const oc = getOC();
|
|
181
|
+
const edge = oc.TopoDS.Edge(shape);
|
|
182
|
+
const props = new oc.GProp_GProps();
|
|
183
|
+
oc.BRepGProp.LinearProperties(edge, props, false, false);
|
|
184
|
+
const length = props.Mass();
|
|
185
|
+
props.delete();
|
|
186
|
+
const adaptor = new oc.BRepAdaptor_Curve(edge);
|
|
187
|
+
const first = adaptor.FirstParameter();
|
|
188
|
+
const last = adaptor.LastParameter();
|
|
189
|
+
const anchor = vecFromPnt(adaptor.Value((first + last) / 2));
|
|
190
|
+
const result = {
|
|
191
|
+
kind: 'edge',
|
|
192
|
+
form: 'curve',
|
|
193
|
+
dir: null,
|
|
194
|
+
dirKind: null,
|
|
195
|
+
point: null,
|
|
196
|
+
center: null,
|
|
197
|
+
anchor,
|
|
198
|
+
length,
|
|
199
|
+
shape,
|
|
200
|
+
};
|
|
201
|
+
const type = adaptor.GetType();
|
|
202
|
+
if (type === oc.GeomAbs_CurveType.GeomAbs_Line) {
|
|
203
|
+
const line = adaptor.Line();
|
|
204
|
+
const point = vecFromPnt(line.Location());
|
|
205
|
+
const dir = vecFromDir(line.Direction());
|
|
206
|
+
line.delete();
|
|
207
|
+
result.form = 'line';
|
|
208
|
+
result.point = point;
|
|
209
|
+
result.dir = dir;
|
|
210
|
+
result.dirKind = 'axis';
|
|
211
|
+
}
|
|
212
|
+
else if (type === oc.GeomAbs_CurveType.GeomAbs_Circle) {
|
|
213
|
+
const circle = adaptor.Circle();
|
|
214
|
+
const center = vecFromPnt(circle.Location());
|
|
215
|
+
const { dir } = axisData(circle.Axis());
|
|
216
|
+
result.radius = circle.Radius();
|
|
217
|
+
circle.delete();
|
|
218
|
+
result.form = adaptor.IsClosed() ? 'circle' : 'arc';
|
|
219
|
+
result.point = center;
|
|
220
|
+
result.center = center;
|
|
221
|
+
result.dir = dir;
|
|
222
|
+
result.dirKind = 'normal';
|
|
223
|
+
}
|
|
224
|
+
else if (type === oc.GeomAbs_CurveType.GeomAbs_Ellipse) {
|
|
225
|
+
const ellipse = adaptor.Ellipse();
|
|
226
|
+
const center = vecFromPnt(ellipse.Location());
|
|
227
|
+
const { dir } = axisData(ellipse.Axis());
|
|
228
|
+
ellipse.delete();
|
|
229
|
+
result.form = 'ellipse';
|
|
230
|
+
result.point = center;
|
|
231
|
+
result.center = center;
|
|
232
|
+
result.dir = dir;
|
|
233
|
+
result.dirKind = 'normal';
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
const straight = detectStraightCurve(adaptor, first, last);
|
|
237
|
+
if (straight) {
|
|
238
|
+
result.form = 'line';
|
|
239
|
+
result.point = straight.point;
|
|
240
|
+
result.dir = straight.dir;
|
|
241
|
+
result.dirKind = 'axis';
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
adaptor.delete();
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TopoDS_Shape } from "ocjs-fluidcad";
|
|
2
|
+
import type { MeasureEntityRef, MeasureResult } from "./measure-types.js";
|
|
3
|
+
export interface MeasureInput {
|
|
4
|
+
ref: MeasureEntityRef;
|
|
5
|
+
shape: TopoDS_Shape;
|
|
6
|
+
}
|
|
7
|
+
export declare class MeasureOps {
|
|
8
|
+
static measure(inputs: MeasureInput[]): MeasureResult;
|
|
9
|
+
}
|