Wire the opening-guides service into the 3D door/window move tools and render the
wall-plane guides as the spatial twin of the 2D plan guides:
- sill / head height (floor → bottom edge, top edge → wall top) — windows only
- edge-to-edge proximity dimensions to the nearest neighbour each side
- a sill-alignment line + SNAP when a window shares a neighbour's sill / centre
/ top (competes with the 0.5m grid, Shift bypasses) — the chosen
"snap + guide" behaviour
- Figma-style equal-spacing "=" badges across a run of openings
Adds `useOpeningGuides` (editor store) + `OpeningGuides3DLayer` (raw THREE.Line
overlays + Html pills, mounted beside Alignment3DGuideLayer) and a thin
`opening-guides-runtime` helper (collect siblings / sill snap / publish / clear)
called from the door + window move-tools at their per-tick `applyPreview` hook;
guides clear on commit / cancel / leave / roof-hover / unmount.
Guides render in the move cursor's building-local frame (reuses `wallLocalToWorld`)
so they track the dragged opening exactly. Codex-reviewed (roof-hover stale-guide
clear, collapsed-dimension suppression). Placement-time guides reuse the same
helper and are the next step.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
34 lines
1.4 KiB
TypeScript
34 lines
1.4 KiB
TypeScript
// Ephemeral store for the 3D opening proximity/alignment guides published by the
|
|
// door/window move + placement tools during a drag — the wall-plane counterpart
|
|
// of `useAlignmentGuides` (which only carries floor-plane XZ guides). Guides are
|
|
// already transformed into the move tool's render frame — the same building-local
|
|
// frame as the drag cursor (ToolManager's group) — so the renderer stays dumb.
|
|
// Producers clear on commit, cancel, leave, and unmount.
|
|
|
|
import { create } from 'zustand'
|
|
|
|
export type OpeningGuideVec3 = [number, number, number]
|
|
|
|
export type OpeningGuide3D =
|
|
// A measured line + distance pill: sill (floor → bottom edge), head (top edge
|
|
// → wall top), or along-wall edge-to-edge proximity.
|
|
| { kind: 'dimension'; from: OpeningGuideVec3; to: OpeningGuideVec3; value: number }
|
|
// A dashed line connecting two openings that share a sill / centre / top.
|
|
| { kind: 'align-line'; from: OpeningGuideVec3; to: OpeningGuideVec3 }
|
|
// A Figma-style "=" badge marking one gap in an equal-spacing run.
|
|
| { kind: 'badge'; at: OpeningGuideVec3; value: number }
|
|
|
|
type OpeningGuidesState = {
|
|
guides: OpeningGuide3D[]
|
|
set(guides: OpeningGuide3D[]): void
|
|
clear(): void
|
|
}
|
|
|
|
const useOpeningGuides = create<OpeningGuidesState>((set) => ({
|
|
guides: [],
|
|
set: (guides) => set({ guides }),
|
|
clear: () => set({ guides: [] }),
|
|
}))
|
|
|
|
export default useOpeningGuides
|