Add presets (table/chair), object count, near_object condition, optimization locks placed objects and randomizes remaining

This commit is contained in:
2026-10-17 19:52:52 -04:00
parent a708a0cfe5
commit ced33b672f
6 changed files with 172 additions and 16 deletions
+98 -11
View File
@@ -1,4 +1,4 @@
import type { ConditionKind, Entrance, FurnitureConfig, LayoutState, RoomConfig } from '../types';
import type { ConditionKind, Entrance, FurnitureConfig, FurniturePreset, LayoutState, RoomConfig } from '../types';
interface ControlPanelProps {
state: LayoutState;
@@ -23,6 +23,21 @@ export function ControlPanel({
optimizing,
timeLeft,
}: ControlPanelProps) {
const addPreset = (p: FurniturePreset) => {
const id = 'f_' + Date.now();
const newItem: FurnitureConfig = {
id,
name: p.name,
shape: { ...p.shape, x: 50, y: 50 },
conditions: p.conditions.map((c) => ({ ...c })),
color: p.color,
lockedForOptimization: false,
placed: true,
};
onStateChange({ ...state, furniture: [...state.furniture, newItem] });
onSelect(id);
};
const addFurniture = () => {
const id = 'f_' + Date.now();
const newItem: FurnitureConfig = {
@@ -41,6 +56,28 @@ export function ControlPanel({
onSelect(id);
};
const tablePreset: FurniturePreset = {
id: 'table',
name: 'Table',
shape: { type: 'rectangle', width: 80, height: 60 },
conditions: [
{ kind: 'walk_to_and_sit', weight: 1 },
{ kind: 'accessible', weight: 1 },
],
color: '#a1887f',
};
const chairPreset: FurniturePreset = {
id: 'chair',
name: 'Chair',
shape: { type: 'rectangle', width: 40, height: 40 },
conditions: [
{ kind: 'walk_to_and_sit', weight: 1 },
{ kind: 'near_object', weight: 1, params: {} },
{ kind: 'accessible', weight: 1 },
],
color: '#d7ccc5',
};
const setRoom = (room: Partial<RoomConfig>) => {
onStateChange({ ...state, room: { ...state.room, ...room } });
};
@@ -68,7 +105,8 @@ export function ControlPanel({
if (f.id !== selectedId) return f;
const has = f.conditions.some((c) => c.kind === kind);
if (enabled && !has) {
return { ...f, conditions: [...f.conditions, { kind, weight: 1 }] };
const params = kind === 'near_object' ? { targetId: '' } : {};
return { ...f, conditions: [...f.conditions, { kind, weight: 1, params }] };
}
if (!enabled && has) {
return { ...f, conditions: f.conditions.filter((c) => c.kind !== kind) };
@@ -78,6 +116,18 @@ export function ControlPanel({
onStateChange({ ...state, furniture: updated });
};
const setNearObjectTarget = (targetId: string) => {
if (!selectedId) return;
const updated = state.furniture.map((f) => {
if (f.id !== selectedId) return f;
return {
...f,
conditions: f.conditions.map((c) => (c.kind === 'near_object' ? { ...c, params: { ...c.params, targetId } } : c)),
};
});
onStateChange({ ...state, furniture: updated });
};
const selected = state.furniture.find((f) => f.id === selectedId);
return (
@@ -112,10 +162,29 @@ export function ControlPanel({
style={{ width: 80, marginLeft: 4 }}
/>
</label>
<div style={{ marginTop: 8 }}>
<label>
Object Count:
<input
type="number"
min={0}
value={state.objectCount ?? state.furniture.length}
onChange={(e) =>
onStateChange({ ...state, objectCount: Math.max(0, Number(e.target.value)) })
}
style={{ width: 80, marginLeft: 4 }}
/>
</label>
</div>
<div style={{ marginTop: 8 }}>
<button onClick={addFurniture}>Add Furniture</button>
<button onClick={placeEntrance} style={{ marginLeft: 8 }}>
Place Entrance
</button> <button onClick={() => addPreset(tablePreset)} style={{ marginLeft: 8 }}>
Add Table
</button>
<button onClick={() => addPreset(chairPreset)} style={{ marginLeft: 8 }}>
Add Chair
</button>
</div>
{state.entrance && (
@@ -176,16 +245,34 @@ export function ControlPanel({
</div>
<div style={{ marginTop: 8 }}>
<div>Conditions:</div>
{(['walk_to_and_sit', 'around_open_area', 'near_entrance', 'accessible', 'not_blocking_path', 'open_circulation'] as ConditionKind[]).map(
{(['walk_to_and_sit', 'around_open_area', 'near_entrance', 'near_object', 'accessible', 'not_blocking_path', 'open_circulation'] as ConditionKind[]).map(
(k) => (
<label key={k} style={{ display: 'block' }}>
<input
type="checkbox"
checked={selected.conditions.some((c) => c.kind === k)}
onChange={(e) => updateSelectedCondition(k, e.target.checked)}
/>
{k}
</label>
<div key={k} style={{ display: 'block' }}>
<label>
<input
type="checkbox"
checked={selected.conditions.some((c) => c.kind === k)}
onChange={(e) => updateSelectedCondition(k, e.target.checked)}
/>
{k}
</label>
{k === 'near_object' && selected.conditions.some((c) => c.kind === 'near_object') && (
<select
style={{ marginLeft: 8 }}
value={(selected.conditions.find((c) => c.kind === 'near_object')?.params as any)?.targetId || ''}
onChange={(e) => setNearObjectTarget(e.target.value)}
>
<option value="">Select object</option>
{state.furniture
.filter((f) => f.id !== selected.id)
.map((f) => (
<option key={f.id} value={f.id}>
{f.name}
</option>
))}
</select>
)}
</div>
),
)}
</div>