copper3d 3.6.8 → 3.6.10

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.
@@ -31,11 +31,15 @@ export interface SurfaceAnnotatorOptions {
31
31
  onModeChange?: (m: AnnotationMode) => void;
32
32
  /** Callback when the annotation list changes (add/remove/undo/clear). */
33
33
  onChange?: (annotations: Annotation[]) => void;
34
- /** Callback when interaction state changes (drawing, armed tool, draw-lock status). */
34
+ /** Callback when the engine changes the selection itself (delete, deselect-on-navigate) so the UI can mirror it. */
35
+ onSelectionChange?: (id: string | null) => void;
36
+ /** Callback when interaction state changes (drawing, armed tool, draw-lock status, geodesic-editing). */
35
37
  onInteractionChange?: (s: {
36
38
  drawing: boolean;
37
39
  armed: AnnotationMode;
38
40
  locked: boolean;
41
+ /** True while a geodesic is editable (in-progress or a re-opened committed one) → its anchors can be dragged/deleted/inserted. */
42
+ editing: boolean;
39
43
  }) => void;
40
44
  }
41
45
  /**
@@ -71,10 +75,15 @@ export declare class SurfaceAnnotator {
71
75
  private activeGeoMarkers;
72
76
  private geoRay;
73
77
  private geoNdc;
74
- private geoHoverBadge?;
75
78
  private hoveredGeoMarker;
79
+ private draggingAnchor;
80
+ private geoRedrawScheduled;
81
+ private editingId;
82
+ private geoClosed;
76
83
  private _projV;
77
84
  constructor(opts: SurfaceAnnotatorOptions);
85
+ /** Block the OS right-click menu when the pointer is over the WebGL canvas (not the HTML panels). */
86
+ private onContextMenu;
78
87
  /** Update the pixel resolution of all fat lines on window resize, otherwise line width distorts. */
79
88
  private onResize;
80
89
  private get freehandColor();
