fix: Ensure each connecting room has minimum 1 GU overlap with parent

Updated room positioning to verify overlap for EACH connected room
after grid alignment, not just the group as a whole. This fixes
layouts like:

  122
  00

Where room 1 was previously positioned with no overlap to room 0.

Changes:
- positionNorthMultiple/positionSouthMultiple: After centering and
  aligning group, check first and last room overlap. If insufficient,
  shift entire group to ensure minimum overlap for each room.
- positionEastMultiple/positionWestMultiple: Same approach for
  vertical stacking along east/west edges.

The algorithm now:
1. Centers the group of connecting rooms over parent
2. Aligns starting position to grid
3. Checks if first room has >= 1 GU overlap, adjusts if not
4. Checks if last room has >= 1 GU overlap, adjusts if not
5. Positions all rooms from the adjusted aligned start

This guarantees each connecting room overlaps with the parent room
by at least one Grid Unit, ensuring proper door placement and room
connectivity.
This commit is contained in:
Z. Cliffe Schreuders
2025-11-17 11:04:52 +00:00
parent 0442139236
commit 150e3a6d43

View File

@@ -1061,32 +1061,51 @@ function positionNorthMultiple(currentRoom, connectedRooms, currentPos, dimensio
}, 0);
// Calculate starting X position to center the group over current room
// This ensures connected rooms are distributed along current room's edge
const groupStartX = currentPos.x + (currentDim.widthPx - totalWidth) / 2;
// Align the starting position to grid
// All rooms will be placed from this aligned start without individual alignment
// since room widths are multiples of grid units
const alignedGroupStart = alignToGrid(groupStartX, 0);
let alignedStartX = alignToGrid(groupStartX, 0).x;
// Position each room side-by-side starting from aligned position
// No individual alignment needed - rooms naturally align when placed from grid-aligned start
let currentX = alignedGroupStart.x;
// CRITICAL: Ensure each room has at least 1 GU overlap with parent room
// After grid alignment, check if all rooms will have minimum overlap
const minOverlap = GRID_UNIT_WIDTH_PX;
// Check first room overlap
const firstDim = dimensions[connectedRooms[0]];
const firstRoomEnd = alignedStartX + firstDim.widthPx;
const firstOverlap = Math.min(firstRoomEnd, currentPos.x + currentDim.widthPx) - Math.max(alignedStartX, currentPos.x);
if (firstOverlap < minOverlap) {
// First room doesn't have enough overlap, shift group to the right
alignedStartX = currentPos.x - firstDim.widthPx + minOverlap;
alignedStartX = alignToGrid(alignedStartX, 0).x;
}
// Check last room overlap (after potential adjustment for first room)
const lastRoomStartX = alignedStartX + totalWidth - dimensions[connectedRooms[connectedRooms.length - 1]].widthPx;
const lastRoomEndX = alignedStartX + totalWidth;
const lastOverlap = Math.min(lastRoomEndX, currentPos.x + currentDim.widthPx) - Math.max(lastRoomStartX, currentPos.x);
if (lastOverlap < minOverlap) {
// Last room doesn't have enough overlap, shift group to the left
const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]];
alignedStartX = currentPos.x + currentDim.widthPx - totalWidth - lastDim.widthPx + minOverlap;
alignedStartX = alignToGrid(alignedStartX, 0).x;
}
// Position each room side-by-side starting from adjusted aligned position
let currentX = alignedStartX;
connectedRooms.forEach(roomId => {
const connectedDim = dimensions[roomId];
// Calculate Y position based on room's stacking height
const roomY = currentPos.y - connectedDim.stackingHeightPx;
// Align Y to grid
const alignedY = alignToGrid(0, roomY).y;
// X is already aligned via group start, just use currentX
positions[roomId] = { x: currentX, y: alignedY };
// Move X position for next room (no individual alignment)
// Since room widths are multiples of grid units, this maintains alignment
// Move X position for next room
currentX += connectedDim.widthPx;
});
@@ -1122,27 +1141,48 @@ function positionSouthMultiple(currentRoom, connectedRooms, currentPos, dimensio
}, 0);
// Calculate starting X position to center the group over current room
// This ensures connected rooms are distributed along current room's edge
const groupStartX = currentPos.x + (currentDim.widthPx - totalWidth) / 2;
// Align the starting position to grid
// All rooms will be placed from this aligned start without individual alignment
const alignedGroupStart = alignToGrid(groupStartX, 0);
let alignedStartX = alignToGrid(groupStartX, 0).x;
// Position each room side-by-side starting from aligned position
let currentX = alignedGroupStart.x;
// CRITICAL: Ensure each room has at least 1 GU overlap with parent room
const minOverlap = GRID_UNIT_WIDTH_PX;
// Check first room overlap
const firstDim = dimensions[connectedRooms[0]];
const firstRoomEnd = alignedStartX + firstDim.widthPx;
const firstOverlap = Math.min(firstRoomEnd, currentPos.x + currentDim.widthPx) - Math.max(alignedStartX, currentPos.x);
if (firstOverlap < minOverlap) {
// First room doesn't have enough overlap, shift group to the right
alignedStartX = currentPos.x - firstDim.widthPx + minOverlap;
alignedStartX = alignToGrid(alignedStartX, 0).x;
}
// Check last room overlap
const lastRoomStartX = alignedStartX + totalWidth - dimensions[connectedRooms[connectedRooms.length - 1]].widthPx;
const lastRoomEndX = alignedStartX + totalWidth;
const lastOverlap = Math.min(lastRoomEndX, currentPos.x + currentDim.widthPx) - Math.max(lastRoomStartX, currentPos.x);
if (lastOverlap < minOverlap) {
// Last room doesn't have enough overlap, shift group to the left
const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]];
alignedStartX = currentPos.x + currentDim.widthPx - totalWidth - lastDim.widthPx + minOverlap;
alignedStartX = alignToGrid(alignedStartX, 0).x;
}
// Position each room side-by-side
let currentX = alignedStartX;
const y = currentPos.y + currentDim.stackingHeightPx;
// Align Y to grid
const alignedY = alignToGrid(0, y).y;
connectedRooms.forEach(roomId => {
const connectedDim = dimensions[roomId];
// X is already aligned via group start, Y is same for all rooms
positions[roomId] = { x: currentX, y: alignedY };
// Move X position for next room (no individual alignment)
// Move X position for next room
currentX += connectedDim.widthPx;
});
@@ -1178,29 +1218,48 @@ function positionEastMultiple(currentRoom, connectedRooms, currentPos, dimension
}, 0);
// Calculate starting Y position to center the group along current room's edge
// This ensures connected rooms are distributed along current room's edge
const groupStartY = currentPos.y + (currentDim.stackingHeightPx - totalHeight) / 2;
// Align the starting position to grid
// All rooms will be placed from this aligned start without individual alignment
const alignedGroupStart = alignToGrid(0, groupStartY);
let alignedStartY = alignToGrid(0, groupStartY).y;
// Position each room stacked vertically starting from aligned position
// CRITICAL: Ensure each room has at least 1 GU overlap with parent room
const minOverlap = GRID_UNIT_HEIGHT_PX;
// Check first room overlap
const firstDim = dimensions[connectedRooms[0]];
const firstRoomEnd = alignedStartY + firstDim.stackingHeightPx;
const firstOverlap = Math.min(firstRoomEnd, currentPos.y + currentDim.stackingHeightPx) - Math.max(alignedStartY, currentPos.y);
if (firstOverlap < minOverlap) {
// First room doesn't have enough overlap, shift group down
alignedStartY = currentPos.y - firstDim.stackingHeightPx + minOverlap;
alignedStartY = alignToGrid(0, alignedStartY).y;
}
// Check last room overlap
const lastRoomStartY = alignedStartY + totalHeight - dimensions[connectedRooms[connectedRooms.length - 1]].stackingHeightPx;
const lastRoomEndY = alignedStartY + totalHeight;
const lastOverlap = Math.min(lastRoomEndY, currentPos.y + currentDim.stackingHeightPx) - Math.max(lastRoomStartY, currentPos.y);
if (lastOverlap < minOverlap) {
// Last room doesn't have enough overlap, shift group up
const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]];
alignedStartY = currentPos.y + currentDim.stackingHeightPx - totalHeight - lastDim.stackingHeightPx + minOverlap;
alignedStartY = alignToGrid(0, alignedStartY).y;
}
// Position each room stacked vertically
const x = currentPos.x + currentDim.widthPx;
// Align X to grid
const alignedX = alignToGrid(x, 0).x;
let currentY = alignedGroupStart.y;
let currentY = alignedStartY;
connectedRooms.forEach(roomId => {
const connectedDim = dimensions[roomId];
// Y is already aligned via group start, X is same for all rooms
positions[roomId] = { x: alignedX, y: currentY };
// Move Y position for next room (no individual alignment)
// Since room heights are multiples of grid units, this maintains alignment
// Move Y position for next room
currentY += connectedDim.stackingHeightPx;
});
@@ -1235,30 +1294,50 @@ function positionWestMultiple(currentRoom, connectedRooms, currentPos, dimension
}, 0);
// Calculate starting Y position to center the group along current room's edge
// This ensures connected rooms are distributed along current room's edge
const groupStartY = currentPos.y + (currentDim.stackingHeightPx - totalHeight) / 2;
// Align the starting position to grid
// All rooms will be placed from this aligned start without individual alignment
const alignedGroupStart = alignToGrid(0, groupStartY);
let alignedStartY = alignToGrid(0, groupStartY).y;
// Position each room stacked vertically starting from aligned position
let currentY = alignedGroupStart.y;
// CRITICAL: Ensure each room has at least 1 GU overlap with parent room
const minOverlap = GRID_UNIT_HEIGHT_PX;
// Check first room overlap
const firstDim = dimensions[connectedRooms[0]];
const firstRoomEnd = alignedStartY + firstDim.stackingHeightPx;
const firstOverlap = Math.min(firstRoomEnd, currentPos.y + currentDim.stackingHeightPx) - Math.max(alignedStartY, currentPos.y);
if (firstOverlap < minOverlap) {
// First room doesn't have enough overlap, shift group down
alignedStartY = currentPos.y - firstDim.stackingHeightPx + minOverlap;
alignedStartY = alignToGrid(0, alignedStartY).y;
}
// Check last room overlap
const lastRoomStartY = alignedStartY + totalHeight - dimensions[connectedRooms[connectedRooms.length - 1]].stackingHeightPx;
const lastRoomEndY = alignedStartY + totalHeight;
const lastOverlap = Math.min(lastRoomEndY, currentPos.y + currentDim.stackingHeightPx) - Math.max(lastRoomStartY, currentPos.y);
if (lastOverlap < minOverlap) {
// Last room doesn't have enough overlap, shift group up
const lastDim = dimensions[connectedRooms[connectedRooms.length - 1]];
alignedStartY = currentPos.y + currentDim.stackingHeightPx - totalHeight - lastDim.stackingHeightPx + minOverlap;
alignedStartY = alignToGrid(0, alignedStartY).y;
}
// Position each room stacked vertically
let currentY = alignedStartY;
connectedRooms.forEach(roomId => {
const connectedDim = dimensions[roomId];
// Position to the left
const x = currentPos.x - connectedDim.widthPx;
// Align X to grid
const alignedX = alignToGrid(x, 0).x;
// Y is already aligned via group start
positions[roomId] = { x: alignedX, y: currentY };
// Move Y position for next room (no individual alignment)
// Since room heights are multiples of grid units, this maintains alignment
// Move Y position for next room
currentY += connectedDim.stackingHeightPx;
});