fix: 修复 3D NaN 崩溃/样品图不刷新/画布点选失效
- replayShape 段过滤补 Y 轴有限值校验(此前仅校验 X) - inferSashGlyphs bdRect 增加有限值守卫 - WindoorThreed 逐网格有限值防护 + maxDim 守卫, 杜绝 NaN 网格 - CombineCanvas shapePts 过滤非有限点, 修复包围盒污染导致的点选失效 - 组合画布引入 rev 版本号: 原地变异几何后强制 3D 预览重建 (修复尺寸编辑后样品图不变化)
This commit is contained in:
@@ -47,10 +47,12 @@ function shapePts(shape: any): Pt[] {
|
||||
const out: Pt[] = []
|
||||
for (const r of (shape.polygon?.polygon ?? []))
|
||||
for (const seg of r) {
|
||||
if (seg.ps && Number.isFinite(seg.ps.x)) out.push(seg.ps)
|
||||
if (seg.pe && Number.isFinite(seg.pe.x)) out.push(seg.pe)
|
||||
if (seg.ps && Number.isFinite(seg.ps.x) && Number.isFinite(seg.ps.y)) out.push(seg.ps)
|
||||
if (seg.pe && Number.isFinite(seg.pe.x) && Number.isFinite(seg.pe.y)) out.push(seg.pe)
|
||||
}
|
||||
for (const sp of (shape.mm?.sp ?? [])) if (sp.line?.pt) out.push(sp.line.pt)
|
||||
for (const sp of (shape.mm?.sp ?? [])) {
|
||||
if (sp.line?.pt && Number.isFinite(sp.line.pt.x) && Number.isFinite(sp.line.pt.y)) out.push(sp.line.pt)
|
||||
}
|
||||
return out
|
||||
}
|
||||
function translateUid(uid: number, dx: number, dy: number) {
|
||||
|
||||
@@ -79,13 +79,17 @@ function build(drawing: DrawingData) {
|
||||
const pts: Pt[] = []
|
||||
for (const s of drawing.sm) {
|
||||
for (const r of replayShape(s).regions) {
|
||||
for (const seg of r) { pts.push(seg.ps); pts.push(seg.pe) }
|
||||
for (const seg of r) {
|
||||
if (Number.isFinite(seg.ps?.x) && Number.isFinite(seg.ps?.y)) pts.push(seg.ps)
|
||||
if (Number.isFinite(seg.pe?.x) && Number.isFinite(seg.pe?.y)) pts.push(seg.pe)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!pts.length) { info.value = '无几何数据'; hasOpenable.value = false; return }
|
||||
const gb = bboxOf(pts)
|
||||
const gw = gb.x1 - gb.x0, gh = gb.y1 - gb.y0
|
||||
const maxDim = Math.max(gw, gh)
|
||||
if (!Number.isFinite(maxDim) || maxDim <= 0) { info.value = '无有效几何'; hasOpenable.value = false; return }
|
||||
const S = 1 / maxDim
|
||||
const cx = (gb.x0 + gb.x1) / 2, cy = (gb.y0 + gb.y1) / 2
|
||||
const DEPTH = Math.max(0.04, (drawing.s?.cs ?? 60) * S * 1.2)
|
||||
@@ -132,6 +136,7 @@ function build(drawing: DrawingData) {
|
||||
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
|
||||
if (![w, h, mx, my].every(Number.isFinite) || w <= 0 || h <= 0) continue
|
||||
const inSash = sashRects.some(r => {
|
||||
const cxr = (r.x0 + r.x1) / 2, cyr = (r.y0 + r.y1) / 2
|
||||
return Math.abs(cxr - (bb.x0 + bb.x1) / 2) < w / 2 && Math.abs(cyr - (bb.y0 + bb.y1) / 2) < h / 2
|
||||
@@ -145,9 +150,9 @@ function build(drawing: DrawingData) {
|
||||
// 扇面板(可开合):玻璃 + 四周扇框,装入铰链/滑动组
|
||||
sashes.forEach((s, k) => {
|
||||
const w = (s.x1 - s.x0) * S, h = (s.y1 - s.y0) * S
|
||||
if (w < 0.02 || h < 0.02) return
|
||||
const cxr = ((s.x0 + s.x1) / 2 - cx) * S
|
||||
const cyr = ((s.y0 + s.y1) / 2 - cy) * S
|
||||
if (![w, h, cxr, cyr].every(Number.isFinite) || w < 0.02 || h < 0.02) return
|
||||
const group = new THREE.Group()
|
||||
const panel = new THREE.Group()
|
||||
const glass = new THREE.Mesh(new THREE.BoxGeometry(w, h, 0.006), gm)
|
||||
|
||||
@@ -143,7 +143,9 @@ export function replayShape(shape: FrameShape): {
|
||||
} {
|
||||
const base = (shape.polygon?.polygon ?? [])
|
||||
.map(r => r
|
||||
.filter(s => s && typeof s === 'object' && s.ps && s.pe && Number.isFinite(s.ps.x) && Number.isFinite(s.pe.x))
|
||||
.filter(s => s && typeof s === 'object' && s.ps && s.pe
|
||||
&& Number.isFinite(s.ps.x) && Number.isFinite(s.ps.y)
|
||||
&& Number.isFinite(s.pe.x) && Number.isFinite(s.pe.y))
|
||||
.map(s => ({ ps: { ...s.ps }, pe: { ...s.pe } })))
|
||||
.filter(r => r.length >= 3)
|
||||
const regions: Segment[][] = base.map(r => r)
|
||||
@@ -237,11 +239,13 @@ export function inferSashGlyphs(shape: FrameShape, replayed?: Segment[][]): {
|
||||
const regionBBs = regions.map(r => bboxOf(regionPoints(r)))
|
||||
const glyphs: SashGlyph[] = []
|
||||
const bdRect = (bd: NonNullable<SashShape['bd']>) => {
|
||||
if (!bd.from || !bd.to) return null
|
||||
const r = {
|
||||
x0: Math.min(bd.from.x, bd.to.x), y0: Math.min(bd.from.y, bd.to.y),
|
||||
x1: Math.max(bd.from.x, bd.to.x), y1: Math.max(bd.from.y, bd.to.y),
|
||||
}
|
||||
return !bd.hidden && r.x1 - r.x0 > 10 && r.y1 - r.y0 > 10 ? r : null
|
||||
const ok = [r.x0, r.y0, r.x1, r.y1].every(v => Number.isFinite(v))
|
||||
return ok && !bd.hidden && r.x1 - r.x0 > 10 && r.y1 - r.y0 > 10 ? r : null
|
||||
}
|
||||
const kindOf = (sub: SashShape) => (sub.type === 'DoubleSash' ? 'sliding' : 'casement') as 'sliding' | 'casement'
|
||||
const pushGlyphs = (r: { x0: number; y0: number; x1: number; y1: number }, entries: any[], sub: SashShape) => {
|
||||
|
||||
@@ -109,10 +109,14 @@ const saveName = ref('')
|
||||
const saving = ref(false)
|
||||
const canvasRef = ref()
|
||||
let uidSeq = 1
|
||||
const rev = ref(0)
|
||||
|
||||
const combinedJson = computed(() =>
|
||||
shapes.value.length ? JSON.stringify({ s: { cs: 60, cjs: 100 }, cp: [], sm: shapes.value,
|
||||
epi: [], sbf: [], wlc: '', wall: [], scale: 0, note: [] }) : '')
|
||||
const combinedJson = computed(() => {
|
||||
void rev.value // 画布原地变异几何后通过版本号强制重算(驱动 3D 预览重建)
|
||||
if (!shapes.value.length) return ''
|
||||
return JSON.stringify({ s: { cs: 60, cjs: 100 }, cp: [], sm: shapes.value,
|
||||
epi: [], sbf: [], wlc: '', wall: [], scale: 0, note: [], rev: rev.value })
|
||||
})
|
||||
|
||||
// ---------- 样板库 ----------
|
||||
async function loadLib() {
|
||||
@@ -198,7 +202,7 @@ function syncSelSize() {
|
||||
if (bb) { selSize.w = Math.round(bb.x1 - bb.x0); selSize.h = Math.round(bb.y1 - bb.y0) }
|
||||
}
|
||||
|
||||
function onCanvasChange() { refreshMeta(); syncSelSize() }
|
||||
function onCanvasChange() { refreshMeta(); syncSelSize(); rev.value++ }
|
||||
|
||||
function onSelResize() {
|
||||
if (selSize.w >= 300 && selSize.h >= 300) canvasRef.value?.resizeSelected(selSize.w, selSize.h)
|
||||
|
||||
Reference in New Issue
Block a user