fix: v2.11 3D 全开/全关状态错误根治——分割树重放语义破译与扇五金解析重建
- polyId 语义破译: {idx,pos}=(分裂子树节点id,子区域序), 节点id=sp 0基序号, child0=法线指向侧
- replayShape 重写为树重放(锚点兜底), 704/31594/31729 全引用精确命中官方平面图, 798 扇矩形 100% 有效
- 坐标系修正: 模型 y 向下, 3D 翻转 y, 布局与原图一致
- 扇五金解析: Slide/DoubleSash=推拉, hm.openDirection 定铰链侧(含上悬), hm.openToward 定内外开, od=全开幅
- 移除错误的滑扇附着兜底; 2D 编辑器写回 polyId 同步树寻址
- 验证: 全关/46%/100% 三态截图 + ui-shots 6 页 + validate3d 全量 0 无效
This commit is contained in:
@@ -87,6 +87,7 @@ let dragging: { x: number; y: number; button: number } | null = null
|
||||
let sashAnims: {
|
||||
group: THREE.Group
|
||||
kind: 'sliding' | 'casement'
|
||||
axis?: 'x' | 'y'
|
||||
baseX: number
|
||||
slideDir: number
|
||||
hingeSign: number
|
||||
@@ -247,7 +248,8 @@ function build(drawing: DrawingData) {
|
||||
const sashRoot = new THREE.Group()
|
||||
sceneRoot.add(frameGroup)
|
||||
sceneRoot.add(sashRoot)
|
||||
const world = (x: number, y: number) => ({ x: (x - cx) * S, y: (y - cy) * S })
|
||||
// 模型坐标 y 向下(屏幕系), Three.js y 向上: 翻转保证布局上下关系与原图一致
|
||||
const world = (x: number, y: number) => ({ x: (x - cx) * S, y: (cy - y) * S })
|
||||
|
||||
for (const shape of drawing.sm) {
|
||||
const { regions, sashes } = inferSashGlyphs(shape)
|
||||
@@ -283,7 +285,7 @@ function build(drawing: DrawingData) {
|
||||
if (used.has(ri)) return
|
||||
const w = (bb.x1 - bb.x0) * S, h = (bb.y1 - bb.y0) * S
|
||||
const mx = ((bb.x0 + bb.x1) / 2 - cx) * S
|
||||
const my = ((bb.y0 + bb.y1) / 2 - cy) * S
|
||||
const my = (cy - (bb.y0 + bb.y1) / 2) * S
|
||||
if (![w, h, mx, my].every(Number.isFinite) || w <= 0 || h <= 0) return
|
||||
const glass = new THREE.Mesh(new THREE.BoxGeometry(w, h, 0.008), gm)
|
||||
glass.position.set(mx, my, 0)
|
||||
@@ -299,7 +301,7 @@ function build(drawing: DrawingData) {
|
||||
panels.forEach(({ rect, sash: s }, k) => {
|
||||
const w = (rect.x1 - rect.x0) * S, h = (rect.y1 - rect.y0) * S
|
||||
const cxr = ((rect.x0 + rect.x1) / 2 - cx) * S
|
||||
const cyr = ((rect.y0 + rect.y1) / 2 - cy) * S
|
||||
const cyr = (cy - (rect.y0 + rect.y1) / 2) * S
|
||||
if (![w, h, cxr, cyr].every(Number.isFinite) || w < 0.02 || h < 0.02) return
|
||||
const group = new THREE.Group()
|
||||
const glass = new THREE.Mesh(new THREE.BoxGeometry(w, h, 0.006), gm)
|
||||
@@ -317,16 +319,26 @@ function build(drawing: DrawingData) {
|
||||
sashAnims.push({ group, kind: 'sliding', baseX: cxr, slideDir: k % 2 === 0 ? 1 : -1,
|
||||
hingeSign: 1, maxAng: 0, w })
|
||||
} else {
|
||||
const odRad = ((s.od ?? 90) * Math.PI) / 180
|
||||
const hingeLeft = Math.cos(odRad) < 0
|
||||
const hingeX = hingeLeft ? cxr - w / 2 : cxr + w / 2
|
||||
group.position.set(hingeX, cyr, 0)
|
||||
// 子元素为面板中心局部坐标: 平移 +(cxr-hingeX) 使 t=0 世界位置不变, 仅将旋转支点移到铰链边
|
||||
group.children.forEach(child => { child.position.x += (cxr - hingeX) })
|
||||
const maxAng = (s.isDoor ? 75 : s.wtf ? 40 : 32) * Math.PI / 180
|
||||
const dirSign = s.openToward === 'inward' ? 1 : -1
|
||||
sashAnims.push({ group, kind: 'casement', baseX: hingeX, slideDir: 0,
|
||||
hingeSign: dirSign, maxAng, w })
|
||||
// 平开/上悬: 铰链侧与内外开取自五金 hm.openDirection/openToward, 开幅取 od(全开=开向角度)
|
||||
const outSign = s.openToward === 'inward' ? -1 : 1 // +1=外开(朝观察者)
|
||||
const maxAng = Math.min(100, Number.isFinite(s.od) && s.od > 0 ? s.od : (s.isDoor ? 75 : 90)) * Math.PI / 180
|
||||
const dir = s.openDirection ?? 'left'
|
||||
if (dir.startsWith('up')) {
|
||||
// 上悬窗: 绕顶边旋转
|
||||
const hingeY = cyr + h / 2
|
||||
group.position.set(cxr, hingeY, 0)
|
||||
group.children.forEach(child => { child.position.y += (cyr - hingeY) })
|
||||
sashAnims.push({ group, kind: 'casement', axis: 'x', baseX: cxr, slideDir: 0,
|
||||
hingeSign: -outSign, maxAng, w })
|
||||
} else {
|
||||
const hingeLeft = dir.startsWith('left')
|
||||
const hingeX = hingeLeft ? cxr - w / 2 : cxr + w / 2
|
||||
group.position.set(hingeX, cyr, 0)
|
||||
// 子元素为面板中心局部坐标: 平移 +(cxr-hingeX) 使 t=0 世界位置不变, 仅将旋转支点移到铰链边
|
||||
group.children.forEach(child => { child.position.x += (cxr - hingeX) })
|
||||
sashAnims.push({ group, kind: 'casement', axis: 'y', baseX: hingeX, slideDir: 0,
|
||||
hingeSign: (hingeLeft ? -1 : 1) * outSign, maxAng, w })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -418,6 +430,8 @@ function applyOpen(t: number) {
|
||||
for (const a of sashAnims) {
|
||||
if (a.kind === 'sliding') {
|
||||
a.group.position.x = a.baseX + a.slideDir * a.w * 0.42 * t
|
||||
} else if (a.axis === 'x') {
|
||||
a.group.rotation.x = a.hingeSign * a.maxAng * t
|
||||
} else {
|
||||
a.group.rotation.y = a.hingeSign * a.maxAng * t
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user