diff --git a/src/components/Building3D.jsx b/src/components/Building3D.jsx index 970ae94..0ba70ce 100644 --- a/src/components/Building3D.jsx +++ b/src/components/Building3D.jsx @@ -37,7 +37,7 @@ const ROOMS = [ // 企业按 Excel 场地安排:成长1=Facebook 越南跨境电商 → 成长8=综合直播私域平台 { x: [45, 51], z: [1, 3], type: 'office', zone: '成长区', no: 'G8', company: '综合性云南直播私域平台' }, { x: [53, 54], z: [1, 3], type: 'hallway', no: 'H01' }, - { x: [55, 58], z: [1, 3], type: 'desk', no: 'W01' }, + { x: [55, 58], z: [1, 3], type: 'stair', no: 'W01' }, { x: [45, 48], z: [5, 6], type: 'office', zone: '成长区', no: 'G7', company: '云南星瑞航空' }, { x: [45, 48], z: [8, 9], type: 'office', zone: '成长区', no: 'G6', company: '五华区丽裳文化' }, { x: [45, 48], z: [11, 12], type: 'office', zone: '成长区', no: 'G5', company: '南菌优培食用菌' }, @@ -82,42 +82,68 @@ const ROOMS = [ { x: [32, 33], z: [36, 40], type: 'stair', no: 'S01' }, // 楼道(真实楼梯通向一楼) { x: [35, 45], z: [36, 40], type: 'meeting', no: 'M01' }, // 大会议室(长桌+讲台) { x: [47, 49], z: [36, 40], type: 'office', zone: '加速区', no: 'A2', company: '米勒克尔蓝宝石珠宝' }, - { x: [51, 54], z: [36, 40], type: 'office', zone: '加速区', no: 'A1', company: '云南派音人工智能科技' }, + { x: [51, 53.5], z: [36, 40], type: 'office', zone: '加速区', no: 'A1', company: '云南派音人工智能科技' }, ]; /* ---- 水平墙段 [z, x0, x1](像素精确提取)---- 说明:行1-3 顶部 G01 南墙在行4;行4/7/10/13/16/19/22/25 为成长区/国际区段间墙; 过道(列50-53)处无墙;行27 玻璃顶南墙;行28-40 加速区内部墙(单格垂直墙点) */ const HWALLS = [ - [0, 0, 58], // 北外墙 - [4, 44, 49], [4, 51, 51], [4, 54, 58], // 顶部 G01 南墙(含列51 隔墙;列50 为过道口) - [7, 44, 49], [7, 54, 58], - [10, 44, 49], [10, 54, 58], - [13, 44, 49], [13, 54, 58], - [16, 44, 49], [16, 54, 58], - [19, 44, 49], [19, 54, 58], - [22, 44, 49], [22, 54, 58], - [25, 44, 49], [25, 54, 58], + [0, 0.5, 57.5], // 北外墙 + [4, 44.5, 48.5], + [4, 51, 51], + [4, 54, 57.5], // 顶部 G01 南墙(含列51 隔墙;列50 为过道口) + [7, 44.5, 48.5], + [7, 54, 57.5], + [10, 44.5, 48.5], + [10, 54, 57.5], + [13, 44.5, 48.5], + [13, 54, 57.5], + [16, 44.5, 48.5], + [16, 54, 57.5], + [19, 44.5, 48.5], + [19, 54, 57.5], + [22, 44.5, 48.5], + [22, 54, 57.5], + [25, 44.5, 48.5], + [25, 54, 57.5], [27, 0, 44], // 玻璃顶南墙(全高) + // 过道上侧 + [32.5, 0.5, 2.5], + [32.5, 5, 10], + [32.5, 13, 15], + [32.5, 17.3, 19], + [32.5, 21, 25], + // z=36 横墙已去除;补相邻垂直墙(z36.6-40.5)间的横向短墙段(z=36.6,x 从第一堵起到第二堵-1) + [36, 0.5, 2.5], + [36, 5, 10], + [36, 13, 14.5], + [36, 17, 19], + [36, 22, 24], + [36, 27, 29], + [36, 33.5, 34], // 过道 + [36, 37, 44], + [36, 46.3, 48.5], + [36, 51, 53.1], // 派音右 [41, 0, 53], // 南外墙 ]; /* ---- 垂直墙段 [x, z0, z1](像素精确提取)---- */ const VWALLS = [ - [0, 0, 41], // 西外墙 - [5, 27, 32], [5, 36, 41], - [13, 27, 32], [13, 36, 41], - [17, 27, 32], [17, 36, 41], - [22, 27, 32], [22, 36, 41], - [27, 27, 32], [27, 36, 41], - [31, 36, 41], // 小会议室与楼道之间 - [34, 36, 41], // 楼道与大会议室之间 - [44, 0, 32], [44, 36, 41], // 玻璃顶东墙 / 大会议室西墙 - [46, 36, 41], // 大会议室东墙 + [0, 0.5, 41], // 西外墙 + [5, 27, 32], [5, 36.6, 40.5], + [13, 27, 32], [13, 36.6, 40.5], + [17, 27, 32], [17, 36.6, 40.5], + [22, 27, 32], [22, 36.6, 40.5], + [27, 27, 32], [27, 36.6, 40.5], + [31, 36.6, 40.5], // 小会议室与楼道之间 + [34, 36.6, 40.5], // 楼道与大会议室之间 + [44, 0.5, 32], [44, 36.6, 40.5], // 玻璃顶东墙 / 大会议室西墙 [49, 4, 5], [49, 7, 8], [49, 10, 11], [49, 13, 14], [49, 16, 17], [49, 19, 20], [49, 22, 23], // 成长区段间西侧墙 - [49, 36, 41], // 底部 - [50, 36, 41], // 底部 A12/A13 之间 - [51, 0, 4], // 顶部共享工位西缘(G01 东墙) - [58, 0, 25], // 东外墙 + [53.5, 4, 5], [53.5, 7, 8], [53.5, 10, 11], [53.5, 13, 14], [53.5, 16, 17], [53.5, 19, 20], [53.5, 22, 23], // 成长区段间西侧墙 + [48.5, 36.6, 40.5], // 底部 A12/A13 之间 + [53.5, 36.6, 40.5], // 底部 A1 右墙(X-0.5=53.5,Z-0.5=[35.5,40.5]) + [51, 0.5, 3.4], // 顶部共享工位西缘(G01 东墙) + [58, 0.5, 24.7], // 东外墙(原 [58,0,25],延伸覆盖底部 A1 东侧) ]; const W = 60, D = 42; @@ -126,14 +152,22 @@ const cz = (z) => (z - D / 2) * U; /* ---------- 基础组件 ---------- */ -function Wall({ x, z, w, h, axis = 'z', color = WALL_COLOR, edge = WALL_EDGE, y = 0 }) { +function Wall({ x, z, w, h, axis = 'z', color = WALL_COLOR, edge = WALL_EDGE, y = 0, gridLabel = '' }) { const size = axis === 'z' ? [w, h, T] : [T, h, w]; return ( - - - - - + + + + + + + {/* 临时调试:墙面数值标签 */} + {gridLabel && ( + +
{gridLabel}
+ + )} +
); } @@ -148,25 +182,6 @@ function Window({ x, z, w, h = 1.0, axis = 'z', y = 0.85 }) { ); } -/* 门(门框 + 门板 + 把手) */ -function Door({ x, z, rotY = 0, y = 0 }) { - return ( - - - - - - - - - - - - - - - ); -} /* 办公桌(办公桌 + 座椅) */ function Desk({ x, z, y = 0, rotY = 0 }) { @@ -322,36 +337,22 @@ function Plant({ x, z, y = 0, s = 1 }) { ); } -/* 楼梯(楼道:从二楼通向一楼,真实踏步+扶手) */ -function Stairs({ x, z, y = 0, rotY = 0, steps = 9, stepW = 0.9, stepD = 0.24, rise = 0.21 }) { +/* 楼梯(楼梯间:从二楼通向一楼 —— 踏步自二楼逐级向下延伸至地面,居中铺满房间) */ +function Stairs({ x, z, y = 0, rotY = 0, steps = 9, stepW = 0.9, stepD = 0.24, rise }) { + // 默认向下:最高一级落在 y(二楼楼面),最低一级落在 y - rise*(steps-1) = 0(一楼地面) + const r = rise ?? (steps > 1 ? y / (steps - 1) : y); + const len = steps * stepD; const els = []; for (let i = 0; i < steps; i++) { - const dz = i * stepD; - const h = y + rise * i; + const dz = i * stepD - len / 2; // 居中铺满房间(避免穿墙) + const h = y - r * i; // 从二楼向下逐级降低 els.push( - - + + ); } - // 扶手(两侧) - const railLen = steps * stepD + 0.3; - const railH = y + rise * (steps - 1) + 0.95; - [-stepW / 2 - 0.06, stepW / 2 + 0.06].forEach((rx) => { - els.push( - - - - - ); - els.push( - - - - - ); - }); return ( {els} @@ -380,7 +381,6 @@ function Building() { const roofs = []; const furniture = []; const tags = []; - const doors = []; /* ===== 1. 一楼大厅(玻璃顶下方挑空) ===== */ const hx0 = cx(0), hx1 = cx(44); @@ -560,12 +560,15 @@ function Building() { furniture.push(); } } else if (r.type === 'stair') { - // 楼道:真实楼梯(二楼 → 一楼) + // 楼梯间:真实楼梯(二楼 → 一楼),自动按房间宽/深选择梯段方向与级数 + const alongX = (x1 - x0) >= (z1 - z0); // 房间宽≥深 → 梯段沿 X 方向 const sX = (x0 + x1) / 2; const sZ = (z0 + z1) / 2; - const sLen = z1 - z0; + const sLen = alongX ? (x1 - x0) : (z1 - z0); + const steps = Math.max(4, Math.min(11, Math.round(sLen / 0.45))); furniture.push( - + ); } // 标签:每个房间显示编号(编号 + 名称),办公室显示入驻企业名 @@ -574,7 +577,7 @@ function Building() { r.type === 'desk' ? '共享工位区' : r.type === 'lounge' ? '休息区' : r.type === 'meeting' ? '会议室' : - r.type === 'stair' ? '楼道' : + r.type === 'stair' ? '楼梯间' : r.type === 'office' ? (r.company || r.zone || '办公室') : '过道'; tags.push( @@ -589,12 +592,14 @@ function Building() { /* ===== 4. 墙体(像素墙段精确生成,无交叉穿出) ===== */ HWALLS.forEach(([z, x0, x1], i) => { walls.push( - + ); }); VWALLS.forEach(([x, z0, z1], i) => { walls.push( - + ); }); @@ -608,37 +613,6 @@ function Building() { walls.push(); walls.push(); - /* ===== 5. 办公室门:全部开向过道一侧(门嵌于墙段位置) ===== */ - ROOMS.forEach((r, i) => { - if (r.type !== 'office') return; - const z0 = cz(r.z[0]), z1 = cz(r.z[1]); - const cZ = (z0 + z1) / 2; - const cX = (cx(r.x[0]) + cx(r.x[1])) / 2; - - if (r.zone === '成长区') { - // 成长区东侧是过道(列50-53),门开在 x=49 墙段位置(列49 是墙) - doors.push(); - } else if (r.zone === '国际区') { - // 国际区西侧是过道,门开在 x=54 墙段位置(列54 是墙) - doors.push(); - } else if (r.zone === '加速区' || r.zone === '管理') { - if (r.z[1] <= 32) { - // 上排:南侧是横向过道(行33-35),门开在 z=32 - doors.push(); - } else { - // 下排:北侧是横向过道,门开在 z=36 - doors.push(); - } - } - }); - - /* ===== 6. 区域标签 ===== */ - tags.push(); - tags.push(); - tags.push(); - tags.push(); - tags.push(); - tags.push(); return ( @@ -646,19 +620,43 @@ function Building() { - + {floors} {walls} - {doors} {roofs} {furniture} {tags} {/* 底座平台 */} - - + + + + + ); +} + +/* ---------- 临时坐标轴指示(XYZ,用于点位沟通调试) ---------- */ +function TempAxis() { + return ( + + {/* 三色轴:X 红 → +x,Y 绿 ↑ +y,Z 蓝 → +z(长度 6) */} + + {/* 轴端文字标签 */} + +
+X →
+ + +
+Y ↑
+ + +
+Z →
+ + {/* 原点 */} + + +
); @@ -671,23 +669,26 @@ export default function Building3D({ interactive = true }) { - + + sectionSize={4} sectionThickness={1} sectionColor="#eef2f8" fadeDistance={40} fadeStrength={2.5} infiniteGrid /> - + + ); -} +} \ No newline at end of file