fix: 门窗渲染语义区分(门=贯穿长把手+锁点+型材同色裙板, 窗=短把手), 对照官方参考图三渲染器同步

This commit is contained in:
HHY
2026-10-05 08:22:19 -07:00
parent 078ca3529d
commit 64bda5e97b
4 changed files with 35 additions and 11 deletions
+22 -5
View File
@@ -84,6 +84,12 @@ function render() {
// 扇层:扇内子格(裙板/格条/编号) + 扇料框 + 开向符号 + 把手(语义同 WindoorCanvas,视觉对齐 2D 图纸)
const rp = replayShape(shape)
const glyphs = inferSashGlyphs(shape, rp).sashes
// 裙板色 = 型材色(cm.g rgba 字符串 → 不透明深色), 解析失败退中性深灰
const cmRaw = typeof shape.cm?.g === 'string' ? shape.cm.g : ''
const cmMatch = cmRaw.match(/(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/)
const frameTint = cmMatch
? `rgb(${Math.round(+cmMatch[1] * 0.62)},${Math.round(+cmMatch[2] * 0.62)},${Math.round(+cmMatch[3] * 0.62)})`
: '#6b6e73'
const sashShapes: SashShape[] = []
const collect = (s: FrameShape | SashShape) => {
if (!['Frame', 'Slide'].includes(String(s.type))) sashShapes.push(s as SashShape)
@@ -105,10 +111,10 @@ function render() {
const px0 = tx(p.x0), px1 = tx(p.x1), py0 = ty(p.y0), py1 = ty(p.y1)
if (px1 - px0 < 4 || py1 - py0 < 4) continue
if (!p.glass) {
// 裙板/实板:暖米色 + 内凹描边
ctx.fillStyle = '#ddd3c0'
// 裙板/实板:型材同色系(取 cm.g, 官方图纸裙板与框扇同色) + 内凹描边
ctx.fillStyle = frameTint
ctx.fillRect(px0, py0, px1 - px0, py1 - py0)
ctx.strokeStyle = 'rgba(90,84,72,0.55)'
ctx.strokeStyle = 'rgba(0,0,0,0.35)'
ctx.lineWidth = 1.5
ctx.strokeRect(px0 + 3, py0 + 3, px1 - px0 - 6, py1 - py0 - 6)
} else if (p.deco) {
@@ -183,9 +189,9 @@ function render() {
ctx.stroke()
ctx.setLineDash([])
}
// 把手: 铰链对面侧白条
// 把手: 铰链对面侧白条(门=贯穿长条, 窗=短条) + 门上下锁点块
const dir = g.openDirection ?? 'left'
const hl = Math.max(10, h * (g.isDoor ? 0.34 : 0.2))
const hl = Math.max(10, h * (g.isDoor ? 0.55 : 0.2))
const hw2 = Math.max(4, 5)
ctx.fillStyle = '#f4f4f6'
ctx.strokeStyle = '#3c4147'
@@ -200,6 +206,17 @@ function render() {
}
ctx.fill()
ctx.stroke()
// 门锁点(把手上下两端小方块)
if (g.isDoor && g.kind === 'casement' && !dir.startsWith('up')) {
const dx = dir.startsWith('left') ? bx1 - hw2 / 2 - 3 : bx0 + hw2 / 2 + 3
const dot = Math.max(3, hw2 * 0.8)
for (const oy of [cy - hl / 3, cy + hl / 3]) {
ctx.beginPath()
ctx.rect(dx - dot / 2, oy - dot / 2, dot, dot)
ctx.fill()
ctx.stroke()
}
}
})
// 外框
const all = dd.sm.flatMap(s => replayShape(s).regions.flat().map(seg => seg.ps))
+10 -5
View File
@@ -596,10 +596,15 @@ function drawFrame(
const px0 = tx(p.x0), px1 = tx(p.x1), py0 = ty(p.y0), py1 = ty(p.y1)
if (px1 - px0 < 4 || py1 - py0 < 4) continue
if (!p.glass) {
ctx.fillStyle = '#e5dfd3'
// 裙板: 型材深色(官方图纸裙板与框扇同色系) + 竖纹肌理
ctx.fillStyle = '#5f6268'
ctx.fillRect(px0, py0, px1 - px0, py1 - py0)
ctx.strokeStyle = STYLE.profileDark
ctx.strokeStyle = 'rgba(255,255,255,0.14)'
ctx.lineWidth = 1
for (let vx = px0 + 7; vx < px1 - 3; vx += 7) {
ctx.beginPath(); ctx.moveTo(vx, py0 + 3); ctx.lineTo(vx, py1 - 3); ctx.stroke()
}
ctx.strokeStyle = STYLE.profileDark
ctx.strokeRect(px0 + 2, py0 + 2, px1 - px0 - 4, py1 - py0 - 4)
} else if (p.deco) {
// hc 等分主格 + gp 内框 + 四角回纹块(近似源站 decorationChinese)
@@ -627,7 +632,7 @@ function drawFrame(
}
if (p.glassText) {
const fs2 = Math.max(9, Math.min(14, (px1 - px0) * 0.1))
ctx.fillStyle = p.glass ? 'rgba(255,255,255,0.92)' : STYLE.label
ctx.fillStyle = 'rgba(255,255,255,0.92)'
ctx.font = `bold ${fs2}px sans-serif`
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
@@ -668,9 +673,9 @@ function drawFrame(
ctx.stroke()
ctx.setLineDash([])
}
// 把手: 铰链对面侧(白条+描边+上下锁点)
// 把手: 铰链对面侧(白条+描边; 门=贯穿长条, 窗=短条)+上下锁点
const dir = g.openDirection ?? 'left'
const hl = Math.max(8, h * (g.isDoor ? 0.36 : 0.2))
const hl = Math.max(8, h * (g.isDoor ? 0.55 : 0.2))
const hw2 = Math.max(3.5, lw * 0.55)
ctx.fillStyle = '#f4f4f6'
ctx.strokeStyle = STYLE.profileDark
+2 -1
View File
@@ -361,8 +361,9 @@ function build(drawing: DrawingData) {
const lmy = (gRect.y1 / 2 + gRect.y0 / 2 - (p.y0 + p.y1) / 2) * S
if (![pw, ph, lmx, lmy].every(Number.isFinite) || pw <= 0.01 || ph <= 0.01) continue
if (!p.glass) {
// 裙板: 型材深色系(与框扇同色域, 对齐官方门板观感)
const board = new THREE.Mesh(new THREE.BoxGeometry(pw, ph, 0.012),
new THREE.MeshStandardMaterial({ color: 0xd9cdb8, roughness: 0.7, metalness: 0.05 }))
new THREE.MeshStandardMaterial({ color: 0x606369, roughness: 0.65, metalness: 0.1 }))
board.position.set(lmx, lmy, 0.004)
group.add(board)
} else if (p.deco) {