Merge origin/main into feat/placement-interaction-overhaul
Resolve 7 conflicts keeping our snapping migration + floorplan perf work as source of truth, combined with main's MEP run-continuation / Alt-detach / latch handles. Rebuilt two import blocks the auto-merge silently truncated (node-arrow-handles.tsx, duct-fitting/move-tool.tsx). Verified: tsc clean across core/viewer/editor/nodes/mcp, 451 tests pass, biome clean. Floorplan view-transform re-render storm confirmed pre-existing (not introduced by this merge). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,7 +27,7 @@ export const pipeTrapDefinition: NodeDefinition<typeof PipeTrapNode> = {
|
||||
metadata: {},
|
||||
position: [0, 0, 0],
|
||||
rotation: 0,
|
||||
diameter: 1.5,
|
||||
diameter: 2,
|
||||
pipeMaterial: 'pvc',
|
||||
armLengthM: 0,
|
||||
}),
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { Group, Mesh, TorusGeometry, Vector3 } from 'three'
|
||||
import { DoubleSide, Group, Mesh, SphereGeometry, TorusGeometry, Vector3 } from 'three'
|
||||
import { buildSection, INCHES_TO_METERS } from '../duct-segment/geometry'
|
||||
import { createPipeMaterial } from '../pipe-segment/geometry'
|
||||
import type { PipeTrapNode } from './schema'
|
||||
|
||||
const BEND_SEGMENTS = 24
|
||||
const RADIAL_SEGMENTS = 20
|
||||
/** Sphere hubs filling the U-bend → stub joints read as a coupling and,
|
||||
* more importantly, hide the wedge gap left where the horizontal arm's
|
||||
* flat end cap meets the bend's upward-facing opening at 90°. */
|
||||
const HUB_RADIUS_FACTOR = 1.12
|
||||
|
||||
/** Inlet drop and arm reach in pipe radii — keeps the trap proportional
|
||||
* to its size without per-size tuning. */
|
||||
@@ -19,8 +24,12 @@ const ARM_REACH_RADII = 3.2
|
||||
export function buildPipeTrapGeometry(node: PipeTrapNode): Group {
|
||||
const group = new Group()
|
||||
const material = createPipeMaterial({ pipeMaterial: node.pipeMaterial, system: 'waste' })
|
||||
// Double-sided so the thin pipe walls don't drop out at grazing angles,
|
||||
// which read as cuts/holes on the bend and stub ends.
|
||||
material.side = DoubleSide
|
||||
const radius = (node.diameter * INCHES_TO_METERS) / 2
|
||||
const bendR = radius * 1.6
|
||||
const hubRadius = radius * HUB_RADIUS_FACTOR
|
||||
|
||||
// U-bend: half torus in the XY plane, opening upward. Sits so its two
|
||||
// tops are at y = bendR (the inlet riser and the arm rise).
|
||||
@@ -49,6 +58,19 @@ export function buildPipeTrapGeometry(node: PipeTrapNode): Group {
|
||||
const arm = buildSection(armStart, armEnd, radius, material, 'pipe-trap-arm')
|
||||
if (arm) group.add(arm)
|
||||
|
||||
// Coupling hubs at the two U-bend tops where the straight stubs meet the
|
||||
// torus. They fill the 90° miter wedge (the visible "cut") and read as
|
||||
// the trap's slip-joint nuts.
|
||||
for (const [i, center] of [
|
||||
new Vector3(0, bendR, 0),
|
||||
new Vector3(bendR * 2, bendR, 0),
|
||||
].entries()) {
|
||||
const hub = new Mesh(new SphereGeometry(hubRadius, RADIAL_SEGMENTS, 12), material)
|
||||
hub.name = `pipe-trap-hub-${i}`
|
||||
hub.position.copy(center)
|
||||
group.add(hub)
|
||||
}
|
||||
|
||||
return group
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ const PipeTrapTool = () => {
|
||||
const activeLevelId = useViewer((s) => s.selection.levelId)
|
||||
const [cursor, setCursor] = useState<[number, number, number] | null>(null)
|
||||
const [yaw, setYaw] = useState(0)
|
||||
const [diameter] = useState(1.5)
|
||||
const [diameter] = useState(pipeTrapDefinition.defaults().diameter)
|
||||
const yawRef = useRef(0)
|
||||
const diameterRef = useRef(diameter)
|
||||
diameterRef.current = diameter
|
||||
|
||||
Reference in New Issue
Block a user