@toolpath/viewer 2.0.0 → 2.2.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/README.md +69 -16
- package/dist/{chunk-4TBLMR4Z.js → chunk-WTTOUG4P.js} +27 -14
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +126 -3
- package/dist/index.js +212 -2
- package/dist/{normalize-CvnV9Ggh.d.ts → normalize--FiXUhO4.d.ts} +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -357,9 +357,9 @@ individual buttons to use only the controls and order your application needs.
|
|
|
357
357
|
</ViewerToolbarProvider>
|
|
358
358
|
```
|
|
359
359
|
|
|
360
|
-
`ViewerToolbar.Controls`, `Divider`, and the
|
|
361
|
-
`ViewerToolbar`: `StockButton`, `AxesButton`, `GridButton`, `BananaButton`, `DirectionsButton`,
|
|
362
|
-
`HoverButton`, `FocusButton`, `WireframeButton`, `SectionButton`, `MeasureButton`, `FitButton`,
|
|
360
|
+
`ViewerToolbar.Controls`, `Divider`, and the fifteen `*Button` components are available on
|
|
361
|
+
`ViewerToolbar`: `StockButton`, `AxesButton`, `GridButton`, `BananaButton`, `ToolsButton`, `DirectionsButton`,
|
|
362
|
+
`DfmButton` (shows or hides an application's DFM flags), `HoverButton`, `FocusButton`, `WireframeButton`, `SectionButton`, `MeasureButton`, `FitButton`,
|
|
363
363
|
`ResetButton`, and `TopButton`. A rendered button requires its matching provider control. For an
|
|
364
364
|
application-specific toolbar component, `useViewerToolbar()` reads the same controls from inside
|
|
365
365
|
the provider.
|
|
@@ -388,19 +388,19 @@ override any of these selectors in your application stylesheet.
|
|
|
388
388
|
The following `data-*` attributes identify generated elements without depending on labels, which
|
|
389
389
|
can change with state or localization:
|
|
390
390
|
|
|
391
|
-
| Attribute | Element and values
|
|
392
|
-
| ------------------------------------- |
|
|
393
|
-
| `data-viewer-root="true"` | `<Viewer>` wrapper
|
|
394
|
-
| `data-viewer-canvas-container="true"` | R3F canvas event container
|
|
395
|
-
| `data-viewer-canvas-frame="true"` | R3F canvas-sizing frame
|
|
396
|
-
| `data-viewer-canvas="true"` | The `<canvas>` itself
|
|
397
|
-
| `data-viewer-hover-card="true"` | `<HoverCard>` shell
|
|
398
|
-
| `data-viewer-toolbar="true"` | Toolbar stack
|
|
399
|
-
| `data-viewer-toolbar-controls="true"` | Controls group
|
|
400
|
-
| `data-viewer-toolbar-action` | Standard button: `stock`, `axes`, `grid`, `banana`, `directions`, `hover`, `focus`, `wireframe`, `section`, `measure`, `fit`, `reset`, or `top` |
|
|
401
|
-
| `data-viewer-toolbar-icon="true"` | Standard button SVG
|
|
402
|
-
| `data-viewer-toolbar-tooltip="true"` | Standard button tooltip
|
|
403
|
-
| `data-viewer-toolbar-divider="true"` | Toolbar separator
|
|
391
|
+
| Attribute | Element and values |
|
|
392
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
393
|
+
| `data-viewer-root="true"` | `<Viewer>` wrapper |
|
|
394
|
+
| `data-viewer-canvas-container="true"` | R3F canvas event container |
|
|
395
|
+
| `data-viewer-canvas-frame="true"` | R3F canvas-sizing frame |
|
|
396
|
+
| `data-viewer-canvas="true"` | The `<canvas>` itself |
|
|
397
|
+
| `data-viewer-hover-card="true"` | `<HoverCard>` shell |
|
|
398
|
+
| `data-viewer-toolbar="true"` | Toolbar stack |
|
|
399
|
+
| `data-viewer-toolbar-controls="true"` | Controls group |
|
|
400
|
+
| `data-viewer-toolbar-action` | Standard button: `stock`, `axes`, `grid`, `banana`, `tools`, `directions`, `hover`, `focus`, `wireframe`, `section`, `measure`, `fit`, `reset`, or `top` |
|
|
401
|
+
| `data-viewer-toolbar-icon="true"` | Standard button SVG |
|
|
402
|
+
| `data-viewer-toolbar-tooltip="true"` | Standard button tooltip |
|
|
403
|
+
| `data-viewer-toolbar-divider="true"` | Toolbar separator |
|
|
404
404
|
|
|
405
405
|
Toggle buttons also carry standard `aria-pressed="true"` or `"false"`; use that to style their
|
|
406
406
|
current state. `Fit`, `Reset`, and `Top view` are actions rather than toggles, so they omit the
|
|
@@ -501,6 +501,7 @@ Draws the part and handles clicks. You only use it directly when you
|
|
|
501
501
|
| `section` | `SectionOptions` | Cut the part open. Omit it to follow the viewer's own cut. See [Section view](#section-view). |
|
|
502
502
|
| `onSectionChange` | `(state: SectionState) => void` | Called when the cut moves or goes away. With `section`, passing it also shows the drag handle. |
|
|
503
503
|
| `onAdjacency` | `(map) => void` | Called once per mesh with which faces touch which. |
|
|
504
|
+
| `children` | `ReactNode` | Objects drawn on the part. They read its model and mesh with `usePartContext()`. |
|
|
504
505
|
|
|
505
506
|
Hovering over the part is handled for you. You only need `onHover` if you want to show the hovered
|
|
506
507
|
feature elsewhere in your UI.
|
|
@@ -606,6 +607,56 @@ what a label looks like is your stylesheet's, through the `toolpath-measure-labe
|
|
|
606
607
|
data attributes on each one — see [Measuring](#measuring) for a starting point. While the tool is
|
|
607
608
|
mounted the part reports no hovers or picks, as with `<SectionTool>`.
|
|
608
609
|
|
|
610
|
+
### `<ToolMarks>`
|
|
611
|
+
|
|
612
|
+
Cutting tools drawn on the part, each to scale where it stands: a see-through end mill — flat,
|
|
613
|
+
bull nose or ball — or any tool given by its profile, rimmed at its bottom and top, with a dimension
|
|
614
|
+
across its top and a label on it. What a tool stands for is yours: the widest tool a pocket admits, the tool an operation uses.
|
|
615
|
+
Nothing here reads a datasheet.
|
|
616
|
+
|
|
617
|
+
```tsx
|
|
618
|
+
<EnginePart report={report}>
|
|
619
|
+
<ToolMarks
|
|
620
|
+
marks={[
|
|
621
|
+
{
|
|
622
|
+
base: { x: 12, y: 4, z: -8 },
|
|
623
|
+
axis: { x: 0, y: 0, z: 1 },
|
|
624
|
+
diameter: 6,
|
|
625
|
+
height: 8,
|
|
626
|
+
cornerRadius: 0.5,
|
|
627
|
+
label: '⌀ 6.000 mm',
|
|
628
|
+
note: 'bull nose R 0.5',
|
|
629
|
+
},
|
|
630
|
+
]}
|
|
631
|
+
/>
|
|
632
|
+
</EnginePart>
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
| Prop | What it does |
|
|
636
|
+
| ---------------- | ---------------------------------------------------------------------------------- |
|
|
637
|
+
| `marks` | The tools, in the coordinates the part is drawn in. See `ToolMark` below. |
|
|
638
|
+
| `visible` | `false` hides them without unmounting. On by default. |
|
|
639
|
+
| `labelClassName` | Added to every label, beside `toolpath-measure-label`. |
|
|
640
|
+
| `theme` | `measure` colours the rims and the dimension, as it does the measure tool's lines. |
|
|
641
|
+
|
|
642
|
+
A `ToolMark` is `base` (the centre of the tool's bottom), `axis` (up the tool), `diameter`,
|
|
643
|
+
`height`, and optionally `cornerRadius` (0 flat, half the diameter a ball), `across` (which way the
|
|
644
|
+
dimension runs; any direction square to the axis otherwise), `label` and `note`. Any other tool —
|
|
645
|
+
a drill, a chamfer mill, a tool in its holder — takes `profile`: its side as `{ r, z }` points from
|
|
646
|
+
the tip up, such as `@toolpath/tool-drawing`'s outline, turned about the axis in place of the end
|
|
647
|
+
mill.
|
|
648
|
+
|
|
649
|
+
Show and hide them with `visible`, from the toolbar's `ToolsButton` and its `tools` control.
|
|
650
|
+
|
|
651
|
+
It draws as `<MeasureTool>` draws: the lines show through the part, and each label is an unstyled
|
|
652
|
+
`<div class="toolpath-measure-label" data-measure-label="tool">` with its text in a
|
|
653
|
+
`data-measure-value` span and its note in a `data-measure-note` one. The marks take no pointer
|
|
654
|
+
events and are left out of framing.
|
|
655
|
+
|
|
656
|
+
Inside `<PartMesh>` or `<EnginePart>`, `usePartContext()` gives the part's `model` and `geometry`,
|
|
657
|
+
and `featureTriangles(model, geometry, tag)` a feature's triangles, for working out where a tool
|
|
658
|
+
stands.
|
|
659
|
+
|
|
609
660
|
### `<Grid>` and `<Axes>`
|
|
610
661
|
|
|
611
662
|
Reference geometry. The camera ignores both when it frames the part.
|
|
@@ -1185,6 +1236,7 @@ is a complete app built this way, with no API key needed.
|
|
|
1185
1236
|
| `useViewerToolbar()` | Inside `<ViewerToolbarProvider>` | Get the actions and state supplied to the provider. |
|
|
1186
1237
|
| `useSectionStore()` | Inside `<Viewer>` | Read, set, or subscribe to the viewer's own cut. |
|
|
1187
1238
|
| `useContentBox()` | Inside `<Viewer>` | Get the part's bounding box (a `THREE.Box3`, empty until loaded). |
|
|
1239
|
+
| `usePartContext()` | Inside `<PartMesh>` | Get the part's `model` and the `geometry` it is drawn from, for an overlay. |
|
|
1188
1240
|
| `useTapGuard()` | Inside `<Viewer>` | Check whether a pointer event was a click and not a drag. |
|
|
1189
1241
|
|
|
1190
1242
|
### Helpers
|
|
@@ -1198,6 +1250,7 @@ is a complete app built this way, with no API key needed.
|
|
|
1198
1250
|
| `focusForPick(pick, lastRegion, lastFocus)` | Steps through a face's matches on repeated clicks. |
|
|
1199
1251
|
| `rankOwners` / `bestOwner` | The ranking `onPick` uses, if you want to run it yourself. |
|
|
1200
1252
|
| `groupByDirection(model)` | Features grouped by machining direction. |
|
|
1253
|
+
| `featureTriangles(model, geometry, tag)` | A feature's triangles and outward normals, as plain arrays. |
|
|
1201
1254
|
| `directionLabel(v)` / `directionColor(i)` | A direction's label and colour. |
|
|
1202
1255
|
| `sectionFromPick({ point, normal })` | Turns a clicked surface into a section plane. |
|
|
1203
1256
|
| `measurementLabel(measurement, format?)` | Writes a measurement the way `<MeasureTool>` labels it. |
|
|
@@ -13,6 +13,15 @@ import {
|
|
|
13
13
|
} from "react";
|
|
14
14
|
import { Vector3 as Vector311 } from "three";
|
|
15
15
|
|
|
16
|
+
// src/part-context.tsx
|
|
17
|
+
import { createContext, useContext } from "react";
|
|
18
|
+
var PartContext = createContext(null);
|
|
19
|
+
var usePartContext = () => {
|
|
20
|
+
const part = useContext(PartContext);
|
|
21
|
+
if (!part) throw new Error("usePartContext must be used inside <PartMesh> or <EnginePart>");
|
|
22
|
+
return part;
|
|
23
|
+
};
|
|
24
|
+
|
|
16
25
|
// src/model/directions.ts
|
|
17
26
|
var EPSILON = 1e-6;
|
|
18
27
|
function sameDirection(a, b) {
|
|
@@ -781,8 +790,8 @@ function perpendicular(axis) {
|
|
|
781
790
|
// src/tap.tsx
|
|
782
791
|
import { useThree } from "@react-three/fiber";
|
|
783
792
|
import {
|
|
784
|
-
createContext,
|
|
785
|
-
useContext,
|
|
793
|
+
createContext as createContext2,
|
|
794
|
+
useContext as useContext2,
|
|
786
795
|
useEffect,
|
|
787
796
|
useMemo,
|
|
788
797
|
useRef
|
|
@@ -823,10 +832,10 @@ function trackDoubleTaps(within = DOUBLE_TAP_MS, slop = TAP_SLOP) {
|
|
|
823
832
|
|
|
824
833
|
// src/tap.tsx
|
|
825
834
|
import { jsx } from "react/jsx-runtime";
|
|
826
|
-
var ViewerTapContext =
|
|
835
|
+
var ViewerTapContext = createContext2(null);
|
|
827
836
|
var ViewerTapProvider = ({ value, children }) => /* @__PURE__ */ jsx(ViewerTapContext.Provider, { value, children });
|
|
828
837
|
function useTapGuard() {
|
|
829
|
-
const shared =
|
|
838
|
+
const shared = useContext2(ViewerTapContext);
|
|
830
839
|
const domElement = useThree((state) => state.gl.domElement);
|
|
831
840
|
const tracker = useRef(null);
|
|
832
841
|
useEffect(() => {
|
|
@@ -1319,10 +1328,10 @@ function focusForPick(pick, previousRegion, previousFocus) {
|
|
|
1319
1328
|
// src/viewer.tsx
|
|
1320
1329
|
import { Canvas, useFrame as useFrame3, useThree as useThree4 } from "@react-three/fiber";
|
|
1321
1330
|
import {
|
|
1322
|
-
createContext as
|
|
1331
|
+
createContext as createContext3,
|
|
1323
1332
|
forwardRef,
|
|
1324
1333
|
useCallback,
|
|
1325
|
-
useContext as
|
|
1334
|
+
useContext as useContext3,
|
|
1326
1335
|
useEffect as useEffect4,
|
|
1327
1336
|
useImperativeHandle,
|
|
1328
1337
|
useMemo as useMemo4,
|
|
@@ -2193,20 +2202,20 @@ function labelTexture(label, color) {
|
|
|
2193
2202
|
|
|
2194
2203
|
// src/viewer.tsx
|
|
2195
2204
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2196
|
-
var ViewerControlsContext =
|
|
2205
|
+
var ViewerControlsContext = createContext3(null);
|
|
2197
2206
|
var useViewerControls = () => {
|
|
2198
|
-
const controls =
|
|
2207
|
+
const controls = useContext3(ViewerControlsContext);
|
|
2199
2208
|
if (!controls) throw new Error("useViewerControls must be used inside <Viewer>");
|
|
2200
2209
|
return controls;
|
|
2201
2210
|
};
|
|
2202
|
-
var SectionStoreContext =
|
|
2211
|
+
var SectionStoreContext = createContext3(null);
|
|
2203
2212
|
var useSectionStore = () => {
|
|
2204
|
-
const store =
|
|
2213
|
+
const store = useContext3(SectionStoreContext);
|
|
2205
2214
|
if (!store) throw new Error("useSectionStore must be used inside <Viewer>");
|
|
2206
2215
|
return store;
|
|
2207
2216
|
};
|
|
2208
|
-
var ViewerRetargetContext =
|
|
2209
|
-
var useRetarget = () =>
|
|
2217
|
+
var ViewerRetargetContext = createContext3(null);
|
|
2218
|
+
var useRetarget = () => useContext3(ViewerRetargetContext);
|
|
2210
2219
|
var ViewerScene = ({
|
|
2211
2220
|
children,
|
|
2212
2221
|
setControls,
|
|
@@ -3029,9 +3038,11 @@ var PartMesh = ({
|
|
|
3029
3038
|
onPick,
|
|
3030
3039
|
theme,
|
|
3031
3040
|
showEdges = true,
|
|
3032
|
-
display = "solid"
|
|
3041
|
+
display = "solid",
|
|
3042
|
+
children
|
|
3033
3043
|
}) => {
|
|
3034
3044
|
const { camera, controls, invalidate } = useThree7();
|
|
3045
|
+
const context = useMemo6(() => ({ model, geometry }), [model, geometry]);
|
|
3035
3046
|
const viewerControls = useViewerControls();
|
|
3036
3047
|
const resolved = useStableTheme(theme);
|
|
3037
3048
|
const currentTheme = useRef6(resolved);
|
|
@@ -3243,7 +3254,8 @@ var PartMesh = ({
|
|
|
3243
3254
|
showHandle: !controlled || onSectionChange !== void 0,
|
|
3244
3255
|
onDrag: !controlled || onSectionChange ? dragSection : void 0
|
|
3245
3256
|
}
|
|
3246
|
-
) : null
|
|
3257
|
+
) : null,
|
|
3258
|
+
children ? /* @__PURE__ */ jsx5(PartContext.Provider, { value: context, children }) : null
|
|
3247
3259
|
] });
|
|
3248
3260
|
};
|
|
3249
3261
|
var ORIGIN = new Vector311();
|
|
@@ -3890,6 +3902,7 @@ function useGeometryResource(part) {
|
|
|
3890
3902
|
}
|
|
3891
3903
|
|
|
3892
3904
|
export {
|
|
3905
|
+
usePartContext,
|
|
3893
3906
|
sameDirection,
|
|
3894
3907
|
directionIndexOf,
|
|
3895
3908
|
groupByDirection,
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PartModel, a as PartMeshRefs } from '../normalize
|
|
2
|
-
export { E as EnginePart, b as EnginePartProps, M as MIN_KERNEL_VERSION, c as assertSupportedKernelVersion, n as normalizePartReport, s as smoothRegionNormals } from '../normalize
|
|
1
|
+
import { P as PartModel, a as PartMeshRefs } from '../normalize--FiXUhO4.js';
|
|
2
|
+
export { E as EnginePart, b as EnginePartProps, M as MIN_KERNEL_VERSION, c as assertSupportedKernelVersion, n as normalizePartReport, s as smoothRegionNormals } from '../normalize--FiXUhO4.js';
|
|
3
3
|
import { BufferGeometry } from 'three';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
package/dist/engine/index.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PartModel, d as PartPick, V as Vec3, R as RegionHighlight, e as ViewerTheme, S as SectionOptions, f as SectionState, g as PartModelRegion, T as TriangleRange,
|
|
2
|
-
export { A as AXES_PLANE_OFFSET, k as AXES_PLANE_SCALE, l as AxesPlane, B as BuildPickInput, C as CANDIDATE_WEIGHT, m as CAP_HATCH, D as DEFAULT_SECTION_NORMAL, o as DEFAULT_THEME, p as DIRECTION_COLORS, q as DISABLED_SECTION, E as EnginePart, r as FeatureHighlight, t as FocusOptions, H as HANDLE_PIXELS, u as HIGHLIGHT_COLORS, v as HIGHLIGHT_WEIGHT, w as HOVER_WEIGHT, x as HighlightLayers, K as KnownFeatureType, y as KnownShapeKind, N as NO_MODIFIERS, O as OUTLINE_SCALE, z as PICKED_SURFACE_LABEL, G as PREVIEW_SCALE, I as PartDisplay, J as PartMesh, L as PartMeshProps, a as PartMeshRefs, Q as PartObject, U as PickModifiers, W as PointerLocation, X as REGION_ATTRIBUTE, Y as RegionPaint, Z as SECTION_GIZMO_FRAME_SCALE, _ as SECTION_RENDER_ORDER, $ as SectionAnchor, a0 as SectionBounds, a1 as SectionPlacement, a2 as ShapeKind, a3 as SurfaceHit, a4 as applyHighlightLayers, a5 as axesPlanes, a6 as buildPick, a7 as buildRegionAttribute, a8 as buildRegionTexels, a9 as createPart, aa as directionColor, ab as dragPlane, ac as focusForPick, ad as hitUnderRay, n as normalizePartReport, ae as pickedStartDepth, af as resolveTheme, ag as sectionAnchor, ah as sectionBounds, ai as sectionConstant, aj as sectionDepth, ak as sectionDepthConstant, al as sectionDepthRange, am as sectionFromPick, an as sectionMeasurement, ao as sectionOffset, ap as sectionOptionsFromState, aq as sectionPlane, s as smoothRegionNormals, ar as surfaceUnderRay, as as themesEqual, at as viewDirection } from './normalize
|
|
1
|
+
import { P as PartModel, F as FeatureTag, d as PartPick, V as Vec3, R as RegionHighlight, e as ViewerTheme, S as SectionOptions, f as SectionState, g as PartModelRegion, T as TriangleRange, h as RegionIndex, i as PartModelFeature, j as FeatureType } from './normalize--FiXUhO4.js';
|
|
2
|
+
export { A as AXES_PLANE_OFFSET, k as AXES_PLANE_SCALE, l as AxesPlane, B as BuildPickInput, C as CANDIDATE_WEIGHT, m as CAP_HATCH, D as DEFAULT_SECTION_NORMAL, o as DEFAULT_THEME, p as DIRECTION_COLORS, q as DISABLED_SECTION, E as EnginePart, r as FeatureHighlight, t as FocusOptions, H as HANDLE_PIXELS, u as HIGHLIGHT_COLORS, v as HIGHLIGHT_WEIGHT, w as HOVER_WEIGHT, x as HighlightLayers, K as KnownFeatureType, y as KnownShapeKind, N as NO_MODIFIERS, O as OUTLINE_SCALE, z as PICKED_SURFACE_LABEL, G as PREVIEW_SCALE, I as PartDisplay, J as PartMesh, L as PartMeshProps, a as PartMeshRefs, Q as PartObject, U as PickModifiers, W as PointerLocation, X as REGION_ATTRIBUTE, Y as RegionPaint, Z as SECTION_GIZMO_FRAME_SCALE, _ as SECTION_RENDER_ORDER, $ as SectionAnchor, a0 as SectionBounds, a1 as SectionPlacement, a2 as ShapeKind, a3 as SurfaceHit, a4 as applyHighlightLayers, a5 as axesPlanes, a6 as buildPick, a7 as buildRegionAttribute, a8 as buildRegionTexels, a9 as createPart, aa as directionColor, ab as dragPlane, ac as focusForPick, ad as hitUnderRay, n as normalizePartReport, ae as pickedStartDepth, af as resolveTheme, ag as sectionAnchor, ah as sectionBounds, ai as sectionConstant, aj as sectionDepth, ak as sectionDepthConstant, al as sectionDepthRange, am as sectionFromPick, an as sectionMeasurement, ao as sectionOffset, ap as sectionOptionsFromState, aq as sectionPlane, s as smoothRegionNormals, ar as surfaceUnderRay, as as themesEqual, at as viewDirection } from './normalize--FiXUhO4.js';
|
|
3
3
|
import { BufferGeometry, Box3, CanvasTexture, Plane, Vector3, OrthographicCamera, PerspectiveCamera, Object3D, Matrix4, Vector2, Ray, ShaderMaterial, Texture, Color, MeshBasicMaterial, WebGLRenderTarget } from 'three';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode, PropsWithChildren, RefObject, CSSProperties } from 'react';
|
|
@@ -13,6 +13,49 @@ import CameraControls from 'camera-controls';
|
|
|
13
13
|
*/
|
|
14
14
|
declare function regionAdjacency(model: PartModel, geometry: BufferGeometry): Map<number, Set<number>>;
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* A feature's faces as plain triangles: what something placed on the part
|
|
18
|
+
* fits itself against, without needing three.js to read them.
|
|
19
|
+
*/
|
|
20
|
+
interface FeatureTriangles {
|
|
21
|
+
/** Nine numbers a triangle — its three corners, x, y, z each — in the geometry's coordinates. */
|
|
22
|
+
readonly positions: Float32Array;
|
|
23
|
+
/** Three a triangle: its unit normal, pointing out of the part. */
|
|
24
|
+
readonly normals: Float32Array;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Every triangle of a feature's faces, read out of the mesh through the
|
|
28
|
+
* region index.
|
|
29
|
+
*
|
|
30
|
+
* Each normal is the mesh's own where it has them — the average of the three
|
|
31
|
+
* corners' — because they say which side is outside whatever order a
|
|
32
|
+
* triangle's corners are wound in. A mesh without normals gives each triangle
|
|
33
|
+
* its winding's. A triangle with no area has no normal and is left out.
|
|
34
|
+
*
|
|
35
|
+
* Indexed and non-indexed meshes both read: triangle `t` is corners `3t` to
|
|
36
|
+
* `3t + 2` of the index where there is one, of the positions where there is
|
|
37
|
+
* not. Empty for a tag the part does not have, or a geometry with no positions.
|
|
38
|
+
*/
|
|
39
|
+
declare function featureTriangles(model: Pick<PartModel, 'regionIndex'>, geometry: BufferGeometry, tag: FeatureTag): FeatureTriangles;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The part an overlay is drawn on: its model and the mesh `<PartMesh>` draws.
|
|
43
|
+
*
|
|
44
|
+
* `<EnginePart>` loads its mesh itself, so a child of it has no other way to
|
|
45
|
+
* reach the geometry — and an overlay placed on the part, such as
|
|
46
|
+
* `<ToolMarks>` at a feature's faces, needs the triangles it is drawn against.
|
|
47
|
+
*/
|
|
48
|
+
interface PartContextValue {
|
|
49
|
+
readonly model: PartModel;
|
|
50
|
+
/** In the coordinates the part is drawn in: the caller's, whatever it did to centre it. */
|
|
51
|
+
readonly geometry: BufferGeometry;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The part this is drawn inside: a child of `<PartMesh>` or `<EnginePart>`.
|
|
55
|
+
* Throws anywhere else, as `useViewerControls` does outside `<Viewer>`.
|
|
56
|
+
*/
|
|
57
|
+
declare const usePartContext: () => PartContextValue;
|
|
58
|
+
|
|
16
59
|
interface HoverCardProps {
|
|
17
60
|
/** The current `onHover` pick, or `null` after the pointer leaves the part. */
|
|
18
61
|
pick: PartPick | null;
|
|
@@ -44,7 +87,10 @@ interface ViewerToolbarControls {
|
|
|
44
87
|
axes?: ViewerToolbarControl;
|
|
45
88
|
grid?: ViewerToolbarControl;
|
|
46
89
|
banana?: ViewerToolbarControl;
|
|
90
|
+
/** Tools drawn on the part: see `<ToolMarks>`. */
|
|
91
|
+
tools?: ViewerToolbarControl;
|
|
47
92
|
directions?: ViewerToolbarControl;
|
|
93
|
+
dfm?: ViewerToolbarControl;
|
|
48
94
|
hover?: ViewerToolbarControl;
|
|
49
95
|
focus?: ViewerToolbarControl;
|
|
50
96
|
wireframe?: ViewerToolbarControl;
|
|
@@ -84,7 +130,9 @@ declare const ViewerToolbar: (({ className, children }: ViewerToolbarProps) => r
|
|
|
84
130
|
AxesButton: () => react.JSX.Element;
|
|
85
131
|
GridButton: () => react.JSX.Element;
|
|
86
132
|
BananaButton: () => react.JSX.Element;
|
|
133
|
+
ToolsButton: () => react.JSX.Element;
|
|
87
134
|
DirectionsButton: () => react.JSX.Element;
|
|
135
|
+
DfmButton: () => react.JSX.Element;
|
|
88
136
|
HoverButton: () => react.JSX.Element;
|
|
89
137
|
FocusButton: () => react.JSX.Element;
|
|
90
138
|
WireframeButton: () => react.JSX.Element;
|
|
@@ -947,6 +995,81 @@ interface MeasureToolProps {
|
|
|
947
995
|
*/
|
|
948
996
|
declare const MeasureTool: ({ mode, measurements, onChange, showDeltas, format, labelClassName, theme, }: MeasureToolProps) => react.JSX.Element | null;
|
|
949
997
|
|
|
998
|
+
/**
|
|
999
|
+
* A cutting tool drawn on the part: an end mill standing at a place, up an
|
|
1000
|
+
* axis, to scale. What it stands for — the widest tool a pocket admits, the
|
|
1001
|
+
* tool an operation uses — is the caller's; this is only where and how big.
|
|
1002
|
+
*/
|
|
1003
|
+
interface ToolMark {
|
|
1004
|
+
/** The centre of the tool's bottom, in the coordinates the part is drawn in. */
|
|
1005
|
+
readonly base: Vec3;
|
|
1006
|
+
/** Up the tool, from its tip to its shank. Need not be unit length. */
|
|
1007
|
+
readonly axis: Vec3;
|
|
1008
|
+
readonly diameter: number;
|
|
1009
|
+
/** How tall the drawn tool stands from its tip. */
|
|
1010
|
+
readonly height: number;
|
|
1011
|
+
/**
|
|
1012
|
+
* The radius on the tool's corner: 0 for a flat end mill, half the diameter
|
|
1013
|
+
* for a ball, anything between for a bull nose. Held to that range.
|
|
1014
|
+
*/
|
|
1015
|
+
readonly cornerRadius?: number;
|
|
1016
|
+
/**
|
|
1017
|
+
* Which way the dimension across the tool's top runs: toward what it
|
|
1018
|
+
* touches, say. Any direction square to the axis when left out or along it.
|
|
1019
|
+
*/
|
|
1020
|
+
readonly across?: Vec3;
|
|
1021
|
+
/**
|
|
1022
|
+
* The tool's own side, to turn about its axis in place of the end mill
|
|
1023
|
+
* `diameter` and `cornerRadius` make: radius out from the axis and height
|
|
1024
|
+
* above the tip, from the tip up — `@toolpath/tool-drawing`'s outline of a
|
|
1025
|
+
* drill, a chamfer mill, a tool in its holder. `diameter` and `height` still
|
|
1026
|
+
* place the rims and the dimension.
|
|
1027
|
+
*/
|
|
1028
|
+
readonly profile?: readonly ToolProfilePoint[];
|
|
1029
|
+
/** Written on the dimension: `⌀ 3.200 mm`. */
|
|
1030
|
+
readonly label?: string;
|
|
1031
|
+
/** After the label, quieter: `bull nose R 0.5 · 3 places`. */
|
|
1032
|
+
readonly note?: string;
|
|
1033
|
+
}
|
|
1034
|
+
/** A point on a tool's side: radius out from its axis and height above its tip. */
|
|
1035
|
+
interface ToolProfilePoint {
|
|
1036
|
+
readonly r: number;
|
|
1037
|
+
readonly z: number;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
interface ToolMarksProps {
|
|
1041
|
+
/** The tools to draw, in the coordinates the part is drawn in. */
|
|
1042
|
+
marks: readonly ToolMark[];
|
|
1043
|
+
/** Draws nothing while false, and keeps its place in the scene. On by default. */
|
|
1044
|
+
visible?: boolean;
|
|
1045
|
+
/**
|
|
1046
|
+
* Added to every label's `className`, beside {@link MEASURE_LABEL_CLASS} —
|
|
1047
|
+
* a Tailwind utility list, or a CSS module's class.
|
|
1048
|
+
*/
|
|
1049
|
+
labelClassName?: string;
|
|
1050
|
+
/** `measure` colours the rims and the dimension, as it does the measure tool's lines. */
|
|
1051
|
+
theme?: Partial<ViewerTheme>;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Cutting tools drawn on the part, each to scale where it stands: a
|
|
1055
|
+
* see-through end mill — flat, bull nose or ball — or any tool turned from its
|
|
1056
|
+
* `profile`, rimmed at its bottom and top, with a dimension across its top and
|
|
1057
|
+
* a label on it. Mount it inside
|
|
1058
|
+
* `<Viewer>`, beside or inside the part.
|
|
1059
|
+
*
|
|
1060
|
+
* What a tool stands for is the caller's. A DFM panel stands the widest tool
|
|
1061
|
+
* a pocket admits in its tightest place; a plan could show the tool an
|
|
1062
|
+
* operation uses. Nothing here reads a datasheet.
|
|
1063
|
+
*
|
|
1064
|
+
* Drawn as the measure tool draws: the lines show through the part, in the
|
|
1065
|
+
* theme's `measure` colour, and the labels are unstyled DOM elements with the
|
|
1066
|
+
* {@link MEASURE_LABEL_CLASS} class and `data-measure-label="tool"`, the
|
|
1067
|
+
* label's text in a `data-measure-value` span and its note in a
|
|
1068
|
+
* `data-measure-note` one. The marks take no pointer events and are left out
|
|
1069
|
+
* of framing, so fitting the view fits the part.
|
|
1070
|
+
*/
|
|
1071
|
+
declare const ToolMarks: ({ marks, visible, labelClassName, theme }: ToolMarksProps) => react.JSX.Element;
|
|
1072
|
+
|
|
950
1073
|
/**
|
|
951
1074
|
* The cut a viewer holds for itself, when nobody else is holding it.
|
|
952
1075
|
*
|
|
@@ -1854,4 +1977,4 @@ declare const ORBIT_TARGET_FADE_MS = 1000;
|
|
|
1854
1977
|
*/
|
|
1855
1978
|
declare function orbitTargetOpacity(sinceHold: number, fade?: number): number;
|
|
1856
1979
|
|
|
1857
|
-
export { ANGLE_ARC_FRACTION, ANGLE_ARC_SEGMENTS, AXIS_COLORS, type AngleMeasurement, type ArrowPlacement, Axes, type AxesProps, type Axis, type AxisLock, BANANA_GAP, BANANA_MODEL_URL, Banana, type BananaProps, type BoxStockFigure, type BoxStockInput, type BoxStockPreview, CAD_CAMERA_UP, CHAMFER, CONTROL_SCHEME_OPTIONS, CadCameraControls, type CadCameraControlsProps, type CameraLimits, type CapMaterial, type CapUniforms, type ControlScheme, type ControlSchemeOption, type CubeZone, type CylinderStockFigure, type CylinderStockInput, type CylinderStockPreview, DEFAULT_FIT_MARGIN, DELTA_DASH_PIXELS, DOUBLE_TAP_MS, type DeltaLeg, DirectionArrows, type DirectionArrowsProps, type DirectionGroup, type DistanceMeasurement, type DoubleTapPoint, type DoubleTapTracker, EXCLUDE_FROM_FRAME, ExtendedCameraControls, type ExtendedCameraControlsOptions, FEATURE_TYPE_RANKS, FeatureTag, FeatureType, Grid, type GridProps, type GridSpec, HoverCard, type HoverCardProps, MAX_FRAME_RATIO, MEASURE_LABEL_CLASS, MEASURE_LINE_PIXELS, MEASURE_MARKER_PIXELS, MEASURE_RENDER_ORDER, MIN_FRAME_RATIO, type MeasureLabelKind, type MeasureMode, MeasureTool, type MeasureToolProps, type Measurement, type NamedDirection, ORBIT_TARGET_COLOR, ORBIT_TARGET_FADE_MS, ORBIT_TARGET_FLASH_MS, ORBIT_TARGET_PIXELS, ORBIT_TARGET_RING_COLOR, ORBIT_TARGET_RING_OPACITY, ORBIT_TARGET_RING_PIXELS, ORBIT_TARGET_RING_WIDTH, PERSPECTIVE_FOV, POINTS_PER_MEASUREMENT, PartModel, PartModelFeature, PartModelRegion, PartPick, PartReportFormatError, type Projection, type RankingContext, RegionHighlight, RegionIndex, type Retarget, type RetargetPose, SNAP_MARKER_PIXELS, SNAP_PIXELS, type SceneBounds, SectionOptions, type SectionSample, SectionState, type SectionStore, SectionTool, type SectionToolProps, SectionView, type Snap, type SnapEdges, type SnapHit, type SnapKind, Stock, type StockAllowance, type StockAppearanceProps, type StockPosition, type StockProps, type StockSource, type SurfaceOf, TAP_SLOP, type TapPoint, type TapTracker, TriangleRange, UnsupportedKernelVersionError, VIEW_NAMES, VIEW_SIGNS, Vec3, ViewCube, type ViewCubeProps, type ViewKind, type ViewName, Viewer, type ViewerCamera, type ViewerControls, type ViewerHandle, type ViewerProps, ViewerTheme, ViewerToolbar, type ViewerToolbarControl, type ViewerToolbarControls, type ViewerToolbarControlsProps, type ViewerToolbarProps, ViewerToolbarProvider, type ViewerView, type ViewportSize, adaptedUp, angleArc, angleArcRadius, angleAt, applyCapTheme, applyProjection, arrowPlacement, aspectRatio, bananaFrameBounds, bananaPosition, bestOwner, boundsFromBox, boxStockBounds, buildRegionIndex, cadViewDirections, cameraLimits, capHit, clipSegments, contentBounds, createCapMaterial, createMaskMaterial, createMaskTarget, createSectionStore, createStencilMaterials, cubeOutlineGeometry, cubeZones, currentViewDirection, cycleOwner, defaultBounds, deltaBetween, deltaLegs, directionHighlights, directionIndexOf, directionLabel, distanceBetween, excludedFromFrame, featureTypeRank, fitDistance, fixedBoxStockBounds, formatDegrees, formatMillimetres, gridGeometry, gridSpec, groupByDirection, labelGeometry, labelTexture, lockToAxis, measurementFromPoints, measurementLabel, measurementLabelAnchor, midpoint, movedFar, nextMeasurementId, orbitTargetOpacity, orthographicHalfHeight, panelGeometry, perspectiveFitDistance, pointInContour, rankOwners, regionAdjacency, regionEdgesGeometry, regionNormals, resolveSectionPlane, retargetPose, sameDirection, sampleSection, screenLength, screenPoint, sectionContour, snapAt, squaredUp, startPosition, targetBoundary, trackDoubleTaps, trackTaps, useContentBox, useRetarget, useSectionStore, useTapGuard, useViewerControls, useViewerToolbar, viewKind, viewUp, viewVector, visualSurfaces };
|
|
1980
|
+
export { ANGLE_ARC_FRACTION, ANGLE_ARC_SEGMENTS, AXIS_COLORS, type AngleMeasurement, type ArrowPlacement, Axes, type AxesProps, type Axis, type AxisLock, BANANA_GAP, BANANA_MODEL_URL, Banana, type BananaProps, type BoxStockFigure, type BoxStockInput, type BoxStockPreview, CAD_CAMERA_UP, CHAMFER, CONTROL_SCHEME_OPTIONS, CadCameraControls, type CadCameraControlsProps, type CameraLimits, type CapMaterial, type CapUniforms, type ControlScheme, type ControlSchemeOption, type CubeZone, type CylinderStockFigure, type CylinderStockInput, type CylinderStockPreview, DEFAULT_FIT_MARGIN, DELTA_DASH_PIXELS, DOUBLE_TAP_MS, type DeltaLeg, DirectionArrows, type DirectionArrowsProps, type DirectionGroup, type DistanceMeasurement, type DoubleTapPoint, type DoubleTapTracker, EXCLUDE_FROM_FRAME, ExtendedCameraControls, type ExtendedCameraControlsOptions, FEATURE_TYPE_RANKS, FeatureTag, type FeatureTriangles, FeatureType, Grid, type GridProps, type GridSpec, HoverCard, type HoverCardProps, MAX_FRAME_RATIO, MEASURE_LABEL_CLASS, MEASURE_LINE_PIXELS, MEASURE_MARKER_PIXELS, MEASURE_RENDER_ORDER, MIN_FRAME_RATIO, type MeasureLabelKind, type MeasureMode, MeasureTool, type MeasureToolProps, type Measurement, type NamedDirection, ORBIT_TARGET_COLOR, ORBIT_TARGET_FADE_MS, ORBIT_TARGET_FLASH_MS, ORBIT_TARGET_PIXELS, ORBIT_TARGET_RING_COLOR, ORBIT_TARGET_RING_OPACITY, ORBIT_TARGET_RING_PIXELS, ORBIT_TARGET_RING_WIDTH, PERSPECTIVE_FOV, POINTS_PER_MEASUREMENT, type PartContextValue, PartModel, PartModelFeature, PartModelRegion, PartPick, PartReportFormatError, type Projection, type RankingContext, RegionHighlight, RegionIndex, type Retarget, type RetargetPose, SNAP_MARKER_PIXELS, SNAP_PIXELS, type SceneBounds, SectionOptions, type SectionSample, SectionState, type SectionStore, SectionTool, type SectionToolProps, SectionView, type Snap, type SnapEdges, type SnapHit, type SnapKind, Stock, type StockAllowance, type StockAppearanceProps, type StockPosition, type StockProps, type StockSource, type SurfaceOf, TAP_SLOP, type TapPoint, type TapTracker, type ToolMark, ToolMarks, type ToolMarksProps, type ToolProfilePoint, TriangleRange, UnsupportedKernelVersionError, VIEW_NAMES, VIEW_SIGNS, Vec3, ViewCube, type ViewCubeProps, type ViewKind, type ViewName, Viewer, type ViewerCamera, type ViewerControls, type ViewerHandle, type ViewerProps, ViewerTheme, ViewerToolbar, type ViewerToolbarControl, type ViewerToolbarControls, type ViewerToolbarControlsProps, type ViewerToolbarProps, ViewerToolbarProvider, type ViewerView, type ViewportSize, adaptedUp, angleArc, angleArcRadius, angleAt, applyCapTheme, applyProjection, arrowPlacement, aspectRatio, bananaFrameBounds, bananaPosition, bestOwner, boundsFromBox, boxStockBounds, buildRegionIndex, cadViewDirections, cameraLimits, capHit, clipSegments, contentBounds, createCapMaterial, createMaskMaterial, createMaskTarget, createSectionStore, createStencilMaterials, cubeOutlineGeometry, cubeZones, currentViewDirection, cycleOwner, defaultBounds, deltaBetween, deltaLegs, directionHighlights, directionIndexOf, directionLabel, distanceBetween, excludedFromFrame, featureTriangles, featureTypeRank, fitDistance, fixedBoxStockBounds, formatDegrees, formatMillimetres, gridGeometry, gridSpec, groupByDirection, labelGeometry, labelTexture, lockToAxis, measurementFromPoints, measurementLabel, measurementLabelAnchor, midpoint, movedFar, nextMeasurementId, orbitTargetOpacity, orthographicHalfHeight, panelGeometry, perspectiveFitDistance, pointInContour, rankOwners, regionAdjacency, regionEdgesGeometry, regionNormals, resolveSectionPlane, retargetPose, sameDirection, sampleSection, screenLength, screenPoint, sectionContour, snapAt, squaredUp, startPosition, targetBoundary, trackDoubleTaps, trackTaps, useContentBox, usePartContext, useRetarget, useSectionStore, useTapGuard, useViewerControls, useViewerToolbar, viewKind, viewUp, viewVector, visualSurfaces };
|
package/dist/index.js
CHANGED
|
@@ -152,6 +152,7 @@ import {
|
|
|
152
152
|
trackDoubleTaps,
|
|
153
153
|
trackTaps,
|
|
154
154
|
useContentBox,
|
|
155
|
+
usePartContext,
|
|
155
156
|
useRetarget,
|
|
156
157
|
useSectionStore,
|
|
157
158
|
useTapGuard,
|
|
@@ -161,7 +162,50 @@ import {
|
|
|
161
162
|
viewUp,
|
|
162
163
|
viewVector,
|
|
163
164
|
visualSurfaces
|
|
164
|
-
} from "./chunk-
|
|
165
|
+
} from "./chunk-WTTOUG4P.js";
|
|
166
|
+
|
|
167
|
+
// src/render/feature-triangles.ts
|
|
168
|
+
var EMPTY = { positions: new Float32Array(), normals: new Float32Array() };
|
|
169
|
+
function featureTriangles(model, geometry, tag) {
|
|
170
|
+
const position = geometry.getAttribute("position");
|
|
171
|
+
if (!position) return EMPTY;
|
|
172
|
+
const normal = geometry.getAttribute("normal");
|
|
173
|
+
const index = geometry.getIndex();
|
|
174
|
+
const vertex = (corner) => index ? index.getX(corner) : corner;
|
|
175
|
+
const triangleCount = Math.floor((index ? index.count : position.count) / 3);
|
|
176
|
+
const positions = [];
|
|
177
|
+
const normals = [];
|
|
178
|
+
for (const region of new Set(model.regionIndex.regionsForFeature(tag))) {
|
|
179
|
+
const range = model.regionIndex.rangeForRegion(region);
|
|
180
|
+
if (!range) continue;
|
|
181
|
+
for (let triangle = range.start; triangle < Math.min(range.end, triangleCount); triangle++) {
|
|
182
|
+
const corners = [vertex(triangle * 3), vertex(triangle * 3 + 1), vertex(triangle * 3 + 2)];
|
|
183
|
+
const at = corners.map((corner) => [
|
|
184
|
+
position.getX(corner),
|
|
185
|
+
position.getY(corner),
|
|
186
|
+
position.getZ(corner)
|
|
187
|
+
]);
|
|
188
|
+
const out = normal ? corners.reduce(
|
|
189
|
+
(sum, corner) => [
|
|
190
|
+
sum[0] + normal.getX(corner),
|
|
191
|
+
sum[1] + normal.getY(corner),
|
|
192
|
+
sum[2] + normal.getZ(corner)
|
|
193
|
+
],
|
|
194
|
+
[0, 0, 0]
|
|
195
|
+
) : winding(at);
|
|
196
|
+
const length = Math.hypot(out[0], out[1], out[2]);
|
|
197
|
+
if (length === 0) continue;
|
|
198
|
+
positions.push(...at[0], ...at[1], ...at[2]);
|
|
199
|
+
normals.push(out[0] / length, out[1] / length, out[2] / length);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return { positions: new Float32Array(positions), normals: new Float32Array(normals) };
|
|
203
|
+
}
|
|
204
|
+
var winding = ([a, b, c]) => {
|
|
205
|
+
const u = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
|
206
|
+
const v = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
|
|
207
|
+
return [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]];
|
|
208
|
+
};
|
|
165
209
|
|
|
166
210
|
// src/hover-card.tsx
|
|
167
211
|
import { useEffect, useState } from "react";
|
|
@@ -222,7 +266,9 @@ var StockIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */
|
|
|
222
266
|
var AxesIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M5 19V3m0 16h16M5 19l10-10M2 6l3-3 3 3m10 10 3 3-3 3M11 9h4v4" }) });
|
|
223
267
|
var GridIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M3 8l9-5 9 5-9 5zM3 8v8l9 5 9-5V8M12 13v8M7.5 5.5v8M16.5 5.5v8" }) });
|
|
224
268
|
var BananaIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { viewBox: "0 0 576 512", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M284.2 245.6c12.99 6.929 25.35 15.14 36.08 25.8L334.5 285.6l65.75-23.47c14.75-5.265 30.18-7.849 45.81-8.389c1.154-10.73 1.764-21.38 1.764-31.87c0-118.5-81.33-221.9-119.7-221.9c-21.01 0-40.91 17.04-40.91 39.25c0 16.18 16.74 41.9 16.74 103C303.1 170.1 300.6 203.1 284.2 245.6zM575.1 389.6c0-3.687-.8637-7.429-2.687-10.93l-15.12-29.11c-21.05-40.53-63.08-64.51-106.9-64.51c-13.43 0-27.02 2.252-40.22 6.969l-84.84 30.27l-28.59-28.41C274.4 270.9 243.7 258.1 212.8 258.1c-23.72 0-47.57 6.97-68.29 21.2L106.3 306.4c-6.732 4.631-10.35 12.07-10.35 19.63c0 14.93 12.7 23.87 24.04 23.87c4.695 0 9.443-1.376 13.61-4.26l38.13-26.23c12.43-8.525 26.71-12.69 40.91-12.69c10.64 0 21.24 2.339 30.97 6.934c-50.62 62.23-128.3 99.85-211.4 99.85C14.42 413.5 0 427.8 0 445.5v31.38c0 17.68 14.66 32.02 32.46 32.02l28.98.0009c14.15 0 34.69 1.098 59.07 1.098c93.51 0 243.4-16.15 304.8-172.4c9.021-3.22 17.95-4.712 26.53-4.712c27.65 0 51.7 15.49 63.7 38.55l15.12 29.11c3.484 6.723 11.74 12.98 21.41 12.98C564.1 413.6 575.1 403.8 575.1 389.6z" }) });
|
|
269
|
+
var ToolsIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M9 2h6v7H9zM9.5 9v9.5l2.5 3.5 2.5-3.5V9M9.5 12l5 2.5M9.5 15.5l5 2.5" }) });
|
|
225
270
|
var DirectionsIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M7 3v18m-4-4 4 4 4-4M17 21V3m-4 4 4-4 4 4" }) });
|
|
271
|
+
var DfmIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M8.3 3h7.4L21 8.3v7.4L15.7 21H8.3L3 15.7V8.3zM12 7.5v5.5m0 3.5v.01" }) });
|
|
226
272
|
var HoverIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 4h16v12H9l-5 4zm4 5h8m-8 3h5" }) });
|
|
227
273
|
var FocusIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 4h16v16H4zM8 8h8v8H8zM2 12h4m12 0h4M12 2v4m0 12v4" }) });
|
|
228
274
|
var WireframeIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 7l8-4 8 4v10l-8 4-8-4zM4 7l8 4 8-4M12 11v10M4 17l8-4 8 4M12 3v10" }) });
|
|
@@ -236,7 +282,9 @@ var ICONS = {
|
|
|
236
282
|
axes: AxesIcon,
|
|
237
283
|
grid: GridIcon,
|
|
238
284
|
banana: BananaIcon,
|
|
285
|
+
tools: ToolsIcon,
|
|
239
286
|
directions: DirectionsIcon,
|
|
287
|
+
dfm: DfmIcon,
|
|
240
288
|
hover: HoverIcon,
|
|
241
289
|
focus: FocusIcon,
|
|
242
290
|
wireframe: WireframeIcon,
|
|
@@ -315,6 +363,14 @@ var BananaButton = () => /* @__PURE__ */ jsx3(
|
|
|
315
363
|
label: (pressed) => pressed ? "Banana for scale (on)" : "Banana for scale"
|
|
316
364
|
}
|
|
317
365
|
);
|
|
366
|
+
var ToolsButton = () => /* @__PURE__ */ jsx3(
|
|
367
|
+
ToolbarButton,
|
|
368
|
+
{
|
|
369
|
+
action: "tools",
|
|
370
|
+
icon: "tools",
|
|
371
|
+
label: (pressed) => pressed ? "Hide tools on the part" : "Show tools on the part"
|
|
372
|
+
}
|
|
373
|
+
);
|
|
318
374
|
var DirectionsButton = () => /* @__PURE__ */ jsx3(
|
|
319
375
|
ToolbarButton,
|
|
320
376
|
{
|
|
@@ -323,6 +379,14 @@ var DirectionsButton = () => /* @__PURE__ */ jsx3(
|
|
|
323
379
|
label: () => "Highlight faces by direction"
|
|
324
380
|
}
|
|
325
381
|
);
|
|
382
|
+
var DfmButton = () => /* @__PURE__ */ jsx3(
|
|
383
|
+
ToolbarButton,
|
|
384
|
+
{
|
|
385
|
+
action: "dfm",
|
|
386
|
+
icon: "dfm",
|
|
387
|
+
label: (pressed) => pressed ? "Hide DFM flags" : "Show DFM flags"
|
|
388
|
+
}
|
|
389
|
+
);
|
|
326
390
|
var HoverButton = () => /* @__PURE__ */ jsx3(
|
|
327
391
|
ToolbarButton,
|
|
328
392
|
{
|
|
@@ -376,10 +440,12 @@ var DefaultControls = () => {
|
|
|
376
440
|
controls.stock ? /* @__PURE__ */ jsx3(StockButton, {}, "stock") : null,
|
|
377
441
|
controls.axes ? /* @__PURE__ */ jsx3(AxesButton, {}, "axes") : null,
|
|
378
442
|
controls.grid ? /* @__PURE__ */ jsx3(GridButton, {}, "grid") : null,
|
|
379
|
-
controls.banana ? /* @__PURE__ */ jsx3(BananaButton, {}, "banana") : null
|
|
443
|
+
controls.banana ? /* @__PURE__ */ jsx3(BananaButton, {}, "banana") : null,
|
|
444
|
+
controls.tools ? /* @__PURE__ */ jsx3(ToolsButton, {}, "tools") : null
|
|
380
445
|
].filter(Boolean);
|
|
381
446
|
const analysis = [
|
|
382
447
|
controls.directions ? /* @__PURE__ */ jsx3(DirectionsButton, {}, "directions") : null,
|
|
448
|
+
controls.dfm ? /* @__PURE__ */ jsx3(DfmButton, {}, "dfm") : null,
|
|
383
449
|
controls.hover ? /* @__PURE__ */ jsx3(HoverButton, {}, "hover") : null,
|
|
384
450
|
controls.focus ? /* @__PURE__ */ jsx3(FocusButton, {}, "focus") : null,
|
|
385
451
|
controls.wireframe ? /* @__PURE__ */ jsx3(WireframeButton, {}, "wireframe") : null,
|
|
@@ -417,7 +483,9 @@ var ViewerToolbar = Object.assign(ViewerToolbarRoot, {
|
|
|
417
483
|
AxesButton,
|
|
418
484
|
GridButton,
|
|
419
485
|
BananaButton,
|
|
486
|
+
ToolsButton,
|
|
420
487
|
DirectionsButton,
|
|
488
|
+
DfmButton,
|
|
421
489
|
HoverButton,
|
|
422
490
|
FocusButton,
|
|
423
491
|
WireframeButton,
|
|
@@ -2168,6 +2236,145 @@ function className(extra) {
|
|
|
2168
2236
|
return extra ? `${MEASURE_LABEL_CLASS} ${extra}` : MEASURE_LABEL_CLASS;
|
|
2169
2237
|
}
|
|
2170
2238
|
|
|
2239
|
+
// src/tool-marks.tsx
|
|
2240
|
+
import { Html as Html2, Line as Line2 } from "@react-three/drei";
|
|
2241
|
+
import { useMemo as useMemo7 } from "react";
|
|
2242
|
+
import { DoubleSide as DoubleSide2 } from "three";
|
|
2243
|
+
|
|
2244
|
+
// src/render/tool-marks.ts
|
|
2245
|
+
import { Quaternion as Quaternion4, Vector2 as Vector23, Vector3 as Vector38 } from "three";
|
|
2246
|
+
var TOOL_CORNER_STEPS = 12;
|
|
2247
|
+
var TOOL_ROUND = 64;
|
|
2248
|
+
function toolProfile(radius, corner, height) {
|
|
2249
|
+
const rounded = Math.min(Math.max(corner, 0), radius);
|
|
2250
|
+
const flat = radius - rounded;
|
|
2251
|
+
const points = [new Vector23(0, 0)];
|
|
2252
|
+
if (rounded <= 0) {
|
|
2253
|
+
points.push(new Vector23(radius, 0));
|
|
2254
|
+
} else {
|
|
2255
|
+
for (let step = 0; step <= TOOL_CORNER_STEPS; step++) {
|
|
2256
|
+
const angle = step / TOOL_CORNER_STEPS * (Math.PI / 2);
|
|
2257
|
+
points.push(
|
|
2258
|
+
new Vector23(flat + Math.sin(angle) * rounded, rounded - Math.cos(angle) * rounded)
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
points.push(new Vector23(radius, Math.max(height, rounded)));
|
|
2263
|
+
return points;
|
|
2264
|
+
}
|
|
2265
|
+
var UP = new Vector38(0, 1, 0);
|
|
2266
|
+
var AXES = [new Vector38(1, 0, 0), new Vector38(0, 1, 0), new Vector38(0, 0, 1)];
|
|
2267
|
+
var toVector = ({ x, y, z }) => new Vector38(x, y, z);
|
|
2268
|
+
var squareTo = (w, along) => {
|
|
2269
|
+
const wanted = along ? toVector(along) : null;
|
|
2270
|
+
const flat = wanted?.clone().addScaledVector(w, -wanted.dot(w));
|
|
2271
|
+
if (flat && flat.lengthSq() > 1e-12) return flat.normalize();
|
|
2272
|
+
const least = AXES.reduce(
|
|
2273
|
+
(best, axis) => Math.abs(axis.dot(w)) < Math.abs(best.dot(w)) ? axis : best
|
|
2274
|
+
);
|
|
2275
|
+
return least.clone().addScaledVector(w, -least.dot(w)).normalize();
|
|
2276
|
+
};
|
|
2277
|
+
var circle = (centre, u, v, radius) => Array.from({ length: TOOL_ROUND + 1 }, (_, step) => {
|
|
2278
|
+
const angle = step / TOOL_ROUND * Math.PI * 2;
|
|
2279
|
+
return centre.clone().addScaledVector(u, Math.cos(angle) * radius).addScaledVector(v, Math.sin(angle) * radius);
|
|
2280
|
+
});
|
|
2281
|
+
var tickLength = (diameter) => Math.min(Math.max(diameter * 0.15, 0.3), 3);
|
|
2282
|
+
function toolMarkShape(mark) {
|
|
2283
|
+
const axis = toVector(mark.axis);
|
|
2284
|
+
if (!(mark.diameter > 0) || axis.lengthSq() === 0) return null;
|
|
2285
|
+
const w = axis.normalize();
|
|
2286
|
+
const u = squareTo(w, mark.across);
|
|
2287
|
+
const v = new Vector38().crossVectors(w, u);
|
|
2288
|
+
const radius = mark.diameter / 2;
|
|
2289
|
+
const corner = Math.min(Math.max(mark.cornerRadius ?? 0, 0), radius);
|
|
2290
|
+
const height = Math.max(mark.height, corner);
|
|
2291
|
+
const base = toVector(mark.base);
|
|
2292
|
+
const top = base.clone().addScaledVector(w, height);
|
|
2293
|
+
const dimension = [
|
|
2294
|
+
top.clone().addScaledVector(u, radius),
|
|
2295
|
+
top.clone().addScaledVector(u, -radius)
|
|
2296
|
+
];
|
|
2297
|
+
const half = tickLength(mark.diameter) / 2;
|
|
2298
|
+
const tick = (end) => [
|
|
2299
|
+
end.clone().addScaledVector(w, -half),
|
|
2300
|
+
end.clone().addScaledVector(w, half)
|
|
2301
|
+
];
|
|
2302
|
+
return {
|
|
2303
|
+
base,
|
|
2304
|
+
turn: new Quaternion4().setFromUnitVectors(UP, w),
|
|
2305
|
+
profile: mark.profile ? mark.profile.map(({ r, z }) => new Vector23(r, z)) : toolProfile(radius, corner, height),
|
|
2306
|
+
rims: [
|
|
2307
|
+
...radius - corner > 1e-9 ? [circle(base, u, v, radius - corner)] : [],
|
|
2308
|
+
circle(top, u, v, radius)
|
|
2309
|
+
],
|
|
2310
|
+
dimension,
|
|
2311
|
+
ticks: [tick(dimension[0]), tick(dimension[1])],
|
|
2312
|
+
labelAt: top
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
// src/tool-marks.tsx
|
|
2317
|
+
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2318
|
+
var BODY = { color: 16317180, opacity: 0.32 };
|
|
2319
|
+
var NO_POINTER2 = { pointerEvents: "none" };
|
|
2320
|
+
var ignoreRay = () => void 0;
|
|
2321
|
+
var ToolMarks = ({ marks, visible = true, labelClassName, theme }) => {
|
|
2322
|
+
const color = resolveTheme(theme).measure;
|
|
2323
|
+
const shapes = useMemo7(
|
|
2324
|
+
() => marks.flatMap((mark) => {
|
|
2325
|
+
const shape = toolMarkShape(mark);
|
|
2326
|
+
return shape ? [{ mark, shape }] : [];
|
|
2327
|
+
}),
|
|
2328
|
+
[marks]
|
|
2329
|
+
);
|
|
2330
|
+
const label = labelClassName ? `${MEASURE_LABEL_CLASS} ${labelClassName}` : MEASURE_LABEL_CLASS;
|
|
2331
|
+
return /* @__PURE__ */ jsx10("group", { visible, userData: { [EXCLUDE_FROM_FRAME]: true }, children: shapes.map(({ mark, shape }, index) => /* @__PURE__ */ jsxs6("group", { children: [
|
|
2332
|
+
/* @__PURE__ */ jsx10(ToolBody, { shape }),
|
|
2333
|
+
[...shape.rims, shape.dimension, ...shape.ticks].map((points, line) => /* @__PURE__ */ jsx10(
|
|
2334
|
+
Line2,
|
|
2335
|
+
{
|
|
2336
|
+
points,
|
|
2337
|
+
color,
|
|
2338
|
+
lineWidth: MEASURE_LINE_PIXELS.line,
|
|
2339
|
+
depthTest: false,
|
|
2340
|
+
depthWrite: false,
|
|
2341
|
+
renderOrder: MEASURE_RENDER_ORDER,
|
|
2342
|
+
raycast: ignoreRay
|
|
2343
|
+
},
|
|
2344
|
+
line
|
|
2345
|
+
)),
|
|
2346
|
+
mark.label && visible ? /* @__PURE__ */ jsx10(Html2, { position: shape.labelAt, center: true, zIndexRange: [0, 0], style: NO_POINTER2, children: /* @__PURE__ */ jsxs6("div", { className: label, "data-measure-label": "tool", children: [
|
|
2347
|
+
/* @__PURE__ */ jsx10("span", { "data-measure-value": true, children: mark.label }),
|
|
2348
|
+
mark.note ? /* @__PURE__ */ jsxs6("span", { "data-measure-note": true, children: [
|
|
2349
|
+
" ",
|
|
2350
|
+
mark.note
|
|
2351
|
+
] }) : null
|
|
2352
|
+
] }) }) : null
|
|
2353
|
+
] }, index)) });
|
|
2354
|
+
};
|
|
2355
|
+
var ToolBody = ({ shape }) => /* @__PURE__ */ jsxs6(
|
|
2356
|
+
"mesh",
|
|
2357
|
+
{
|
|
2358
|
+
position: shape.base,
|
|
2359
|
+
quaternion: shape.turn,
|
|
2360
|
+
raycast: ignoreRay,
|
|
2361
|
+
renderOrder: MEASURE_RENDER_ORDER - 1,
|
|
2362
|
+
children: [
|
|
2363
|
+
/* @__PURE__ */ jsx10("latheGeometry", { args: [shape.profile, 64] }),
|
|
2364
|
+
/* @__PURE__ */ jsx10(
|
|
2365
|
+
"meshBasicMaterial",
|
|
2366
|
+
{
|
|
2367
|
+
color: BODY.color,
|
|
2368
|
+
transparent: true,
|
|
2369
|
+
opacity: BODY.opacity,
|
|
2370
|
+
depthWrite: false,
|
|
2371
|
+
side: DoubleSide2
|
|
2372
|
+
}
|
|
2373
|
+
)
|
|
2374
|
+
]
|
|
2375
|
+
}
|
|
2376
|
+
);
|
|
2377
|
+
|
|
2171
2378
|
// src/model/normals.ts
|
|
2172
2379
|
function regionNormals(geometry, regions) {
|
|
2173
2380
|
const position = geometry.getAttribute("position");
|
|
@@ -2267,6 +2474,7 @@ export {
|
|
|
2267
2474
|
SectionView,
|
|
2268
2475
|
Stock,
|
|
2269
2476
|
TAP_SLOP,
|
|
2477
|
+
ToolMarks,
|
|
2270
2478
|
UnsupportedKernelVersionError,
|
|
2271
2479
|
VIEW_NAMES,
|
|
2272
2480
|
VIEW_SIGNS,
|
|
@@ -2318,6 +2526,7 @@ export {
|
|
|
2318
2526
|
distanceBetween,
|
|
2319
2527
|
dragPlane,
|
|
2320
2528
|
excludedFromFrame,
|
|
2529
|
+
featureTriangles,
|
|
2321
2530
|
featureTypeRank,
|
|
2322
2531
|
fitDistance,
|
|
2323
2532
|
fixedBoxStockBounds,
|
|
@@ -2377,6 +2586,7 @@ export {
|
|
|
2377
2586
|
trackDoubleTaps,
|
|
2378
2587
|
trackTaps,
|
|
2379
2588
|
useContentBox,
|
|
2589
|
+
usePartContext,
|
|
2380
2590
|
useRetarget,
|
|
2381
2591
|
useSectionStore,
|
|
2382
2592
|
useTapGuard,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
import { Group, Mesh, LineSegments, Box3, Plane, BufferGeometry, Vector3, Raycaster, Object3D, Intersection, Camera } from 'three';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -851,6 +852,11 @@ interface PartMeshProps {
|
|
|
851
852
|
showEdges?: boolean;
|
|
852
853
|
/** Wireframe shows region boundaries and any hovered/painted faces, with no triangle diagonals. */
|
|
853
854
|
display?: PartDisplay;
|
|
855
|
+
/**
|
|
856
|
+
* Objects drawn on the part, such as `<ToolMarks>`. They can read its model
|
|
857
|
+
* and mesh with `usePartContext`.
|
|
858
|
+
*/
|
|
859
|
+
children?: ReactNode;
|
|
854
860
|
}
|
|
855
861
|
/**
|
|
856
862
|
* The part, as one mesh with one material.
|
|
@@ -862,7 +868,7 @@ interface PartMeshProps {
|
|
|
862
868
|
* React render at all: the hovered face lives in a ref, and routing it through
|
|
863
869
|
* state is what this rewrite exists to stop doing.
|
|
864
870
|
*/
|
|
865
|
-
declare const PartMesh: ({ model, geometry, selection, focus, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, hover, activeDirection, section, onSectionChange, onAdjacency, focusFeature, onHover, onPick, theme, showEdges, display, }: PartMeshProps) => react.JSX.Element;
|
|
871
|
+
declare const PartMesh: ({ model, geometry, selection, focus, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, hover, activeDirection, section, onSectionChange, onAdjacency, focusFeature, onHover, onPick, theme, showEdges, display, children, }: PartMeshProps) => react.JSX.Element;
|
|
866
872
|
|
|
867
873
|
interface EnginePartProps extends Omit<PartMeshProps, 'model' | 'geometry'> {
|
|
868
874
|
/**
|