Align floorplan drawing with local build coordinates

This commit is contained in:
sudhir
2026-04-24 12:39:36 +05:30
parent 1492e5bd0c
commit 83e1c9d1fd
4 changed files with 796 additions and 44 deletions
@@ -11,6 +11,7 @@ type SvgLine = {
type FloorplanDraftLayerProps = { type FloorplanDraftLayerProps = {
draftPolygonPoints: string | null draftPolygonPoints: string | null
linearDraftSegment: SvgLine | null
polygonDraftPolygonPoints: string | null polygonDraftPolygonPoints: string | null
polygonDraftPolylinePoints: string | null polygonDraftPolylinePoints: string | null
polygonDraftClosingSegment: SvgLine | null polygonDraftClosingSegment: SvgLine | null
@@ -22,6 +23,7 @@ type FloorplanDraftLayerProps = {
export const FloorplanDraftLayer = memo(function FloorplanDraftLayer({ export const FloorplanDraftLayer = memo(function FloorplanDraftLayer({
draftPolygonPoints, draftPolygonPoints,
linearDraftSegment,
polygonDraftPolygonPoints, polygonDraftPolygonPoints,
polygonDraftPolylinePoints, polygonDraftPolylinePoints,
polygonDraftClosingSegment, polygonDraftClosingSegment,
@@ -44,6 +46,21 @@ export const FloorplanDraftLayer = memo(function FloorplanDraftLayer({
/> />
)} )}
{linearDraftSegment && (
<line
stroke={draftStroke}
strokeDasharray="0.2 0.12"
strokeLinecap="round"
strokeOpacity={0.95}
strokeWidth="0.08"
vectorEffect="non-scaling-stroke"
x1={linearDraftSegment.x1}
x2={linearDraftSegment.x2}
y1={linearDraftSegment.y1}
y2={linearDraftSegment.y2}
/>
)}
{polygonDraftPolygonPoints && ( {polygonDraftPolygonPoints && (
<polygon fill={draftFill} fillOpacity={0.2} points={polygonDraftPolygonPoints} stroke="none" /> <polygon fill={draftFill} fillOpacity={0.2} points={polygonDraftPolygonPoints} stroke="none" />
)} )}
File diff suppressed because it is too large Load Diff
@@ -111,15 +111,15 @@ export const CeilingTool: React.FC = () => {
const onGridMove = (event: GridEvent) => { const onGridMove = (event: GridEvent) => {
if (!(cursorRef.current && gridCursorRef.current)) return if (!(cursorRef.current && gridCursorRef.current)) return
const gridX = Math.round(event.position[0] * 2) / 2 const gridX = Math.round(event.localPosition[0] * 2) / 2
const gridZ = Math.round(event.position[2] * 2) / 2 const gridZ = Math.round(event.localPosition[2] * 2) / 2
const gridPosition: [number, number] = [gridX, gridZ] const gridPosition: [number, number] = [gridX, gridZ]
setCursorPosition(gridPosition) setCursorPosition(gridPosition)
setLevelY(event.position[1]) setLevelY(event.localPosition[1])
const ceilingY = event.position[1] + CEILING_HEIGHT const ceilingY = event.localPosition[1] + CEILING_HEIGHT
const gridY = event.position[1] + GRID_OFFSET const gridY = event.localPosition[1] + GRID_OFFSET
// Calculate snapped display position (bypass snap when Shift is held) // Calculate snapped display position (bypass snap when Shift is held)
const lastPoint = points[points.length - 1] const lastPoint = points[points.length - 1]
@@ -1,4 +1,5 @@
import type { import type {
CeilingNode,
DoorNode, DoorNode,
ItemNode, ItemNode,
RoofNode, RoofNode,
@@ -46,6 +47,12 @@ type SlabEntry = {
holes: Point2D[][] holes: Point2D[][]
} }
type CeilingEntry = {
ceiling: CeilingNode
polygon: Point2D[]
holes: Point2D[][]
}
type RoofEntry = { type RoofEntry = {
roof: RoofNode roof: RoofNode
segments: Array<{ segments: Array<{
@@ -63,6 +70,7 @@ type FloorplanSelectionToolContext = {
stairs: StairEntry[] stairs: StairEntry[]
walls: WallEntry[] walls: WallEntry[]
slabs: SlabEntry[] slabs: SlabEntry[]
ceilings: CeilingEntry[]
roofs: RoofEntry[] roofs: RoofEntry[]
openingHitTolerance: number openingHitTolerance: number
wallHitTolerance: number wallHitTolerance: number
@@ -131,6 +139,13 @@ export function getFloorplanHitNodeId(context: FloorplanSelectionToolContext) {
return roofHit.roof.id return roofHit.roof.id
} }
const ceilingHit = context.ceilings.find(({ polygon, holes }) =>
isPointInsidePolygonWithHoles(context.point, polygon, holes),
)
if (ceilingHit) {
return ceilingHit.ceiling.id
}
const slabHit = context.slabs.find(({ polygon, holes }) => const slabHit = context.slabs.find(({ polygon, holes }) =>
isPointInsidePolygonWithHoles(context.point, polygon, holes), isPointInsidePolygonWithHoles(context.point, polygon, holes),
) )
@@ -150,6 +165,7 @@ type FloorplanSelectionBoundsContext = {
walls: WallEntry[] walls: WallEntry[]
openings: OpeningPolygonEntry[] openings: OpeningPolygonEntry[]
slabs: SlabEntry[] slabs: SlabEntry[]
ceilings: CeilingEntry[]
stairs: StairEntry[] stairs: StairEntry[]
roofs: RoofEntry[] roofs: RoofEntry[]
} }
@@ -162,6 +178,7 @@ export function getFloorplanSelectionIdsInBounds({
walls, walls,
openings, openings,
slabs, slabs,
ceilings,
stairs, stairs,
roofs, roofs,
}: FloorplanSelectionBoundsContext) { }: FloorplanSelectionBoundsContext) {
@@ -184,6 +201,9 @@ export function getFloorplanSelectionIdsInBounds({
const slabIds = slabs const slabIds = slabs
.filter(({ polygon }) => doesPolygonIntersectSelectionBounds(polygon, bounds)) .filter(({ polygon }) => doesPolygonIntersectSelectionBounds(polygon, bounds))
.map(({ slab }) => slab.id) .map(({ slab }) => slab.id)
const ceilingIds = ceilings
.filter(({ polygon }) => doesPolygonIntersectSelectionBounds(polygon, bounds))
.map(({ ceiling }) => ceiling.id)
const stairIds = stairs const stairIds = stairs
.filter((stair) => .filter((stair) =>
getStairHitPolygons(stair).some((polygon) => getStairHitPolygons(stair).some((polygon) =>
@@ -198,6 +218,14 @@ export function getFloorplanSelectionIdsInBounds({
.map(({ roof }) => roof.id) .map(({ roof }) => roof.id)
return Array.from( return Array.from(
new Set([...itemIds, ...wallIds, ...openingIds, ...slabIds, ...stairIds, ...roofIds]), new Set([
...itemIds,
...wallIds,
...openingIds,
...slabIds,
...ceilingIds,
...stairIds,
...roofIds,
]),
) )
} }