@@ -89,22 +98,15 @@ export declare class SurfaceAnnotator {
89
98
  clearAll(): void;
90
99
  deleteAnnotation(id: string): void;
91
100
  selectAnnotation(id: string | null): void;
101
+ /** Change the selection from inside the engine (delete / deselect-on-navigate) and mirror it to the UI. */
102
+ private setSelected;
92
103
  /** Redraw the corresponding three object after a color change. */
93
104
  refreshAnnotation(id: string): void;
94
105
  exportJSON(modelName: string, opts?: ExportOptions): {
95
106
  model: string;
96
107
  exportedAt: string;
97
108
  space: "local" | "world";
98
- annotations: {
99
- id: string;
100
- type: "contour" | "points";
101
- mode: "freehand" | "geodesic" | null;
102
- label: string;
103
- color: string;
104
- closed: boolean;
105
- visible: boolean;
106
- points: number[][];
107
- }[];
109
+ annotations: Record<string, unknown>[];
108
110
  };
109
111
  setVisible(id: string, visible: boolean): void;
110
112
  /**
@@ -122,15 +124,20 @@ export declare class SurfaceAnnotator {
122
124
  closed: boolean;
123
125
  visible?: boolean;
124
126
  points: number[][];
127
+ anchors?: number[][];
125
128
  }>;
126
129
  }): number;
127
130
  private get drawing();
128
131
  private applyCameraGating;
132
+ /** Emit the current interaction state (camera gating + whether a geodesic is editable). */
133
+ private emitInteraction;
129
134
  /** Reconcile the scene against store.list(): add missing objects, remove deleted ones (no dispose, kept for undo restore). */
130
135
  private reconcile;
131
136
  private applySelection;
132
137
  private disposeObject;
133
138
  private nextId;
139
+ /** Parse a raw exported point ([x,y,z] or [x,y,z,nx,ny,nz], local space) into an AnnotationVertex, recovering the normal from the nearest graph vertex when absent. */
140
+ private rawToVertex;
134
141
  private hit;
135
142
  /**
136
143
  * Whether the event target is the WebGL canvas inside the container.
@@ -141,6 +148,10 @@ export declare class SurfaceAnnotator {
141
148
  */
142
149
  private insideContainer;
143
150
  private onPointerDown;
151
+ /** After any anchor edit: refresh markers + line; drop/delete the contour when it becomes degenerate. */
152
+ private afterGeoEdit;
153
+ /** Coalesce live drag redraws to one per animation frame (moveAnchorTo runs Dijkstra per move). */
154
+ private scheduleGeoRedraw;
144
155
  /**
145
156
  * Pick an in-progress anchor: return the index of the nearest anchor (screen pixel distance <
146
157
  * tolerance), or -1 on a miss.
@@ -154,15 +165,14 @@ export declare class SurfaceAnnotator {
154
165
  * radius to make it easy to hit.
155
166
  */
156
167
  private pickGeoMarker;
157
- /** Set the currently hovered anchor (-1 = none): update highlight scale, cursor, and the "✕ (cancel)" floating badge. */
168
+ /**
169
+ * Set the currently hovered anchor (-1 = none): scale it up as a highlight and show a "grab"
170
+ * cursor to signal it's draggable. Delete is now a right-click (no floating ✕ affordance).
171
+ */
158
172
  private setGeoHover;
159
- /** Lazily create the floating badge (appended inside the container, pointer-events:none so it doesn't block clicks). */
160
- private ensureGeoBadge;
161
- /** Position the ✕ badge at the anchor's screen projection (dead center, i.e. where the cursor hovers, to avoid ambiguity). */
162
- private positionGeoBadge;
163
- /** Rebuild the visible anchor spheres from the current anchors (slightly larger than placed points, so they're easy to see and click to cancel). */
173
+ /** Rebuild the visible anchor spheres from the current anchors (slightly larger than placed points, so they're easy to see and grab). */
164
174
  private rebuildGeoMarkers;
165
- /** Redraw the in-progress geodesic from the current anchors (not closed); remove the line when fewer than two points. */
175
+ /** Redraw the active geodesic from its current anchors (honoring the closed state); when editing a committed contour, also keep the stored annotation data in sync so export stays correct. */
166
176
  private redrawGeoLine;
167
177
  /** Discard the in-progress geodesic: remove and dispose the line and all anchors. */
168
178
  private clearActiveGeo;
@@ -175,6 +185,18 @@ export declare class SurfaceAnnotator {
175
185
  private surfacePathBetween;
176
186
  /** Finish the current geodesic: close it into a ring and commit it as one contour. */
177
187
  private finishGeodesic;
188
+ /**
189
+ * Re-open a committed geodesic contour for editing: rebuild its anchors (from the stored positions)
190
+ * as draggable markers and reuse its line for live updates. No-op for non-geodesic / anchorless
191
+ * annotations. The edit session ends on Enter / mode-switch / selecting another / Esc.
192
+ */
193
+ private tryOpenGeoEdit;
194
+ /**
195
+ * Finalize an edit session on a committed geodesic: the annotation data was kept in sync live
196
+ * (redrawGeoLine), so here we just remove the edit markers, notify subscribers, and end the
197
+ * session — or delete the annotation if it was reduced below 2 anchors.
198
+ */
199
+ private recommitGeodesic;
178
200
  private isTypingTarget;
179
201
  private onKeyDown;
180
202
  private onKeyUp;
@@ -21,19 +21,12 @@ export declare class AnnotationStore {
21
21
  setLabel(id: string, label: string): void;
22
22
  setColor(id: string, color: string): void;
23
23
  setVisible(id: string, visible: boolean): void;
24
+ /** Notify subscribers after an in-place mutation of an existing annotation (e.g. geodesic edit re-commit). */
25
+ touch(): void;
24
26
  toJSON(modelName: string, mesh: THREE.Mesh, opts?: ExportOptions): {
25
27
  model: string;
26
28
  exportedAt: string;
27
29
  space: "local" | "world";
28
- annotations: {
29
- id: string;
30
- type: "contour" | "points";
31
- mode: "freehand" | "geodesic" | null;
32
- label: string;
33
- color: string;
34
- closed: boolean;
35
- visible: boolean;
36
- points: number[][];
37
- }[];
30
+ annotations: Record<string, unknown>[];
38
31
  };
39
32
  }
@@ -17,6 +17,22 @@ export declare class GeodesicContour {
17
17
  private snapshot;
18
18
  /** Given a local hit point, snap to the nearest vertex and compute the path to the previous anchor. */
19
19
  addAnchor(localHitPoint: THREE.Vector3): void;
20
+ /** Move the anchor at `index` to the vertex nearest `localHitPoint`, rebuilding adjacent segments live. */
21
+ moveAnchorTo(index: number, localHitPoint: THREE.Vector3): void;
22
+ /** Anchor vertex indices (persisted on a committed geodesic so it can be re-opened for editing). */
23
+ getAnchorIndices(): number[];
24
+ /** Rebuild an editable contour from stored anchor vertex indices (re-opening a committed geodesic). */
25
+ static fromAnchors(graph: MeshGraph, mesh: THREE.Mesh, indices: number[]): GeodesicContour;
26
+ /** Insert a new anchor (snapped to the nearest vertex) at position `index`, rebuilding segments. */
27
+ insertAnchorAt(index: number, localHitPoint: THREE.Vector3): void;
28
+ /**
29
+ * Which anchor interval's surface path passes closest to `worldPoint` — i.e. the edge the user
30
+ * clicked on, so a new anchor can be inserted there. Returns the interval index (insert after that
31
+ * anchor, i.e. at index+1), or -1 when there are fewer than 2 anchors or the click is farther than
32
+ * `maxDist` (world units) from every edge. For a closed contour the trailing closing edge
33
+ * (last→first) is considered and maps to appending at the end.
34
+ */
35
+ nearestInsertIndex(worldPoint: THREE.Vector3, matrixWorld: THREE.Matrix4, closed: boolean, maxDist: number): number;
20
36
  /** Remove the anchor at the given index and recompute adjacent segments (allows canceling any middle point). */
21
37
  removeAnchorAt(index: number): void;
22
38
  /** Whether there is still an editable change to undo (add/remove point). */
@@ -30,4 +46,14 @@ export declare class GeodesicContour {
30
46
  get anchorCount(): number;
31
47
  /** Stitch all path vertices (world) + normals into a polyline; when closed, add one first-to-last segment. */
32
48
  buildVertices(closed: boolean): AnnotationVertex[];
49
+ /**
50
+ * Relax the stitched shortest-path polyline so it reads as a smooth curve instead of the raw
51
+ * voxel staircase, WITHOUT changing the point count (keeps editing/index mapping simple) and
52
+ * WITHOUT moving the anchors (they stay exact control points). A few Laplacian passes pull each
53
+ * interior point toward the midpoint of its neighbours; anchors and (for open paths) the two
54
+ * endpoints are pinned. Normals are carried over from each point's original graph vertex — the
55
+ * points only shift slightly and the line already floats above the surface by `epsilon`, so the
56
+ * approximation is invisible and avoids an O(V) nearest-vertex scan per point on every redraw.
57
+ */
58
+ private smoothPath;
33
59
  }
@@ -6,3 +6,11 @@ import type { AnnotationVertex } from "./types";
6
6
  * radius is passed in by the caller, scaled to the model bbox.
7
7
  */
8
8
  export declare function makePointMarker(v: AnnotationVertex, mesh: THREE.Mesh, color: string, radius: number): THREE.Mesh;
9
+ /**
10
+ * Create a draggable ANCHOR HANDLE (for the geodesic editor): a white outer rim around a
11
+ * tool-colored core, so the handle stands out against both the (same-colored) contour line and the
12
+ * grey surface. Returned as a Group; scale it to show hover/selection feedback. depthTest stays ON
13
+ * (occluded by the model on the far side) and it's lifted a touch more than a plain marker so it
14
+ * sits above the thickened line rather than sinking into it.
15
+ */
16
+ export declare function makeAnchorHandle(v: AnnotationVertex, mesh: THREE.Mesh, coreColor: string, radius: number): THREE.Group;
@@ -24,6 +24,12 @@ export interface Annotation {
24
24
  closed: boolean;
25
25
  visible: boolean;
26
26
  vertices: AnnotationVertex[];
27
+ /**
28
+ * Geodesic control points (local-space positions) — present only for geodesic contours. Lets a
29
+ * committed contour be re-opened for editing (drag/delete/insert its anchors). Stored as positions
30
+ * (not graph indices) so it survives export/import across sessions.
31
+ */
32
+ anchors?: AnnotationVertex[];
27
33
  object3D: THREE.Object3D | null;
28
34
  }
29
35
  export interface ExportOptions {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "copper3d",
3
3
  "description": "A 3d visualisation package base on threejs provides multiple scenes and Nrrd image load funtion.",
4
- "version": "3.6.8",
4
+ "version": "3.6.10",
5
5
  "main": "dist/bundle.umd.js",
6
6
  "moudle": "dist/bundle.esm.js",
7
7
  "types": "dist/types/index.d.ts",