feat: add WALL_CABLE electrical type and room outlet/switch count stats
Add wall cable item — a bare cable exit from the wall for direct consumer connection without an outlet. Includes 2D symbol (circle + cable stub), 3D mesh (round plate + protruding cable), and palette entry. Also add outlet and switch count metrics to the room info section in the properties panel.
This commit is contained in:
@@ -242,6 +242,8 @@
|
||||
"properties.curtainLeftOpen": "Left open",
|
||||
"properties.curtainRightOpen": "Right open",
|
||||
"properties.curtainFabricColor": "Fabric color",
|
||||
"properties.outletCountStat": "Outlets",
|
||||
"properties.switchCountStat": "Switches",
|
||||
"properties.outletWidth": "Outlet width",
|
||||
"properties.outletHeight": "Outlet height",
|
||||
"properties.outletCount": "Count",
|
||||
@@ -293,6 +295,7 @@
|
||||
"electrical.junction": "Junction",
|
||||
"electrical.lights": "Lights",
|
||||
"electrical.cable": "Cable",
|
||||
"electrical.wallCable": "Wall Cable",
|
||||
|
||||
"furniture.title": "Furniture",
|
||||
"furniture.searchPlaceholder": "Search furniture\u2026",
|
||||
|
||||
@@ -245,6 +245,8 @@
|
||||
"properties.curtainLeftOpen": "Левая створка",
|
||||
"properties.curtainRightOpen": "Правая створка",
|
||||
"properties.curtainFabricColor": "Цвет ткани",
|
||||
"properties.outletCountStat": "Розетки",
|
||||
"properties.switchCountStat": "Выключатели",
|
||||
"properties.outletWidth": "Ширина розетки",
|
||||
"properties.outletHeight": "Высота розетки",
|
||||
"properties.outletCount": "Количество",
|
||||
@@ -296,6 +298,7 @@
|
||||
"electrical.junction": "Распределительная коробка",
|
||||
"electrical.lights": "Освещение",
|
||||
"electrical.cable": "Кабель",
|
||||
"electrical.wallCable": "Кабель из стены",
|
||||
|
||||
"furniture.title": "Мебель",
|
||||
"furniture.searchPlaceholder": "Поиск мебели\u2026",
|
||||
|
||||
@@ -151,6 +151,14 @@ export function PropertiesPanel() {
|
||||
)}
|
||||
<PropertyRow label={t('properties.wallHeight')} value={`${room.wallHeight}m`} />
|
||||
<PropertyRow label={t('properties.plinthHeight')} value={`${Math.round(room.plinthHeight * 1000) / 10}cm`} />
|
||||
<PropertyRow
|
||||
label={t('properties.outletCountStat')}
|
||||
value={String(electricalItems.filter((e) => e.type === 'OUTLET').reduce((sum, e) => sum + Math.max(1, e.count), 0))}
|
||||
/>
|
||||
<PropertyRow
|
||||
label={t('properties.switchCountStat')}
|
||||
value={String(electricalItems.filter((e) => e.type === 'SWITCH').length)}
|
||||
/>
|
||||
{/* Stretch ceiling drop (натяжной потолок). Stored in meters,
|
||||
edited in cm for ergonomics. 0 = disabled. */}
|
||||
<EditablePropertyRow
|
||||
|
||||
@@ -290,8 +290,27 @@ export function ProjectionElectrical({
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
{item.type === 'WALL_CABLE' && (
|
||||
<>
|
||||
{/* Wall plate circle */}
|
||||
<Circle
|
||||
x={center.x}
|
||||
y={center.y}
|
||||
radius={half * 0.7}
|
||||
fill={fillColor}
|
||||
stroke={strokeColor}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
{/* Cable stub hanging down */}
|
||||
<Line
|
||||
points={[center.x, center.y + half * 0.7, center.x, center.y + half * 1.6]}
|
||||
stroke="#555555"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* Fallback for other wall-mounted types */}
|
||||
{item.type !== 'OUTLET' && item.type !== 'SWITCH' && item.type !== 'LIGHT_WALL' && (
|
||||
{item.type !== 'OUTLET' && item.type !== 'SWITCH' && item.type !== 'LIGHT_WALL' && item.type !== 'WALL_CABLE' && (
|
||||
<Rect
|
||||
x={center.x - half}
|
||||
y={center.y - half}
|
||||
@@ -315,7 +334,9 @@ export function ProjectionElectrical({
|
||||
? 'OUT'
|
||||
: item.type === 'SWITCH'
|
||||
? 'SW'
|
||||
: 'WL'
|
||||
: item.type === 'WALL_CABLE'
|
||||
? 'CBL'
|
||||
: 'WL'
|
||||
}
|
||||
align="center"
|
||||
fontSize={8}
|
||||
|
||||
@@ -29,6 +29,7 @@ export const ELECTRICAL_SYMBOL_DEFS: readonly ElectricalSymbolDef[] = [
|
||||
{ type: 'LIGHT_CEILING', label: 'Ceiling Light', category: 'light', wallMounted: false, coverageRadius: 2.0 },
|
||||
{ type: 'LIGHT_WALL', label: 'Wall Light', category: 'light', wallMounted: true, coverageRadius: 1.5 },
|
||||
{ type: 'CABLE_ROUTE', label: 'Cable Route', category: 'cable', wallMounted: false },
|
||||
{ type: 'WALL_CABLE', label: 'Wall Cable', category: 'cable', wallMounted: true },
|
||||
];
|
||||
|
||||
/** Get the variant from an electrical item's metadata. Used by switches; outlets use `count`. */
|
||||
|
||||
@@ -53,6 +53,7 @@ const ELECTRICAL_COLORS: Record<ElectricalType, string> = {
|
||||
LIGHT_CEILING: '#fff8dc',
|
||||
LIGHT_WALL: '#fff8dc',
|
||||
CABLE_ROUTE: '#ff6b35',
|
||||
WALL_CABLE: '#c0c0c0',
|
||||
};
|
||||
|
||||
const SELECTED_COLOR = '#6fa8dc';
|
||||
@@ -375,6 +376,24 @@ function WallLightMesh({ color, style, cordLength, lampSize }: {
|
||||
}
|
||||
}
|
||||
|
||||
/** Wall cable: round plate on wall with a cable stub protruding into the room. */
|
||||
function WallCableMesh({ color }: { readonly color: string }) {
|
||||
return (
|
||||
<group>
|
||||
{/* Wall plate */}
|
||||
<mesh castShadow>
|
||||
<cylinderGeometry args={[0.03, 0.03, 0.01, 16]} />
|
||||
<meshStandardMaterial color={color} roughness={0.4} />
|
||||
</mesh>
|
||||
{/* Cable stub protruding from the wall */}
|
||||
<mesh position={[0, 0, 0.025]} rotation={[Math.PI / 2, 0, 0]} castShadow>
|
||||
<cylinderGeometry args={[0.006, 0.006, 0.04, 8]} />
|
||||
<meshStandardMaterial color="#333333" roughness={0.7} />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
/** Cable route: small orange marker */
|
||||
function CableRouteMesh({ color }: { readonly color: string }) {
|
||||
return (
|
||||
@@ -513,6 +532,7 @@ export function ElectricalMeshWithHeight({
|
||||
/>
|
||||
)}
|
||||
{item.type === 'CABLE_ROUTE' && <CableRouteMesh color={color} />}
|
||||
{item.type === 'WALL_CABLE' && <WallCableMesh color={color} />}
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -221,6 +221,7 @@ export const ELECTRICAL_TYPES = [
|
||||
'LIGHT_CEILING',
|
||||
'LIGHT_WALL',
|
||||
'CABLE_ROUTE',
|
||||
'WALL_CABLE',
|
||||
] as const;
|
||||
export type ElectricalType = (typeof ELECTRICAL_TYPES)[number];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user